diff options
Diffstat (limited to 'tests/deps/zip-0.2.1')
-rw-r--r-- | tests/deps/zip-0.2.1/zip.nimble | 18 | ||||
-rw-r--r-- | tests/deps/zip-0.2.1/zip/gzipfiles.nim | 97 | ||||
-rw-r--r-- | tests/deps/zip-0.2.1/zip/libzip.nim | 252 | ||||
-rw-r--r-- | tests/deps/zip-0.2.1/zip/private/libzip_all.c | 4193 | ||||
-rw-r--r-- | tests/deps/zip-0.2.1/zip/zipfiles.nim | 193 | ||||
-rw-r--r-- | tests/deps/zip-0.2.1/zip/zlib.nim | 425 | ||||
-rw-r--r-- | tests/deps/zip-0.2.1/zip/zzip.nim | 176 |
7 files changed, 5354 insertions, 0 deletions
diff --git a/tests/deps/zip-0.2.1/zip.nimble b/tests/deps/zip-0.2.1/zip.nimble new file mode 100644 index 000000000..561f1b9c9 --- /dev/null +++ b/tests/deps/zip-0.2.1/zip.nimble @@ -0,0 +1,18 @@ +# Package + +version = "0.2.1" +author = "Anonymous" +description = "Wrapper for the zip library" +license = "MIT" + +skipDirs = @["tests"] + +# Dependencies + +requires "nim >= 0.10.0" + +task tests, "Run lib tests": + withDir "tests": + exec "nim c -r ziptests" + exec "nim c -r zlibtests" + exec "nim c -r gziptests" diff --git a/tests/deps/zip-0.2.1/zip/gzipfiles.nim b/tests/deps/zip-0.2.1/zip/gzipfiles.nim new file mode 100644 index 000000000..82c412bc3 --- /dev/null +++ b/tests/deps/zip-0.2.1/zip/gzipfiles.nim @@ -0,0 +1,97 @@ +import os +import zlib +import streams +export streams + +## This module implements a gzipfile stream for reading, writing, appending. + +type + GzFileStream* = ref object of Stream + mode: FileMode + f: GzFile + +const SEEK_SET = 0.int32 # Seek from beginning of file. + +proc fsClose(s: Stream) = + if not GzFileStream(s).f.isNil: + discard gzclose(GzFileStream(s).f) + GzFileStream(s).f = nil + +proc fsFlush(s: Stream) = + # compiler flushFile also discard c_fflush + discard gzflush(GzFileStream(s).f, Z_FINISH) + +proc fsAtEnd(s: Stream): bool = + result = gzeof(GzFileStream(s).f) == 1 + +proc fsSetPosition(s: Stream, pos: int) = + if gzseek(GzFileStream(s).f, pos.ZOffT, SEEK_SET) == -1: + if GzFileStream(s).mode in {fmWrite, fmAppend}: + raise newException(IOError, "error in gzip stream while seeking! (file is in write/append mode!") + else: + raise newException(IOError, "error in gzip stream while seeking!") + +proc fsGetPosition(s: Stream): int = + result = gztell(GzFileStream(s).f).int + +proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = + result = gzread(GzFileStream(s).f, buffer, bufLen).int + if result == -1: + if GzFileStream(s).mode in {fmWrite, fmAppend}: + raise newException(IOError, "cannot read data from write-only gzip stream!") + else: + raise newException(IOError, "cannot read from stream!") + +proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int = + let gz = GzFileStream(s) + if gz.mode in {fmWrite, fmAppend}: + raise newException(IOError, "cannot peek data from write-only gzip stream!") + let pos = int(gztell(gz.f)) + result = fsReadData(s, buffer, bufLen) + fsSetPosition(s, pos) + +proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) = + if gzwrite(GzFileStream(s).f, buffer, bufLen).int != bufLen: + if GzFileStream(s).mode in {fmWrite, fmAppend}: + raise newException(IOError, "cannot write data to gzip stream!") + else: + raise newException(IOError, "cannot write data to read-only gzip stream!") + + +proc newGzFileStream*(filename: string; mode=fmRead; level=Z_DEFAULT_COMPRESSION): GzFileStream = + ## Opens a Gzipfile as a file stream. `mode` can be + ## ``fmRead``, ``fmWrite`` or ``fmAppend``. + ## + ## Compression level can be set with ``level`` argument. Currently + ## ``Z_DEFAULT_COMPRESSION`` is 6. + ## + ## Note: ``level`` is ignored if ``mode`` is `fmRead` + ## + ## Note: There is only partial support for file seeking + ## - in fmRead mode, seeking randomly inside the gzip + ## file will lead to poor performance. + ## - in fmWrite, fmAppend mode, only forward seeking + ## is supported. + new(result) + case mode + of fmRead: result.f = gzopen(filename, "rb") + of fmWrite: result.f = gzopen(filename, "wb") + of fmAppend: result.f = gzopen(filename, "ab") + else: raise newException(IOError, "unsupported file mode '" & $mode & + "' for GzFileStream!") + if result.f.isNil: + let err = osLastError() + if err != OSErrorCode(0'i32): + raiseOSError(err) + if mode in {fmWrite, fmAppend}: + discard gzsetparams(result.f, level.int32, Z_DEFAULT_STRATEGY.int32) + + result.mode = mode + result.closeImpl = fsClose + result.atEndImpl = fsAtEnd + result.setPositionImpl = fsSetPosition + result.getPositionImpl = fsGetPosition + result.readDataImpl = fsReadData + result.peekDataImpl = fsPeekData + result.writeDataImpl = fsWriteData + result.flushImpl = fsFlush diff --git a/tests/deps/zip-0.2.1/zip/libzip.nim b/tests/deps/zip-0.2.1/zip/libzip.nim new file mode 100644 index 000000000..a2904cd2c --- /dev/null +++ b/tests/deps/zip-0.2.1/zip/libzip.nim @@ -0,0 +1,252 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2013 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Interface to the `libzip <http://www.nih.at/libzip/index.html>`_ library by +## Dieter Baron and Thomas Klausner. This version links +## against ``libzip2.so.2`` unless you define the symbol ``useLibzipSrc``; then +## it is compiled against some old ``libizp_all.c`` file. + +# +# zip.h -- exported declarations. +# Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner +# +# This file is part of libzip, a library to manipulate ZIP archives. +# The authors can be contacted at <libzip@nih.at> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. The names of the authors may not be used to endorse or promote +# products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +import times + +when defined(unix) and not defined(useLibzipSrc): + when defined(macosx): + {.pragma: mydll, dynlib: "libzip(|2|4).dylib".} + else: + {.pragma: mydll, dynlib: "libzip(|2).so(|.4|.2|.1|.0)".} +else: + when defined(unix): + {.passl: "-lz".} + {.compile: "zip/private/libzip_all.c".} + {.pragma: mydll.} + +type + ZipSourceCmd* = int32 + + ZipSourceCallback* = proc (state: pointer, data: pointer, length: int, + cmd: ZipSourceCmd): int {.cdecl.} + PZipStat* = ptr ZipStat + ZipStat* = object ## the 'zip_stat' struct + name*: cstring ## name of the file + index*: int32 ## index within archive + crc*: int32 ## crc of file data + mtime*: Time ## modification time + size*: int ## size of file (uncompressed) + compSize*: int ## size of file (compressed) + compMethod*: int16 ## compression method used + encryptionMethod*: int16 ## encryption method used + + Zip = object + ZipSource = object + ZipFile = object + + PZip* = ptr Zip ## represents a zip archive + PZipFile* = ptr ZipFile ## represents a file within an archive + PZipSource* = ptr ZipSource ## represents a source for an archive +{.deprecated: [TZipSourceCmd: ZipSourceCmd, TZipStat: ZipStat, TZip: Zip, + TZipSourceCallback: ZipSourceCallback, TZipSource: ZipSource, + TZipFile: ZipFile].} + +# flags for zip_name_locate, zip_fopen, zip_stat, ... +const + ZIP_CREATE* = 1'i32 + ZIP_EXCL* = 2'i32 + ZIP_CHECKCONS* = 4'i32 + ZIP_FL_NOCASE* = 1'i32 ## ignore case on name lookup + ZIP_FL_NODIR* = 2'i32 ## ignore directory component + ZIP_FL_COMPRESSED* = 4'i32 ## read compressed data + ZIP_FL_UNCHANGED* = 8'i32 ## use original data, ignoring changes + ZIP_FL_RECOMPRESS* = 16'i32 ## force recompression of data + +const # archive global flags flags + ZIP_AFL_TORRENT* = 1'i32 ## torrent zipped + +const # libzip error codes + ZIP_ER_OK* = 0'i32 ## N No error + ZIP_ER_MULTIDISK* = 1'i32 ## N Multi-disk zip archives not supported + ZIP_ER_RENAME* = 2'i32 ## S Renaming temporary file failed + ZIP_ER_CLOSE* = 3'i32 ## S Closing zip archive failed + ZIP_ER_SEEK* = 4'i32 ## S Seek error + ZIP_ER_READ* = 5'i32 ## S Read error + ZIP_ER_WRITE* = 6'i32 ## S Write error + ZIP_ER_CRC* = 7'i32 ## N CRC error + ZIP_ER_ZIPCLOSED* = 8'i32 ## N Containing zip archive was closed + ZIP_ER_NOENT* = 9'i32 ## N No such file + ZIP_ER_EXISTS* = 10'i32 ## N File already exists + ZIP_ER_OPEN* = 11'i32 ## S Can't open file + ZIP_ER_TMPOPEN* = 12'i32 ## S Failure to create temporary file + ZIP_ER_ZLIB* = 13'i32 ## Z Zlib error + ZIP_ER_MEMORY* = 14'i32 ## N Malloc failure + ZIP_ER_CHANGED* = 15'i32 ## N Entry has been changed + ZIP_ER_COMPNOTSUPP* = 16'i32 ## N Compression method not supported + ZIP_ER_EOF* = 17'i32 ## N Premature EOF + ZIP_ER_INVAL* = 18'i32 ## N Invalid argument + ZIP_ER_NOZIP* = 19'i32 ## N Not a zip archive + ZIP_ER_INTERNAL* = 20'i32 ## N Internal error + ZIP_ER_INCONS* = 21'i32 ## N Zip archive inconsistent + ZIP_ER_REMOVE* = 22'i32 ## S Can't remove file + ZIP_ER_DELETED* = 23'i32 ## N Entry has been deleted + +const # type of system error value + ZIP_ET_NONE* = 0'i32 ## sys_err unused + ZIP_ET_SYS* = 1'i32 ## sys_err is errno + ZIP_ET_ZLIB* = 2'i32 ## sys_err is zlib error code + +const # compression methods + ZIP_CM_DEFAULT* = -1'i32 ## better of deflate or store + ZIP_CM_STORE* = 0'i32 ## stored (uncompressed) + ZIP_CM_SHRINK* = 1'i32 ## shrunk + ZIP_CM_REDUCE_1* = 2'i32 ## reduced with factor 1 + ZIP_CM_REDUCE_2* = 3'i32 ## reduced with factor 2 + ZIP_CM_REDUCE_3* = 4'i32 ## reduced with factor 3 + ZIP_CM_REDUCE_4* = 5'i32 ## reduced with factor 4 + ZIP_CM_IMPLODE* = 6'i32 ## imploded + ## 7 - Reserved for Tokenizing compression algorithm + ZIP_CM_DEFLATE* = 8'i32 ## deflated + ZIP_CM_DEFLATE64* = 9'i32 ## deflate64 + ZIP_CM_PKWARE_IMPLODE* = 10'i32 ## PKWARE imploding + ## 11 - Reserved by PKWARE + ZIP_CM_BZIP2* = 12'i32 ## compressed using BZIP2 algorithm + ## 13 - Reserved by PKWARE + ZIP_CM_LZMA* = 14'i32 ## LZMA (EFS) + ## 15-17 - Reserved by PKWARE + ZIP_CM_TERSE* = 18'i32 ## compressed using IBM TERSE (new) + ZIP_CM_LZ77* = 19'i32 ## IBM LZ77 z Architecture (PFS) + ZIP_CM_WAVPACK* = 97'i32 ## WavPack compressed data + ZIP_CM_PPMD* = 98'i32 ## PPMd version I, Rev 1 + +const # encryption methods + ZIP_EM_NONE* = 0'i32 ## not encrypted + ZIP_EM_TRAD_PKWARE* = 1'i32 ## traditional PKWARE encryption + +const + ZIP_EM_UNKNOWN* = 0x0000FFFF'i32 ## unknown algorithm + +const + ZIP_SOURCE_OPEN* = 0'i32 ## prepare for reading + ZIP_SOURCE_READ* = 1'i32 ## read data + ZIP_SOURCE_CLOSE* = 2'i32 ## reading is done + ZIP_SOURCE_STAT* = 3'i32 ## get meta information + ZIP_SOURCE_ERROR* = 4'i32 ## get error information + constZIP_SOURCE_FREE* = 5'i32 ## cleanup and free resources + ZIP_SOURCE_SUPPORTS* = 14'i32 ## check supported commands + +proc zip_add*(para1: PZip, para2: cstring, para3: PZipSource): int32 {.cdecl, + importc: "zip_add", mydll.} +proc zip_add_dir*(para1: PZip, para2: cstring): int32 {.cdecl, + importc: "zip_add_dir", mydll.} +proc zip_close*(para1: PZip) {.cdecl, importc: "zip_close", mydll.} +proc zip_delete*(para1: PZip, para2: int32): int32 {.cdecl, mydll, + importc: "zip_delete".} +proc zip_error_clear*(para1: PZip) {.cdecl, importc: "zip_error_clear", mydll.} +proc zip_error_get*(para1: PZip, para2: ptr int32, para3: ptr int32) {.cdecl, + importc: "zip_error_get", mydll.} +proc zip_error_get_sys_type*(para1: int32): int32 {.cdecl, mydll, + importc: "zip_error_get_sys_type".} +proc zip_error_to_str*(para1: cstring, para2: int, para3: int32, + para4: int32): int32 {.cdecl, mydll, + importc: "zip_error_to_str".} +proc zip_fclose*(para1: PZipFile) {.cdecl, mydll, + importc: "zip_fclose".} +proc zip_file_error_clear*(para1: PZipFile) {.cdecl, mydll, + importc: "zip_file_error_clear".} +proc zip_file_error_get*(para1: PZipFile, para2: ptr int32, para3: ptr int32) {. + cdecl, mydll, importc: "zip_file_error_get".} +proc zip_file_strerror*(para1: PZipFile): cstring {.cdecl, mydll, + importc: "zip_file_strerror".} +proc zip_fopen*(para1: PZip, para2: cstring, para3: int32): PZipFile {.cdecl, + mydll, importc: "zip_fopen".} +proc zip_fopen_index*(para1: PZip, para2: int32, para3: int32): PZipFile {. + cdecl, mydll, importc: "zip_fopen_index".} +proc zip_fread*(para1: PZipFile, para2: pointer, para3: int): int {. + cdecl, mydll, importc: "zip_fread".} +proc zip_get_archive_comment*(para1: PZip, para2: ptr int32, para3: int32): cstring {. + cdecl, mydll, importc: "zip_get_archive_comment".} +proc zip_get_archive_flag*(para1: PZip, para2: int32, para3: int32): int32 {. + cdecl, mydll, importc: "zip_get_archive_flag".} +proc zip_get_file_comment*(para1: PZip, para2: int32, para3: ptr int32, + para4: int32): cstring {.cdecl, mydll, + importc: "zip_get_file_comment".} +proc zip_get_name*(para1: PZip, para2: int32, para3: int32): cstring {.cdecl, + mydll, importc: "zip_get_name".} +proc zip_get_num_files*(para1: PZip): int32 {.cdecl, + mydll, importc: "zip_get_num_files".} +proc zip_name_locate*(para1: PZip, para2: cstring, para3: int32): int32 {.cdecl, + mydll, importc: "zip_name_locate".} +proc zip_open*(para1: cstring, para2: int32, para3: ptr int32): PZip {.cdecl, + mydll, importc: "zip_open".} +proc zip_rename*(para1: PZip, para2: int32, para3: cstring): int32 {.cdecl, + mydll, importc: "zip_rename".} +proc zip_replace*(para1: PZip, para2: int32, para3: PZipSource): int32 {.cdecl, + mydll, importc: "zip_replace".} +proc zip_set_archive_comment*(para1: PZip, para2: cstring, para3: int32): int32 {. + cdecl, mydll, importc: "zip_set_archive_comment".} +proc zip_set_archive_flag*(para1: PZip, para2: int32, para3: int32): int32 {. + cdecl, mydll, importc: "zip_set_archive_flag".} +proc zip_set_file_comment*(para1: PZip, para2: int32, para3: cstring, + para4: int32): int32 {.cdecl, mydll, + importc: "zip_set_file_comment".} +proc zip_source_buffer*(para1: PZip, para2: pointer, para3: int, para4: int32): PZipSource {. + cdecl, mydll, importc: "zip_source_buffer".} +proc zip_source_file*(para1: PZip, para2: cstring, para3: int, para4: int): PZipSource {. + cdecl, mydll, importc: "zip_source_file".} +proc zip_source_filep*(para1: PZip, para2: File, para3: int, para4: int): PZipSource {. + cdecl, mydll, importc: "zip_source_filep".} +proc zip_source_free*(para1: PZipSource) {.cdecl, mydll, + importc: "zip_source_free".} +proc zip_source_function*(para1: PZip, para2: ZipSourceCallback, + para3: pointer): PZipSource {.cdecl, mydll, + importc: "zip_source_function".} +proc zip_source_zip*(para1: PZip, para2: PZip, para3: int32, para4: int32, + para5: int, para6: int): PZipSource {.cdecl, mydll, + importc: "zip_source_zip".} +proc zip_stat*(para1: PZip, para2: cstring, para3: int32, para4: PZipStat): int32 {. + cdecl, mydll, importc: "zip_stat".} +proc zip_stat_index*(para1: PZip, para2: int32, para3: int32, para4: PZipStat): int32 {. + cdecl, mydll, importc: "zip_stat_index".} +proc zip_stat_init*(para1: PZipStat) {.cdecl, mydll, importc: "zip_stat_init".} +proc zip_strerror*(para1: PZip): cstring {.cdecl, mydll, importc: "zip_strerror".} +proc zip_unchange*(para1: PZip, para2: int32): int32 {.cdecl, mydll, + importc: "zip_unchange".} +proc zip_unchange_all*(para1: PZip): int32 {.cdecl, mydll, + importc: "zip_unchange_all".} +proc zip_unchange_archive*(para1: PZip): int32 {.cdecl, mydll, + importc: "zip_unchange_archive".} diff --git a/tests/deps/zip-0.2.1/zip/private/libzip_all.c b/tests/deps/zip-0.2.1/zip/private/libzip_all.c new file mode 100644 index 000000000..e0627a7eb --- /dev/null +++ b/tests/deps/zip-0.2.1/zip/private/libzip_all.c @@ -0,0 +1,4193 @@ +/* + zipint.h -- internal declarations. + Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at <libzip@nih.at> + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include <zlib.h> + +/* +#ifdef _MSC_VER +#define ZIP_EXTERN __declspec(dllimport) +#endif +*/ + +/* + zip.h -- exported declarations. + Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner + + This file is part of libzip, a library to manipulate ZIP archives. + The authors can be contacted at <libzip@nih.at> + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef ZIP_EXTERN +#define ZIP_EXTERN +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <stdio.h> +#include <time.h> + +/* flags for zip_open */ + +#define ZIP_CREATE 1 +#define ZIP_EXCL 2 +#define ZIP_CHECKCONS 4 + + +/* flags for zip_name_locate, zip_fopen, zip_stat, ... */ + +#define ZIP_FL_NOCASE 1 /* ignore case on name lookup */ +#define ZIP_FL_NODIR 2 /* ignore directory component */ +#define ZIP_FL_COMPRESSED 4 /* read compressed data */ +#define ZIP_FL_UNCHANGED 8 /* use original data, ignoring changes */ +#define ZIP_FL_RECOMPRESS 16 /* force recompression of data */ + +/* archive global flags flags */ + +#define ZIP_AFL_TORRENT 1 /* torrent zipped */ + +/* libzip error codes */ + +#define ZIP_ER_OK 0 /* N No error */ +#define ZIP_ER_MULTIDISK 1 /* N Multi-disk zip archives not supported */ +#define ZIP_ER_RENAME 2 /* S Renaming temporary file failed */ +#define ZIP_ER_CLOSE 3 /* S Closing zip archive failed */ +#define ZIP_ER_SEEK 4 /* S Seek error */ +#define ZIP_ER_READ 5 /* S Read error */ +#define ZIP_ER_WRITE 6 /* S Write error */ +#define ZIP_ER_CRC 7 /* N CRC error */ +#define ZIP_ER_ZIPCLOSED 8 /* N Containing zip archive was closed */ +#define ZIP_ER_NOENT 9 /* N No such file */ +#define ZIP_ER_EXISTS 10 /* N File already exists */ +#define ZIP_ER_OPEN 11 /* S Can't open file */ +#define ZIP_ER_TMPOPEN 12 /* S Failure to create temporary file */ +#define ZIP_ER_ZLIB 13 /* Z Zlib error */ +#define ZIP_ER_MEMORY 14 /* N Malloc failure */ +#define ZIP_ER_CHANGED 15 /* N Entry has been changed */ +#define ZIP_ER_COMPNOTSUPP 16 /* N Compression method not supported */ +#define ZIP_ER_EOF 17 /* N Premature EOF */ +#define ZIP_ER_INVAL 18 /* N Invalid argument */ +#define ZIP_ER_NOZIP 19 /* N Not a zip archive */ +#define ZIP_ER_INTERNAL 20 /* N Internal error */ +#define ZIP_ER_INCONS 21 /* N Zip archive inconsistent */ +#define ZIP_ER_REMOVE 22 /* S Can't remove file */ +#define ZIP_ER_DELETED 23 /* N Entry has been deleted */ + + +/* type of system error value */ + +#define ZIP_ET_NONE 0 /* sys_err unused */ +#define ZIP_ET_SYS 1 /* sys_err is errno */ +#define ZIP_ET_ZLIB 2 /* sys_err is zlib error code */ + +/* compression methods */ + +#define ZIP_CM_DEFAULT -1 /* better of deflate or store */ +#define ZIP_CM_STORE 0 /* stored (uncompressed) */ +#define ZIP_CM_SHRINK 1 /* shrunk */ +#define ZIP_CM_REDUCE_1 2 /* reduced with factor 1 */ +#define ZIP_CM_REDUCE_2 3 /* reduced with factor 2 */ +#define ZIP_CM_REDUCE_3 4 /* reduced with factor 3 */ +#define ZIP_CM_REDUCE_4 5 /* reduced with factor 4 */ +#define ZIP_CM_IMPLODE 6 /* imploded */ +/* 7 - Reserved for Tokenizing compression algorithm */ +#define ZIP_CM_DEFLATE 8 /* deflated */ +#define ZIP_CM_DEFLATE64 9 /* deflate64 */ +#define ZIP_CM_PKWARE_IMPLODE 10 /* PKWARE imploding */ +/* 11 - Reserved by PKWARE */ +#define ZIP_CM_BZIP2 12 /* compressed using BZIP2 algorithm */ +/* 13 - Reserved by PKWARE */ +#define ZIP_CM_LZMA 14 /* LZMA (EFS) */ +/* 15-17 - Reserved by PKWARE */ +#define ZIP_CM_TERSE 18 /* compressed using IBM TERSE (new) */ +#define ZIP_CM_LZ77 19 /* IBM LZ77 z Architecture (PFS) */ +#define ZIP_CM_WAVPACK 97 /* WavPack compressed data */ +#define ZIP_CM_PPMD 98 /* PPMd version I, Rev 1 */ + +/* encryption methods */ + +#define ZIP_EM_NONE 0 /* not encrypted */ +#define ZIP_EM_TRAD_PKWARE 1 /* traditional PKWARE encryption */ +#if 0 /* Strong Encryption Header not parsed yet */ +#define ZIP_EM_DES 0x6601 /* strong encryption: DES */ +#define ZIP_EM_RC2_OLD 0x6602 /* strong encryption: RC2, version < 5.2 */ +#define ZIP_EM_3DES_168 0x6603 +#define ZIP_EM_3DES_112 0x6609 +#define ZIP_EM_AES_128 0x660e +#define ZIP_EM_AES_192 0x660f +#define ZIP_EM_AES_256 0x6610 +#define ZIP_EM_RC2 0x6702 /* strong encryption: RC2, version >= 5.2 */ +#define ZIP_EM_RC4 0x6801 +#endif +#define ZIP_EM_UNKNOWN 0xffff /* unknown algorithm */ + +typedef long myoff_t; /* XXX: 64 bit support */ + +enum zip_source_cmd { + ZIP_SOURCE_OPEN, /* prepare for reading */ + ZIP_SOURCE_READ, /* read data */ + ZIP_SOURCE_CLOSE, /* reading is done */ + ZIP_SOURCE_STAT, /* get meta information */ + ZIP_SOURCE_ERROR, /* get error information */ + ZIP_SOURCE_FREE /* cleanup and free resources */ +}; + +typedef ssize_t (*zip_source_callback)(void *state, void *data, + size_t len, enum zip_source_cmd cmd); + +struct zip_stat { + const char *name; /* name of the file */ + int index; /* index within archive */ + unsigned int crc; /* crc of file data */ + time_t mtime; /* modification time */ + myoff_t size; /* size of file (uncompressed) */ + myoff_t comp_size; /* size of file (compressed) */ + unsigned short comp_method; /* compression method used */ + unsigned short encryption_method; /* encryption method used */ +}; + +struct zip; +struct zip_file; +struct zip_source; + + +ZIP_EXTERN int zip_add(struct zip *, const char *, struct zip_source *); +ZIP_EXTERN int zip_add_dir(struct zip *, const char *); +ZIP_EXTERN int zip_close(struct zip *); +ZIP_EXTERN int zip_delete(struct zip *, int); +ZIP_EXTERN void zip_error_clear(struct zip *); +ZIP_EXTERN void zip_error_get(struct zip *, int *, int *); +ZIP_EXTERN int zip_error_get_sys_type(int); +ZIP_EXTERN int zip_error_to_str(char *, size_t, int, int); +ZIP_EXTERN int zip_fclose(struct zip_file *); +ZIP_EXTERN void zip_file_error_clear(struct zip_file *); +ZIP_EXTERN void zip_file_error_get(struct zip_file *, int *, int *); +ZIP_EXTERN const char *zip_file_strerror(struct zip_file *); +ZIP_EXTERN struct zip_file *zip_fopen(struct zip *, const char *, int); +ZIP_EXTERN struct zip_file *zip_fopen_index(struct zip *, int, int); +ZIP_EXTERN ssize_t zip_fread(struct zip_file *, void *, size_t); +ZIP_EXTERN const char *zip_get_archive_comment(struct zip *, int *, int); +ZIP_EXTERN int zip_get_archive_flag(struct zip *, int, int); +ZIP_EXTERN const char *zip_get_file_comment(struct zip *, int, int *, int); +ZIP_EXTERN const char *zip_get_name(struct zip *, int, int); +ZIP_EXTERN int zip_get_num_files(struct zip *); +ZIP_EXTERN int zip_name_locate(struct zip *, const char *, int); +ZIP_EXTERN struct zip *zip_open(const char *, int, int *); +ZIP_EXTERN int zip_rename(struct zip *, int, const char *); +ZIP_EXTERN int zip_replace(struct zip *, int, struct zip_source *); +ZIP_EXTERN int zip_set_archive_comment(struct zip *, const char *, int); +ZIP_EXTERN int zip_set_archive_flag(struct zip *, int, int); +ZIP_EXTERN int zip_set_file_comment(struct zip *, int, const char *, int); +ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *, + myoff_t, int); +ZIP_EXTERN struct zip_source *zip_source_file(struct zip *, const char *, + myoff_t, myoff_t); +ZIP_EXTERN struct zip_source *zip_source_filep(struct zip *, FILE *, + myoff_t, myoff_t); +ZIP_EXTERN void zip_source_free(struct zip_source *); +ZIP_EXTERN struct zip_source *zip_source_function(struct zip *, + zip_source_callback, void *); +ZIP_EXTERN struct zip_source *zip_source_zip(struct zip *, struct zip *, + int, int, myoff_t, myoff_t); +ZIP_EXTERN int zip_stat(struct zip *, const char *, int, struct zip_stat *); +ZIP_EXTERN int zip_stat_index(struct zip *, int, int, struct zip_stat *); +ZIP_EXTERN void zip_stat_init(struct zip_stat *); +ZIP_EXTERN const char *zip_strerror(struct zip *); +ZIP_EXTERN int zip_unchange(struct zip *, int); +ZIP_EXTERN int zip_unchange_all(struct zip *); +ZIP_EXTERN int zip_unchange_archive(struct zip *); + +#ifdef __cplusplus +} +#endif + + +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. + */ +/* #undef HAVE_DECL_TZNAME */ + +#define HAVE_CONFIG_H 1 + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the `fseeko' function. */ +#define HAVE_FSEEKO 1 + +/* Define to 1 if you have the `ftello' function. */ +#define HAVE_FTELLO 1 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `z' library (-lz). */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the `MoveFileExA' function. */ +/* #undef HAVE_MOVEFILEEXA */ + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if `tm_zone' is member of `struct tm'. */ +#ifdef WIN32 +#undef HAVE_STRUCT_TM_TM_ZONE +#else +#define HAVE_STRUCT_TM_TM_ZONE 1 +#endif + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use + `HAVE_STRUCT_TM_TM_ZONE' instead. */ +#define HAVE_TM_ZONE 1 + +/* Define to 1 if you don't have `tm_zone' but do have the external array + `tzname'. */ +/* #undef HAVE_TZNAME */ + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "libzip" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "libzip@nih.at" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libzip" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libzip 0.9" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libzip" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.9" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if your <sys/time.h> declares `struct tm'. */ +/* #undef TM_IN_SYS_TIME */ + +/* Version number of package */ +#define VERSION "0.9" + + +#ifndef HAVE_MKSTEMP +int _zip_mkstemp(char *); +#define mkstemp _zip_mkstemp +#endif + +#ifdef HAVE_MOVEFILEEXA +#include <windows.h> +#define _zip_rename(s, t) \ + (!MoveFileExA((s), (t), \ + MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING)) +#else +#define _zip_rename rename +#endif + +#ifndef HAVE_FSEEKO +#define fseeko(s, o, w) (fseek((s), (long int)(o), (w))) +#endif +#ifndef HAVE_FTELLO +#define ftello(s) ((long)ftell((s))) +#endif + + +#define CENTRAL_MAGIC "PK\1\2" +#define LOCAL_MAGIC "PK\3\4" +#define EOCD_MAGIC "PK\5\6" +#define DATADES_MAGIC "PK\7\8" +#define TORRENT_SIG "TORRENTZIPPED-" +#define TORRENT_SIG_LEN 14 +#define TORRENT_CRC_LEN 8 +#define TORRENT_MEM_LEVEL 8 +#define CDENTRYSIZE 46u +#define LENTRYSIZE 30 +#define MAXCOMLEN 65536 +#define EOCDLEN 22 +#define CDBUFSIZE (MAXCOMLEN+EOCDLEN) +#define BUFSIZE 8192 + + +/* state of change of a file in zip archive */ + +enum zip_state { ZIP_ST_UNCHANGED, ZIP_ST_DELETED, ZIP_ST_REPLACED, + ZIP_ST_ADDED, ZIP_ST_RENAMED }; + +/* constants for struct zip_file's member flags */ + +#define ZIP_ZF_EOF 1 /* EOF reached */ +#define ZIP_ZF_DECOMP 2 /* decompress data */ +#define ZIP_ZF_CRC 4 /* compute and compare CRC */ + +/* directory entry: general purpose bit flags */ + +#define ZIP_GPBF_ENCRYPTED 0x0001 /* is encrypted */ +#define ZIP_GPBF_DATA_DESCRIPTOR 0x0008 /* crc/size after file data */ +#define ZIP_GPBF_STRONG_ENCRYPTION 0x0040 /* uses strong encryption */ + +/* error information */ + +struct zip_error { + int zip_err; /* libzip error code (ZIP_ER_*) */ + int sys_err; /* copy of errno (E*) or zlib error code */ + char *str; /* string representation or NULL */ +}; + +/* zip archive, part of API */ + +struct zip { + char *zn; /* file name */ + FILE *zp; /* file */ + struct zip_error error; /* error information */ + + unsigned int flags; /* archive global flags */ + unsigned int ch_flags; /* changed archive global flags */ + + struct zip_cdir *cdir; /* central directory */ + char *ch_comment; /* changed archive comment */ + int ch_comment_len; /* length of changed zip archive + * comment, -1 if unchanged */ + int nentry; /* number of entries */ + int nentry_alloc; /* number of entries allocated */ + struct zip_entry *entry; /* entries */ + int nfile; /* number of opened files within archive */ + int nfile_alloc; /* number of files allocated */ + struct zip_file **file; /* opened files within archive */ +}; + +/* file in zip archive, part of API */ + +struct zip_file { + struct zip *za; /* zip archive containing this file */ + struct zip_error error; /* error information */ + int flags; /* -1: eof, >0: error */ + + int method; /* compression method */ + myoff_t fpos; /* position within zip file (fread/fwrite) */ + unsigned long bytes_left; /* number of bytes left to read */ + unsigned long cbytes_left; /* number of bytes of compressed data left */ + + unsigned long crc; /* CRC so far */ + unsigned long crc_orig; /* CRC recorded in archive */ + + char *buffer; + z_stream *zstr; +}; + +/* zip archive directory entry (central or local) */ + +struct zip_dirent { + unsigned short version_madeby; /* (c) version of creator */ + unsigned short version_needed; /* (cl) version needed to extract */ + unsigned short bitflags; /* (cl) general purpose bit flag */ + unsigned short comp_method; /* (cl) compression method used */ + time_t last_mod; /* (cl) time of last modification */ + unsigned int crc; /* (cl) CRC-32 of uncompressed data */ + unsigned int comp_size; /* (cl) size of commpressed data */ + unsigned int uncomp_size; /* (cl) size of uncommpressed data */ + char *filename; /* (cl) file name (NUL-terminated) */ + unsigned short filename_len; /* (cl) length of filename (w/o NUL) */ + char *extrafield; /* (cl) extra field */ + unsigned short extrafield_len; /* (cl) length of extra field */ + char *comment; /* (c) file comment */ + unsigned short comment_len; /* (c) length of file comment */ + unsigned short disk_number; /* (c) disk number start */ + unsigned short int_attrib; /* (c) internal file attributes */ + unsigned int ext_attrib; /* (c) external file attributes */ + unsigned int offset; /* (c) offset of local header */ +}; + +/* zip archive central directory */ + +struct zip_cdir { + struct zip_dirent *entry; /* directory entries */ + int nentry; /* number of entries */ + + unsigned int size; /* size of central direcotry */ + unsigned int offset; /* offset of central directory in file */ + char *comment; /* zip archive comment */ + unsigned short comment_len; /* length of zip archive comment */ +}; + + + +struct zip_source { + zip_source_callback f; + void *ud; +}; + +/* entry in zip archive directory */ + +struct zip_entry { + enum zip_state state; + struct zip_source *source; + char *ch_filename; + char *ch_comment; + int ch_comment_len; +}; + + + +extern const char * const _zip_err_str[]; +extern const int _zip_nerr_str; +extern const int _zip_err_type[]; + + + +#define ZIP_ENTRY_DATA_CHANGED(x) \ + ((x)->state == ZIP_ST_REPLACED \ + || (x)->state == ZIP_ST_ADDED) + + + +int _zip_cdir_compute_crc(struct zip *, uLong *); +void _zip_cdir_free(struct zip_cdir *); +struct zip_cdir *_zip_cdir_new(int, struct zip_error *); +int _zip_cdir_write(struct zip_cdir *, FILE *, struct zip_error *); + +void _zip_dirent_finalize(struct zip_dirent *); +void _zip_dirent_init(struct zip_dirent *); +int _zip_dirent_read(struct zip_dirent *, FILE *, + unsigned char **, unsigned int, int, struct zip_error *); +void _zip_dirent_torrent_normalize(struct zip_dirent *); +int _zip_dirent_write(struct zip_dirent *, FILE *, int, struct zip_error *); + +void _zip_entry_free(struct zip_entry *); +void _zip_entry_init(struct zip *, int); +struct zip_entry *_zip_entry_new(struct zip *); + +void _zip_error_clear(struct zip_error *); +void _zip_error_copy(struct zip_error *, struct zip_error *); +void _zip_error_fini(struct zip_error *); +void _zip_error_get(struct zip_error *, int *, int *); +void _zip_error_init(struct zip_error *); +void _zip_error_set(struct zip_error *, int, int); +const char *_zip_error_strerror(struct zip_error *); + +int _zip_file_fillbuf(void *, size_t, struct zip_file *); +unsigned int _zip_file_get_offset(struct zip *, int); + +int _zip_filerange_crc(FILE *, myoff_t, myoff_t, uLong *, struct zip_error *); + +struct zip_source *_zip_source_file_or_p(struct zip *, const char *, FILE *, + myoff_t, myoff_t); + +void _zip_free(struct zip *); +const char *_zip_get_name(struct zip *, int, int, struct zip_error *); +int _zip_local_header_read(struct zip *, int); +void *_zip_memdup(const void *, size_t, struct zip_error *); +int _zip_name_locate(struct zip *, const char *, int, struct zip_error *); +struct zip *_zip_new(struct zip_error *); +unsigned short _zip_read2(unsigned char **); +unsigned int _zip_read4(unsigned char **); +int _zip_replace(struct zip *, int, const char *, struct zip_source *); +int _zip_set_name(struct zip *, int, const char *); +int _zip_unchange(struct zip *, int, int); +void _zip_unchange_data(struct zip_entry *); + + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +const char * +_zip_error_strerror(struct zip_error *err) +{ + const char *zs, *ss; + char buf[128], *s; + + _zip_error_fini(err); + + if (err->zip_err < 0 || err->zip_err >= _zip_nerr_str) { + sprintf(buf, "Unknown error %d", err->zip_err); + zs = NULL; + ss = buf; + } + else { + zs = _zip_err_str[err->zip_err]; + + switch (_zip_err_type[err->zip_err]) { + case ZIP_ET_SYS: + ss = strerror(err->sys_err); + break; + + case ZIP_ET_ZLIB: + ss = zError(err->sys_err); + break; + + default: + ss = NULL; + } + } + + if (ss == NULL) + return zs; + else { + if ((s=(char *)malloc(strlen(ss) + + (zs ? strlen(zs)+2 : 0) + 1)) == NULL) + return _zip_err_str[ZIP_ER_MEMORY]; + + sprintf(s, "%s%s%s", + (zs ? zs : ""), + (zs ? ": " : ""), + ss); + err->str = s; + + return s; + } +} + +#include <stdlib.h> + + + +void +_zip_error_clear(struct zip_error *err) +{ + err->zip_err = ZIP_ER_OK; + err->sys_err = 0; +} + + + +void +_zip_error_copy(struct zip_error *dst, struct zip_error *src) +{ + dst->zip_err = src->zip_err; + dst->sys_err = src->sys_err; +} + + + +void +_zip_error_fini(struct zip_error *err) +{ + free(err->str); + err->str = NULL; +} + + + +void +_zip_error_get(struct zip_error *err, int *zep, int *sep) +{ + if (zep) + *zep = err->zip_err; + if (sep) { + if (zip_error_get_sys_type(err->zip_err) != ZIP_ET_NONE) + *sep = err->sys_err; + else + *sep = 0; + } +} + + + +void +_zip_error_init(struct zip_error *err) +{ + err->zip_err = ZIP_ER_OK; + err->sys_err = 0; + err->str = NULL; +} + + + +void +_zip_error_set(struct zip_error *err, int ze, int se) +{ + if (err) { + err->zip_err = ze; + err->sys_err = se; + } +} + + +#include <sys/types.h> +#include <sys/stat.h> + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + + + +int +_zip_mkstemp(char *path) +{ + int fd; + char *start, *trv; + struct stat sbuf; + pid_t pid; + + /* To guarantee multiple calls generate unique names even if + the file is not created. 676 different possibilities with 7 + or more X's, 26 with 6 or less. */ + static char xtra[2] = "aa"; + int xcnt = 0; + + pid = getpid(); + + /* Move to end of path and count trailing X's. */ + for (trv = path; *trv; ++trv) + if (*trv == 'X') + xcnt++; + else + xcnt = 0; + + /* Use at least one from xtra. Use 2 if more than 6 X's. */ + if (*(trv - 1) == 'X') + *--trv = xtra[0]; + if (xcnt > 6 && *(trv - 1) == 'X') + *--trv = xtra[1]; + + /* Set remaining X's to pid digits with 0's to the left. */ + while (*--trv == 'X') { + *trv = (pid % 10) + '0'; + pid /= 10; + } + + /* update xtra for next call. */ + if (xtra[0] != 'z') + xtra[0]++; + else { + xtra[0] = 'a'; + if (xtra[1] != 'z') + xtra[1]++; + else + xtra[1] = 'a'; + } + + /* + * check the target directory; if you have six X's and it + * doesn't exist this runs for a *very* long time. + */ + for (start = trv + 1;; --trv) { + if (trv <= path) + break; + if (*trv == '/') { + *trv = '\0'; + if (stat(path, &sbuf)) + return (0); + if (!S_ISDIR(sbuf.st_mode)) { + errno = ENOTDIR; + return (0); + } + *trv = '/'; + break; + } + } + + for (;;) { + if ((fd=open(path, O_CREAT|O_EXCL|O_RDWR|O_BINARY, 0600)) >= 0) + return (fd); + if (errno != EEXIST) + return (0); + + /* tricky little algorithm for backward compatibility */ + for (trv = start;;) { + if (!*trv) + return (0); + if (*trv == 'z') + *trv++ = 'a'; + else { + if (isdigit((unsigned char)*trv)) + *trv = 'a'; + else + ++*trv; + break; + } + } + } + /*NOTREACHED*/ +} + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +static time_t _zip_d2u_time(int, int); +static char *_zip_readfpstr(FILE *, unsigned int, int, struct zip_error *); +static char *_zip_readstr(unsigned char **, int, int, struct zip_error *); +static void _zip_u2d_time(time_t, unsigned short *, unsigned short *); +static void _zip_write2(unsigned short, FILE *); +static void _zip_write4(unsigned int, FILE *); + + + +void +_zip_cdir_free(struct zip_cdir *cd) +{ + int i; + + if (!cd) + return; + + for (i=0; i<cd->nentry; i++) + _zip_dirent_finalize(cd->entry+i); + free(cd->comment); + free(cd->entry); + free(cd); +} + + + +struct zip_cdir * +_zip_cdir_new(int nentry, struct zip_error *error) +{ + struct zip_cdir *cd; + + if ((cd=(struct zip_cdir *)malloc(sizeof(*cd))) == NULL) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if ((cd->entry=(struct zip_dirent *)malloc(sizeof(*(cd->entry))*nentry)) + == NULL) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + free(cd); + return NULL; + } + + /* entries must be initialized by caller */ + + cd->nentry = nentry; + cd->size = cd->offset = 0; + cd->comment = NULL; + cd->comment_len = 0; + + return cd; +} + + + +int +_zip_cdir_write(struct zip_cdir *cd, FILE *fp, struct zip_error *error) +{ + int i; + + cd->offset = ftello(fp); + + for (i=0; i<cd->nentry; i++) { + if (_zip_dirent_write(cd->entry+i, fp, 0, error) != 0) + return -1; + } + + cd->size = ftello(fp) - cd->offset; + + /* clearerr(fp); */ + fwrite(EOCD_MAGIC, 1, 4, fp); + _zip_write4(0, fp); + _zip_write2((unsigned short)cd->nentry, fp); + _zip_write2((unsigned short)cd->nentry, fp); + _zip_write4(cd->size, fp); + _zip_write4(cd->offset, fp); + _zip_write2(cd->comment_len, fp); + fwrite(cd->comment, 1, cd->comment_len, fp); + + if (ferror(fp)) { + _zip_error_set(error, ZIP_ER_WRITE, errno); + return -1; + } + + return 0; +} + + + +void +_zip_dirent_finalize(struct zip_dirent *zde) +{ + free(zde->filename); + zde->filename = NULL; + free(zde->extrafield); + zde->extrafield = NULL; + free(zde->comment); + zde->comment = NULL; +} + + + +void +_zip_dirent_init(struct zip_dirent *de) +{ + de->version_madeby = 0; + de->version_needed = 20; /* 2.0 */ + de->bitflags = 0; + de->comp_method = 0; + de->last_mod = 0; + de->crc = 0; + de->comp_size = 0; + de->uncomp_size = 0; + de->filename = NULL; + de->filename_len = 0; + de->extrafield = NULL; + de->extrafield_len = 0; + de->comment = NULL; + de->comment_len = 0; + de->disk_number = 0; + de->int_attrib = 0; + de->ext_attrib = 0; + de->offset = 0; +} + + + +/* _zip_dirent_read(zde, fp, bufp, left, localp, error): + Fills the zip directory entry zde. + + If bufp is non-NULL, data is taken from there and bufp is advanced + by the amount of data used; no more than left bytes are used. + Otherwise data is read from fp as needed. + + If localp != 0, it reads a local header instead of a central + directory entry. + + Returns 0 if successful. On error, error is filled in and -1 is + returned. +*/ + +int +_zip_dirent_read(struct zip_dirent *zde, FILE *fp, + unsigned char **bufp, unsigned int left, int localp, + struct zip_error *error) +{ + unsigned char buf[CDENTRYSIZE]; + unsigned char *cur; + unsigned short dostime, dosdate; + unsigned int size; + + if (localp) + size = LENTRYSIZE; + else + size = CDENTRYSIZE; + + if (bufp) { + /* use data from buffer */ + cur = *bufp; + if (left < size) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return -1; + } + } + else { + /* read entry from disk */ + if ((fread(buf, 1, size, fp)<size)) { + _zip_error_set(error, ZIP_ER_READ, errno); + return -1; + } + left = size; + cur = buf; + } + + if (memcmp(cur, (localp ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return -1; + } + cur += 4; + + + /* convert buffercontents to zip_dirent */ + + if (!localp) + zde->version_madeby = _zip_read2(&cur); + else + zde->version_madeby = 0; + zde->version_needed = _zip_read2(&cur); + zde->bitflags = _zip_read2(&cur); + zde->comp_method = _zip_read2(&cur); + + /* convert to time_t */ + dostime = _zip_read2(&cur); + dosdate = _zip_read2(&cur); + zde->last_mod = _zip_d2u_time(dostime, dosdate); + + zde->crc = _zip_read4(&cur); + zde->comp_size = _zip_read4(&cur); + zde->uncomp_size = _zip_read4(&cur); + + zde->filename_len = _zip_read2(&cur); + zde->extrafield_len = _zip_read2(&cur); + + if (localp) { + zde->comment_len = 0; + zde->disk_number = 0; + zde->int_attrib = 0; + zde->ext_attrib = 0; + zde->offset = 0; + } else { + zde->comment_len = _zip_read2(&cur); + zde->disk_number = _zip_read2(&cur); + zde->int_attrib = _zip_read2(&cur); + zde->ext_attrib = _zip_read4(&cur); + zde->offset = _zip_read4(&cur); + } + + zde->filename = NULL; + zde->extrafield = NULL; + zde->comment = NULL; + + if (bufp) { + if (left < CDENTRYSIZE + (zde->filename_len+zde->extrafield_len + +zde->comment_len)) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return -1; + } + + if (zde->filename_len) { + zde->filename = _zip_readstr(&cur, zde->filename_len, 1, error); + if (!zde->filename) + return -1; + } + + if (zde->extrafield_len) { + zde->extrafield = _zip_readstr(&cur, zde->extrafield_len, 0, + error); + if (!zde->extrafield) + return -1; + } + + if (zde->comment_len) { + zde->comment = _zip_readstr(&cur, zde->comment_len, 0, error); + if (!zde->comment) + return -1; + } + } + else { + if (zde->filename_len) { + zde->filename = _zip_readfpstr(fp, zde->filename_len, 1, error); + if (!zde->filename) + return -1; + } + + if (zde->extrafield_len) { + zde->extrafield = _zip_readfpstr(fp, zde->extrafield_len, 0, + error); + if (!zde->extrafield) + return -1; + } + + if (zde->comment_len) { + zde->comment = _zip_readfpstr(fp, zde->comment_len, 0, error); + if (!zde->comment) + return -1; + } + } + + if (bufp) + *bufp = cur; + + return 0; +} + + + +/* _zip_dirent_torrent_normalize(de); + Set values suitable for torrentzip. +*/ + +void +_zip_dirent_torrent_normalize(struct zip_dirent *de) +{ + static struct tm torrenttime; + static time_t last_mod = 0; + + if (last_mod == 0) { +#ifdef HAVE_STRUCT_TM_TM_ZONE + time_t now; + struct tm *l; +#endif + + torrenttime.tm_sec = 0; + torrenttime.tm_min = 32; + torrenttime.tm_hour = 23; + torrenttime.tm_mday = 24; + torrenttime.tm_mon = 11; + torrenttime.tm_year = 96; + torrenttime.tm_wday = 0; + torrenttime.tm_yday = 0; + torrenttime.tm_isdst = 0; + +#ifdef HAVE_STRUCT_TM_TM_ZONE + time(&now); + l = localtime(&now); + torrenttime.tm_gmtoff = l->tm_gmtoff; + torrenttime.tm_zone = l->tm_zone; +#endif + + last_mod = mktime(&torrenttime); + } + + de->version_madeby = 0; + de->version_needed = 20; /* 2.0 */ + de->bitflags = 2; /* maximum compression */ + de->comp_method = ZIP_CM_DEFLATE; + de->last_mod = last_mod; + + de->disk_number = 0; + de->int_attrib = 0; + de->ext_attrib = 0; + de->offset = 0; + + free(de->extrafield); + de->extrafield = NULL; + de->extrafield_len = 0; + free(de->comment); + de->comment = NULL; + de->comment_len = 0; +} + + + +/* _zip_dirent_write(zde, fp, localp, error): + Writes zip directory entry zde to file fp. + + If localp != 0, it writes a local header instead of a central + directory entry. + + Returns 0 if successful. On error, error is filled in and -1 is + returned. +*/ + +int +_zip_dirent_write(struct zip_dirent *zde, FILE *fp, int localp, + struct zip_error *error) +{ + unsigned short dostime, dosdate; + + fwrite(localp ? LOCAL_MAGIC : CENTRAL_MAGIC, 1, 4, fp); + + if (!localp) + _zip_write2(zde->version_madeby, fp); + _zip_write2(zde->version_needed, fp); + _zip_write2(zde->bitflags, fp); + _zip_write2(zde->comp_method, fp); + + _zip_u2d_time(zde->last_mod, &dostime, &dosdate); + _zip_write2(dostime, fp); + _zip_write2(dosdate, fp); + + _zip_write4(zde->crc, fp); + _zip_write4(zde->comp_size, fp); + _zip_write4(zde->uncomp_size, fp); + + _zip_write2(zde->filename_len, fp); + _zip_write2(zde->extrafield_len, fp); + + if (!localp) { + _zip_write2(zde->comment_len, fp); + _zip_write2(zde->disk_number, fp); + _zip_write2(zde->int_attrib, fp); + _zip_write4(zde->ext_attrib, fp); + _zip_write4(zde->offset, fp); + } + + if (zde->filename_len) + fwrite(zde->filename, 1, zde->filename_len, fp); + + if (zde->extrafield_len) + fwrite(zde->extrafield, 1, zde->extrafield_len, fp); + + if (!localp) { + if (zde->comment_len) + fwrite(zde->comment, 1, zde->comment_len, fp); + } + + if (ferror(fp)) { + _zip_error_set(error, ZIP_ER_WRITE, errno); + return -1; + } + + return 0; +} + + + +static time_t +_zip_d2u_time(int dtime, int ddate) +{ + struct tm *tm; + time_t now; + + now = time(NULL); + tm = localtime(&now); + /* let mktime decide if DST is in effect */ + tm->tm_isdst = -1; + + tm->tm_year = ((ddate>>9)&127) + 1980 - 1900; + tm->tm_mon = ((ddate>>5)&15) - 1; + tm->tm_mday = ddate&31; + + tm->tm_hour = (dtime>>11)&31; + tm->tm_min = (dtime>>5)&63; + tm->tm_sec = (dtime<<1)&62; + + return mktime(tm); +} + + + +unsigned short +_zip_read2(unsigned char **a) +{ + unsigned short ret; + + ret = (*a)[0]+((*a)[1]<<8); + *a += 2; + + return ret; +} + + + +unsigned int +_zip_read4(unsigned char **a) +{ + unsigned int ret; + + ret = ((((((*a)[3]<<8)+(*a)[2])<<8)+(*a)[1])<<8)+(*a)[0]; + *a += 4; + + return ret; +} + + + +static char * +_zip_readfpstr(FILE *fp, unsigned int len, int nulp, struct zip_error *error) +{ + char *r, *o; + + r = (char *)malloc(nulp ? len+1 : len); + if (!r) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if (fread(r, 1, len, fp)<len) { + free(r); + _zip_error_set(error, ZIP_ER_READ, errno); + return NULL; + } + + if (nulp) { + /* replace any in-string NUL characters with spaces */ + r[len] = 0; + for (o=r; o<r+len; o++) + if (*o == '\0') + *o = ' '; + } + + return r; +} + + + +static char * +_zip_readstr(unsigned char **buf, int len, int nulp, struct zip_error *error) +{ + char *r, *o; + + r = (char *)malloc(nulp ? len+1 : len); + if (!r) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + memcpy(r, *buf, len); + *buf += len; + + if (nulp) { + /* replace any in-string NUL characters with spaces */ + r[len] = 0; + for (o=r; o<r+len; o++) + if (*o == '\0') + *o = ' '; + } + + return r; +} + + + +static void +_zip_write2(unsigned short i, FILE *fp) +{ + putc(i&0xff, fp); + putc((i>>8)&0xff, fp); + + return; +} + + + +static void +_zip_write4(unsigned int i, FILE *fp) +{ + putc(i&0xff, fp); + putc((i>>8)&0xff, fp); + putc((i>>16)&0xff, fp); + putc((i>>24)&0xff, fp); + + return; +} + + + +static void +_zip_u2d_time(time_t time, unsigned short *dtime, unsigned short *ddate) +{ + struct tm *tm; + + tm = localtime(&time); + *ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + + tm->tm_mday; + *dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + + ((tm->tm_sec)>>1); + + return; +} + + + +ZIP_EXTERN int +zip_delete(struct zip *za, int idx) +{ + if (idx < 0 || idx >= za->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + /* allow duplicate file names, because the file will + * be removed directly afterwards */ + if (_zip_unchange(za, idx, 1) != 0) + return -1; + + za->entry[idx].state = ZIP_ST_DELETED; + + return 0; +} + + + +ZIP_EXTERN void +zip_error_clear(struct zip *za) +{ + _zip_error_clear(&za->error); +} + + +ZIP_EXTERN int +zip_add(struct zip *za, const char *name, struct zip_source *source) +{ + if (name == NULL || source == NULL) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + return _zip_replace(za, -1, name, source); +} + + +ZIP_EXTERN int +zip_error_get_sys_type(int ze) +{ + if (ze < 0 || ze >= _zip_nerr_str) + return 0; + + return _zip_err_type[ze]; +} + + +ZIP_EXTERN void +zip_error_get(struct zip *za, int *zep, int *sep) +{ + _zip_error_get(&za->error, zep, sep); +} + + +const char * const _zip_err_str[] = { + "No error", + "Multi-disk zip archives not supported", + "Renaming temporary file failed", + "Closing zip archive failed", + "Seek error", + "Read error", + "Write error", + "CRC error", + "Containing zip archive was closed", + "No such file", + "File already exists", + "Can't open file", + "Failure to create temporary file", + "Zlib error", + "Malloc failure", + "Entry has been changed", + "Compression method not supported", + "Premature EOF", + "Invalid argument", + "Not a zip archive", + "Internal error", + "Zip archive inconsistent", + "Can't remove file", + "Entry has been deleted", +}; + +const int _zip_nerr_str = sizeof(_zip_err_str)/sizeof(_zip_err_str[0]); + +#define N ZIP_ET_NONE +#define S ZIP_ET_SYS +#define Z ZIP_ET_ZLIB + +const int _zip_err_type[] = { + N, + N, + S, + S, + S, + S, + S, + N, + N, + N, + N, + S, + S, + Z, + N, + N, + N, + N, + N, + N, + N, + N, + S, + N, +}; + + +struct zip_entry * +_zip_entry_new(struct zip *za) +{ + struct zip_entry *ze; + if (!za) { + ze = (struct zip_entry *)malloc(sizeof(struct zip_entry)); + if (!ze) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + } + else { + if (za->nentry >= za->nentry_alloc-1) { + za->nentry_alloc += 16; + za->entry = (struct zip_entry *)realloc(za->entry, + sizeof(struct zip_entry) + * za->nentry_alloc); + if (!za->entry) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + } + ze = za->entry+za->nentry; + } + + ze->state = ZIP_ST_UNCHANGED; + + ze->ch_filename = NULL; + ze->ch_comment = NULL; + ze->ch_comment_len = -1; + ze->source = NULL; + + if (za) + za->nentry++; + + return ze; +} + + +void +_zip_entry_free(struct zip_entry *ze) +{ + free(ze->ch_filename); + ze->ch_filename = NULL; + free(ze->ch_comment); + ze->ch_comment = NULL; + ze->ch_comment_len = -1; + + _zip_unchange_data(ze); +} + + +static int add_data(struct zip *, struct zip_source *, struct zip_dirent *, + FILE *); +static int add_data_comp(zip_source_callback, void *, struct zip_stat *, + FILE *, struct zip_error *); +static int add_data_uncomp(struct zip *, zip_source_callback, void *, + struct zip_stat *, FILE *); +static void ch_set_error(struct zip_error *, zip_source_callback, void *); +static int copy_data(FILE *, myoff_t, FILE *, struct zip_error *); +static int write_cdir(struct zip *, struct zip_cdir *, FILE *); +static int _zip_cdir_set_comment(struct zip_cdir *, struct zip *); +static int _zip_changed(struct zip *, int *); +static char *_zip_create_temp_output(struct zip *, FILE **); +static int _zip_torrentzip_cmp(const void *, const void *); + + + +struct filelist { + int idx; + const char *name; +}; + + + +ZIP_EXTERN int +zip_close(struct zip *za) +{ + int survivors; + int i, j, error; + char *temp; + FILE *out; + mode_t mask; + struct zip_cdir *cd; + struct zip_dirent de; + struct filelist *filelist; + int reopen_on_error; + int new_torrentzip; + + reopen_on_error = 0; + + if (za == NULL) + return -1; + + if (!_zip_changed(za, &survivors)) { + _zip_free(za); + return 0; + } + + /* don't create zip files with no entries */ + if (survivors == 0) { + if (za->zn && za->zp) { + if (remove(za->zn) != 0) { + _zip_error_set(&za->error, ZIP_ER_REMOVE, errno); + return -1; + } + } + _zip_free(za); + return 0; + } + + if ((filelist=(struct filelist *)malloc(sizeof(filelist[0])*survivors)) + == NULL) + return -1; + + if ((cd=_zip_cdir_new(survivors, &za->error)) == NULL) { + free(filelist); + return -1; + } + + for (i=0; i<survivors; i++) + _zip_dirent_init(&cd->entry[i]); + + /* archive comment is special for torrentzip */ + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) { + cd->comment = _zip_memdup(TORRENT_SIG "XXXXXXXX", + TORRENT_SIG_LEN + TORRENT_CRC_LEN, + &za->error); + if (cd->comment == NULL) { + _zip_cdir_free(cd); + free(filelist); + return -1; + } + cd->comment_len = TORRENT_SIG_LEN + TORRENT_CRC_LEN; + } + else if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, ZIP_FL_UNCHANGED) == 0) { + if (_zip_cdir_set_comment(cd, za) == -1) { + _zip_cdir_free(cd); + free(filelist); + return -1; + } + } + + if ((temp=_zip_create_temp_output(za, &out)) == NULL) { + _zip_cdir_free(cd); + return -1; + } + + + /* create list of files with index into original archive */ + for (i=j=0; i<za->nentry; i++) { + if (za->entry[i].state == ZIP_ST_DELETED) + continue; + + filelist[j].idx = i; + filelist[j].name = zip_get_name(za, i, 0); + j++; + } + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) + qsort(filelist, survivors, sizeof(filelist[0]), + _zip_torrentzip_cmp); + + new_torrentzip = (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 1 + && zip_get_archive_flag(za, ZIP_AFL_TORRENT, + ZIP_FL_UNCHANGED) == 0); + error = 0; + for (j=0; j<survivors; j++) { + i = filelist[j].idx; + + /* create new local directory entry */ + if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) { + _zip_dirent_init(&de); + + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) + _zip_dirent_torrent_normalize(&de); + + /* use it as central directory entry */ + memcpy(cd->entry+j, &de, sizeof(cd->entry[j])); + + /* set/update file name */ + if (za->entry[i].ch_filename == NULL) { + if (za->entry[i].state == ZIP_ST_ADDED) { + de.filename = strdup("-"); + de.filename_len = 1; + cd->entry[j].filename = "-"; + } + else { + de.filename = strdup(za->cdir->entry[i].filename); + de.filename_len = strlen(de.filename); + cd->entry[j].filename = za->cdir->entry[i].filename; + cd->entry[j].filename_len = de.filename_len; + } + } + } + else { + /* copy existing directory entries */ + if (fseeko(za->zp, za->cdir->entry[i].offset, SEEK_SET) != 0) { + _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + error = 1; + break; + } + if (_zip_dirent_read(&de, za->zp, NULL, 0, 1, &za->error) != 0) { + error = 1; + break; + } + if (de.bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { + de.crc = za->cdir->entry[i].crc; + de.comp_size = za->cdir->entry[i].comp_size; + de.uncomp_size = za->cdir->entry[i].uncomp_size; + de.bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR; + } + memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[j])); + } + + if (za->entry[i].ch_filename) { + free(de.filename); + if ((de.filename=strdup(za->entry[i].ch_filename)) == NULL) { + error = 1; + break; + } + de.filename_len = strlen(de.filename); + cd->entry[j].filename = za->entry[i].ch_filename; + cd->entry[j].filename_len = de.filename_len; + } + + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0 + && za->entry[i].ch_comment_len != -1) { + /* as the rest of cd entries, its malloc/free is done by za */ + cd->entry[j].comment = za->entry[i].ch_comment; + cd->entry[j].comment_len = za->entry[i].ch_comment_len; + } + + cd->entry[j].offset = ftello(out); + + if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) { + struct zip_source *zs; + + zs = NULL; + if (!ZIP_ENTRY_DATA_CHANGED(za->entry+i)) { + if ((zs=zip_source_zip(za, za, i, ZIP_FL_RECOMPRESS, 0, -1)) + == NULL) { + error = 1; + break; + } + } + + if (add_data(za, zs ? zs : za->entry[i].source, &de, out) < 0) { + error = 1; + break; + } + cd->entry[j].last_mod = de.last_mod; + cd->entry[j].comp_method = de.comp_method; + cd->entry[j].comp_size = de.comp_size; + cd->entry[j].uncomp_size = de.uncomp_size; + cd->entry[j].crc = de.crc; + } + else { + if (_zip_dirent_write(&de, out, 1, &za->error) < 0) { + error = 1; + break; + } + /* we just read the local dirent, file is at correct position */ + if (copy_data(za->zp, cd->entry[j].comp_size, out, + &za->error) < 0) { + error = 1; + break; + } + } + + _zip_dirent_finalize(&de); + } + + if (!error) { + if (write_cdir(za, cd, out) < 0) + error = 1; + } + + /* pointers in cd entries are owned by za */ + cd->nentry = 0; + _zip_cdir_free(cd); + + if (error) { + _zip_dirent_finalize(&de); + fclose(out); + remove(temp); + free(temp); + return -1; + } + + if (fclose(out) != 0) { + _zip_error_set(&za->error, ZIP_ER_CLOSE, errno); + remove(temp); + free(temp); + return -1; + } + + if (za->zp) { + fclose(za->zp); + za->zp = NULL; + reopen_on_error = 1; + } + if (_zip_rename(temp, za->zn) != 0) { + _zip_error_set(&za->error, ZIP_ER_RENAME, errno); + remove(temp); + free(temp); + if (reopen_on_error) { + /* ignore errors, since we're already in an error case */ + za->zp = fopen(za->zn, "rb"); + } + return -1; + } + mask = umask(0); + umask(mask); + chmod(za->zn, 0666&~mask); + + _zip_free(za); + free(temp); + + return 0; +} + + + +static int +add_data(struct zip *za, struct zip_source *zs, struct zip_dirent *de, FILE *ft) +{ + myoff_t offstart, offend; + zip_source_callback cb; + void *ud; + struct zip_stat st; + + cb = zs->f; + ud = zs->ud; + + if (cb(ud, &st, sizeof(st), ZIP_SOURCE_STAT) < (ssize_t)sizeof(st)) { + ch_set_error(&za->error, cb, ud); + return -1; + } + + if (cb(ud, NULL, 0, ZIP_SOURCE_OPEN) < 0) { + ch_set_error(&za->error, cb, ud); + return -1; + } + + offstart = ftello(ft); + + if (_zip_dirent_write(de, ft, 1, &za->error) < 0) + return -1; + + if (st.comp_method != ZIP_CM_STORE) { + if (add_data_comp(cb, ud, &st, ft, &za->error) < 0) + return -1; + } + else { + if (add_data_uncomp(za, cb, ud, &st, ft) < 0) + return -1; + } + + if (cb(ud, NULL, 0, ZIP_SOURCE_CLOSE) < 0) { + ch_set_error(&za->error, cb, ud); + return -1; + } + + offend = ftello(ft); + + if (fseeko(ft, offstart, SEEK_SET) < 0) { + _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + return -1; + } + + + de->last_mod = st.mtime; + de->comp_method = st.comp_method; + de->crc = st.crc; + de->uncomp_size = st.size; + de->comp_size = st.comp_size; + + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) + _zip_dirent_torrent_normalize(de); + + if (_zip_dirent_write(de, ft, 1, &za->error) < 0) + return -1; + + if (fseeko(ft, offend, SEEK_SET) < 0) { + _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + return -1; + } + + return 0; +} + + + +static int +add_data_comp(zip_source_callback cb, void *ud, struct zip_stat *st,FILE *ft, + struct zip_error *error) +{ + char buf[BUFSIZE]; + ssize_t n; + + st->comp_size = 0; + while ((n=cb(ud, buf, sizeof(buf), ZIP_SOURCE_READ)) > 0) { + if (fwrite(buf, 1, n, ft) != (size_t)n) { + _zip_error_set(error, ZIP_ER_WRITE, errno); + return -1; + } + + st->comp_size += n; + } + if (n < 0) { + ch_set_error(error, cb, ud); + return -1; + } + + return 0; +} + + + +static int +add_data_uncomp(struct zip *za, zip_source_callback cb, void *ud, + struct zip_stat *st, FILE *ft) +{ + char b1[BUFSIZE], b2[BUFSIZE]; + int end, flush, ret; + ssize_t n; + size_t n2; + z_stream zstr; + int mem_level; + + st->comp_method = ZIP_CM_DEFLATE; + st->comp_size = st->size = 0; + st->crc = crc32(0, NULL, 0); + + zstr.zalloc = Z_NULL; + zstr.zfree = Z_NULL; + zstr.opaque = NULL; + zstr.avail_in = 0; + zstr.avail_out = 0; + + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) + mem_level = TORRENT_MEM_LEVEL; + else + mem_level = MAX_MEM_LEVEL; + + /* -MAX_WBITS: undocumented feature of zlib to _not_ write a zlib header */ + deflateInit2(&zstr, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, mem_level, + Z_DEFAULT_STRATEGY); + + zstr.next_out = (Bytef *)b2; + zstr.avail_out = sizeof(b2); + zstr.avail_in = 0; + + flush = 0; + end = 0; + while (!end) { + if (zstr.avail_in == 0 && !flush) { + if ((n=cb(ud, b1, sizeof(b1), ZIP_SOURCE_READ)) < 0) { + ch_set_error(&za->error, cb, ud); + deflateEnd(&zstr); + return -1; + } + if (n > 0) { + zstr.avail_in = n; + zstr.next_in = (Bytef *)b1; + st->size += n; + st->crc = crc32(st->crc, (Bytef *)b1, n); + } + else + flush = Z_FINISH; + } + + ret = deflate(&zstr, flush); + if (ret != Z_OK && ret != Z_STREAM_END) { + _zip_error_set(&za->error, ZIP_ER_ZLIB, ret); + return -1; + } + + if (zstr.avail_out != sizeof(b2)) { + n2 = sizeof(b2) - zstr.avail_out; + + if (fwrite(b2, 1, n2, ft) != n2) { + _zip_error_set(&za->error, ZIP_ER_WRITE, errno); + return -1; + } + + zstr.next_out = (Bytef *)b2; + zstr.avail_out = sizeof(b2); + st->comp_size += n2; + } + + if (ret == Z_STREAM_END) { + deflateEnd(&zstr); + end = 1; + } + } + + return 0; +} + + + +static void +ch_set_error(struct zip_error *error, zip_source_callback cb, void *ud) +{ + int e[2]; + + if ((cb(ud, e, sizeof(e), ZIP_SOURCE_ERROR)) < (ssize_t)sizeof(e)) { + error->zip_err = ZIP_ER_INTERNAL; + error->sys_err = 0; + } + else { + error->zip_err = e[0]; + error->sys_err = e[1]; + } +} + + + +static int +copy_data(FILE *fs, myoff_t len, FILE *ft, struct zip_error *error) +{ + char buf[BUFSIZE]; + int n, nn; + + if (len == 0) + return 0; + + while (len > 0) { + nn = len > sizeof(buf) ? sizeof(buf) : len; + if ((n=fread(buf, 1, nn, fs)) < 0) { + _zip_error_set(error, ZIP_ER_READ, errno); + return -1; + } + else if (n == 0) { + _zip_error_set(error, ZIP_ER_EOF, 0); + return -1; + } + + if (fwrite(buf, 1, n, ft) != (size_t)n) { + _zip_error_set(error, ZIP_ER_WRITE, errno); + return -1; + } + + len -= n; + } + + return 0; +} + + + +static int +write_cdir(struct zip *za, struct zip_cdir *cd, FILE *out) +{ + myoff_t offset; + uLong crc; + char buf[TORRENT_CRC_LEN+1]; + + if (_zip_cdir_write(cd, out, &za->error) < 0) + return -1; + + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0) + return 0; + + + /* fix up torrentzip comment */ + + offset = ftello(out); + + if (_zip_filerange_crc(out, cd->offset, cd->size, &crc, &za->error) < 0) + return -1; + + snprintf(buf, sizeof(buf), "%08lX", (long)crc); + + if (fseeko(out, offset-TORRENT_CRC_LEN, SEEK_SET) < 0) { + _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + return -1; + } + + if (fwrite(buf, TORRENT_CRC_LEN, 1, out) != 1) { + _zip_error_set(&za->error, ZIP_ER_WRITE, errno); + return -1; + } + + return 0; +} + + + +static int +_zip_cdir_set_comment(struct zip_cdir *dest, struct zip *src) +{ + if (src->ch_comment_len != -1) { + dest->comment = _zip_memdup(src->ch_comment, + src->ch_comment_len, &src->error); + if (dest->comment == NULL) + return -1; + dest->comment_len = src->ch_comment_len; + } else { + if (src->cdir && src->cdir->comment) { + dest->comment = _zip_memdup(src->cdir->comment, + src->cdir->comment_len, &src->error); + if (dest->comment == NULL) + return -1; + dest->comment_len = src->cdir->comment_len; + } + } + + return 0; +} + + + +static int +_zip_changed(struct zip *za, int *survivorsp) +{ + int changed, i, survivors; + + changed = survivors = 0; + + if (za->ch_comment_len != -1 + || za->ch_flags != za->flags) + changed = 1; + + for (i=0; i<za->nentry; i++) { + if ((za->entry[i].state != ZIP_ST_UNCHANGED) + || (za->entry[i].ch_comment_len != -1)) + changed = 1; + if (za->entry[i].state != ZIP_ST_DELETED) + survivors++; + } + + *survivorsp = survivors; + + return changed; +} + + + +static char * +_zip_create_temp_output(struct zip *za, FILE **outp) +{ + char *temp; + int tfd; + FILE *tfp; + + if ((temp=(char *)malloc(strlen(za->zn)+8)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + sprintf(temp, "%s.XXXXXX", za->zn); + + if ((tfd=mkstemp(temp)) == -1) { + _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno); + free(temp); + return NULL; + } + + if ((tfp=fdopen(tfd, "r+b")) == NULL) { + _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno); + close(tfd); + remove(temp); + free(temp); + return NULL; + } + + *outp = tfp; + return temp; +} + + + +static int +_zip_torrentzip_cmp(const void *a, const void *b) +{ + return strcasecmp(((const struct filelist *)a)->name, + ((const struct filelist *)b)->name); +} + + + +ZIP_EXTERN int +zip_add_dir(struct zip *za, const char *name) +{ + int len, ret; + char *s; + struct zip_source *source; + + if (name == NULL) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + s = NULL; + len = strlen(name); + + if (name[len-1] != '/') { + if ((s=(char *)malloc(len+2)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + strcpy(s, name); + s[len] = '/'; + s[len+1] = '\0'; + } + + if ((source=zip_source_buffer(za, NULL, 0, 0)) == NULL) { + free(s); + return -1; + } + + ret = _zip_replace(za, -1, s ? s : name, source); + + free(s); + if (ret < 0) + zip_source_free(source); + + return ret; +} + + +ZIP_EXTERN int +zip_error_to_str(char *buf, size_t len, int ze, int se) +{ + const char *zs, *ss; + + if (ze < 0 || ze >= _zip_nerr_str) + return snprintf(buf, len, "Unknown error %d", ze); + + zs = _zip_err_str[ze]; + + switch (_zip_err_type[ze]) { + case ZIP_ET_SYS: + ss = strerror(se); + break; + + case ZIP_ET_ZLIB: + ss = zError(se); + break; + + default: + ss = NULL; + } + + return snprintf(buf, len, "%s%s%s", + zs, (ss ? ": " : ""), (ss ? ss : "")); +} + + +ZIP_EXTERN void +zip_file_error_clear(struct zip_file *zf) +{ + _zip_error_clear(&zf->error); +} + + +ZIP_EXTERN int +zip_fclose(struct zip_file *zf) +{ + int i, ret; + + if (zf->zstr) + inflateEnd(zf->zstr); + free(zf->buffer); + free(zf->zstr); + + for (i=0; i<zf->za->nfile; i++) { + if (zf->za->file[i] == zf) { + zf->za->file[i] = zf->za->file[zf->za->nfile-1]; + zf->za->nfile--; + break; + } + } + + ret = 0; + if (zf->error.zip_err) + ret = zf->error.zip_err; + else if ((zf->flags & ZIP_ZF_CRC) && (zf->flags & ZIP_ZF_EOF)) { + /* if EOF, compare CRC */ + if (zf->crc_orig != zf->crc) + ret = ZIP_ER_CRC; + } + + free(zf); + return ret; +} + + +int +_zip_filerange_crc(FILE *fp, myoff_t start, myoff_t len, uLong *crcp, + struct zip_error *errp) +{ + Bytef buf[BUFSIZE]; + size_t n; + + *crcp = crc32(0L, Z_NULL, 0); + + if (fseeko(fp, start, SEEK_SET) != 0) { + _zip_error_set(errp, ZIP_ER_SEEK, errno); + return -1; + } + + while (len > 0) { + n = len > BUFSIZE ? BUFSIZE : len; + if ((n=fread(buf, 1, n, fp)) <= 0) { + _zip_error_set(errp, ZIP_ER_READ, errno); + return -1; + } + + *crcp = crc32(*crcp, buf, n); + + len-= n; + } + + return 0; +} + + +ZIP_EXTERN const char * +zip_file_strerror(struct zip_file *zf) +{ + return _zip_error_strerror(&zf->error); +} + + +/* _zip_file_get_offset(za, ze): + Returns the offset of the file data for entry ze. + + On error, fills in za->error and returns 0. +*/ + +unsigned int +_zip_file_get_offset(struct zip *za, int idx) +{ + struct zip_dirent de; + unsigned int offset; + + offset = za->cdir->entry[idx].offset; + + if (fseeko(za->zp, offset, SEEK_SET) != 0) { + _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + return 0; + } + + if (_zip_dirent_read(&de, za->zp, NULL, 0, 1, &za->error) != 0) + return 0; + + offset += LENTRYSIZE + de.filename_len + de.extrafield_len; + + _zip_dirent_finalize(&de); + + return offset; +} + + +ZIP_EXTERN void +zip_file_error_get(struct zip_file *zf, int *zep, int *sep) +{ + _zip_error_get(&zf->error, zep, sep); +} + + +static struct zip_file *_zip_file_new(struct zip *za); + + + +ZIP_EXTERN struct zip_file * +zip_fopen_index(struct zip *za, int fileno, int flags) +{ + int len, ret; + int zfflags; + struct zip_file *zf; + + if ((fileno < 0) || (fileno >= za->nentry)) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((flags & ZIP_FL_UNCHANGED) == 0 + && ZIP_ENTRY_DATA_CHANGED(za->entry+fileno)) { + _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); + return NULL; + } + + if (fileno >= za->cdir->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + zfflags = 0; + switch (za->cdir->entry[fileno].comp_method) { + case ZIP_CM_STORE: + zfflags |= ZIP_ZF_CRC; + break; + + case ZIP_CM_DEFLATE: + if ((flags & ZIP_FL_COMPRESSED) == 0) + zfflags |= ZIP_ZF_CRC | ZIP_ZF_DECOMP; + break; + default: + if ((flags & ZIP_FL_COMPRESSED) == 0) { + _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); + return NULL; + } + break; + } + + zf = _zip_file_new(za); + + zf->flags = zfflags; + /* zf->name = za->cdir->entry[fileno].filename; */ + zf->method = za->cdir->entry[fileno].comp_method; + zf->bytes_left = za->cdir->entry[fileno].uncomp_size; + zf->cbytes_left = za->cdir->entry[fileno].comp_size; + zf->crc_orig = za->cdir->entry[fileno].crc; + + if ((zf->fpos=_zip_file_get_offset(za, fileno)) == 0) { + zip_fclose(zf); + return NULL; + } + + if ((zf->flags & ZIP_ZF_DECOMP) == 0) + zf->bytes_left = zf->cbytes_left; + else { + if ((zf->buffer=(char *)malloc(BUFSIZE)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + zip_fclose(zf); + return NULL; + } + + len = _zip_file_fillbuf(zf->buffer, BUFSIZE, zf); + if (len <= 0) { + _zip_error_copy(&za->error, &zf->error); + zip_fclose(zf); + return NULL; + } + + if ((zf->zstr = (z_stream *)malloc(sizeof(z_stream))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + zip_fclose(zf); + return NULL; + } + zf->zstr->zalloc = Z_NULL; + zf->zstr->zfree = Z_NULL; + zf->zstr->opaque = NULL; + zf->zstr->next_in = (Bytef *)zf->buffer; + zf->zstr->avail_in = len; + + /* negative value to tell zlib that there is no header */ + if ((ret=inflateInit2(zf->zstr, -MAX_WBITS)) != Z_OK) { + _zip_error_set(&za->error, ZIP_ER_ZLIB, ret); + zip_fclose(zf); + return NULL; + } + } + + return zf; +} + + + +int +_zip_file_fillbuf(void *buf, size_t buflen, struct zip_file *zf) +{ + int i, j; + + if (zf->error.zip_err != ZIP_ER_OK) + return -1; + + if ((zf->flags & ZIP_ZF_EOF) || zf->cbytes_left <= 0 || buflen <= 0) + return 0; + + if (fseeko(zf->za->zp, zf->fpos, SEEK_SET) < 0) { + _zip_error_set(&zf->error, ZIP_ER_SEEK, errno); + return -1; + } + if (buflen < zf->cbytes_left) + i = buflen; + else + i = zf->cbytes_left; + + j = fread(buf, 1, i, zf->za->zp); + if (j == 0) { + _zip_error_set(&zf->error, ZIP_ER_EOF, 0); + j = -1; + } + else if (j < 0) + _zip_error_set(&zf->error, ZIP_ER_READ, errno); + else { + zf->fpos += j; + zf->cbytes_left -= j; + } + + return j; +} + + + +static struct zip_file * +_zip_file_new(struct zip *za) +{ + struct zip_file *zf, **file; + int n; + + if ((zf=(struct zip_file *)malloc(sizeof(struct zip_file))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if (za->nfile >= za->nfile_alloc-1) { + n = za->nfile_alloc + 10; + file = (struct zip_file **)realloc(za->file, + n*sizeof(struct zip_file *)); + if (file == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + free(zf); + return NULL; + } + za->nfile_alloc = n; + za->file = file; + } + + za->file[za->nfile++] = zf; + + zf->za = za; + _zip_error_init(&zf->error); + zf->flags = 0; + zf->crc = crc32(0L, Z_NULL, 0); + zf->crc_orig = 0; + zf->method = -1; + zf->bytes_left = zf->cbytes_left = 0; + zf->fpos = 0; + zf->buffer = NULL; + zf->zstr = NULL; + + return zf; +} + + +ZIP_EXTERN struct zip_file * +zip_fopen(struct zip *za, const char *fname, int flags) +{ + int idx; + + if ((idx=zip_name_locate(za, fname, flags)) < 0) + return NULL; + + return zip_fopen_index(za, idx, flags); +} + + +ZIP_EXTERN int +zip_set_file_comment(struct zip *za, int idx, const char *comment, int len) +{ + char *tmpcom; + + if (idx < 0 || idx >= za->nentry + || len < 0 || len > MAXCOMLEN + || (len > 0 && comment == NULL)) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (len > 0) { + if ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL) + return -1; + } + else + tmpcom = NULL; + + free(za->entry[idx].ch_comment); + za->entry[idx].ch_comment = tmpcom; + za->entry[idx].ch_comment_len = len; + + return 0; +} + + +ZIP_EXTERN struct zip_source * +zip_source_file(struct zip *za, const char *fname, myoff_t start, myoff_t len) +{ + if (za == NULL) + return NULL; + + if (fname == NULL || start < 0 || len < -1) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + return _zip_source_file_or_p(za, fname, NULL, start, len); +} + + +struct read_data { + const char *buf, *data, *end; + time_t mtime; + int freep; +}; + +static ssize_t read_data(void *state, void *data, size_t len, + enum zip_source_cmd cmd); + + + +ZIP_EXTERN struct zip_source * +zip_source_buffer(struct zip *za, const void *data, myoff_t len, int freep) +{ + struct read_data *f; + struct zip_source *zs; + + if (za == NULL) + return NULL; + + if (len < 0 || (data == NULL && len > 0)) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((f=(struct read_data *)malloc(sizeof(*f))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + f->data = (const char *)data; + f->end = ((const char *)data)+len; + f->freep = freep; + f->mtime = time(NULL); + + if ((zs=zip_source_function(za, read_data, f)) == NULL) { + free(f); + return NULL; + } + + return zs; +} + + + +static ssize_t +read_data(void *state, void *data, size_t len, enum zip_source_cmd cmd) +{ + struct read_data *z; + char *buf; + size_t n; + + z = (struct read_data *)state; + buf = (char *)data; + + switch (cmd) { + case ZIP_SOURCE_OPEN: + z->buf = z->data; + return 0; + + case ZIP_SOURCE_READ: + n = z->end - z->buf; + if (n > len) + n = len; + + if (n) { + memcpy(buf, z->buf, n); + z->buf += n; + } + + return n; + + case ZIP_SOURCE_CLOSE: + return 0; + + case ZIP_SOURCE_STAT: + { + struct zip_stat *st; + + if (len < sizeof(*st)) + return -1; + + st = (struct zip_stat *)data; + + zip_stat_init(st); + st->mtime = z->mtime; + st->size = z->end - z->data; + + return sizeof(*st); + } + + case ZIP_SOURCE_ERROR: + { + int *e; + + if (len < sizeof(int)*2) + return -1; + + e = (int *)data; + e[0] = e[1] = 0; + } + return sizeof(int)*2; + + case ZIP_SOURCE_FREE: + if (z->freep) { + free((void *)z->data); + z->data = NULL; + } + free(z); + return 0; + + default: + ; + } + + return -1; +} + + +int +_zip_set_name(struct zip *za, int idx, const char *name) +{ + char *s; + int i; + + if (idx < 0 || idx >= za->nentry || name == NULL) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if ((i=_zip_name_locate(za, name, 0, NULL)) != -1 && i != idx) { + _zip_error_set(&za->error, ZIP_ER_EXISTS, 0); + return -1; + } + + /* no effective name change */ + if (i == idx) + return 0; + + if ((s=strdup(name)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + + if (za->entry[idx].state == ZIP_ST_UNCHANGED) + za->entry[idx].state = ZIP_ST_RENAMED; + + free(za->entry[idx].ch_filename); + za->entry[idx].ch_filename = s; + + return 0; +} + + +ZIP_EXTERN int +zip_set_archive_flag(struct zip *za, int flag, int value) +{ + if (value) + za->ch_flags |= flag; + else + za->ch_flags &= ~flag; + + return 0; +} + + +void +_zip_unchange_data(struct zip_entry *ze) +{ + if (ze->source) { + (void)ze->source->f(ze->source->ud, NULL, 0, ZIP_SOURCE_FREE); + free(ze->source); + ze->source = NULL; + } + + ze->state = ze->ch_filename ? ZIP_ST_RENAMED : ZIP_ST_UNCHANGED; +} + + +ZIP_EXTERN int +zip_unchange_archive(struct zip *za) +{ + free(za->ch_comment); + za->ch_comment = NULL; + za->ch_comment_len = -1; + + za->ch_flags = za->flags; + + return 0; +} + +ZIP_EXTERN int +zip_unchange(struct zip *za, int idx) +{ + return _zip_unchange(za, idx, 0); +} + + + +int +_zip_unchange(struct zip *za, int idx, int allow_duplicates) +{ + int i; + + if (idx < 0 || idx >= za->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (za->entry[idx].ch_filename) { + if (!allow_duplicates) { + i = _zip_name_locate(za, + _zip_get_name(za, idx, ZIP_FL_UNCHANGED, NULL), + 0, NULL); + if (i != -1 && i != idx) { + _zip_error_set(&za->error, ZIP_ER_EXISTS, 0); + return -1; + } + } + + free(za->entry[idx].ch_filename); + za->entry[idx].ch_filename = NULL; + } + + free(za->entry[idx].ch_comment); + za->entry[idx].ch_comment = NULL; + za->entry[idx].ch_comment_len = -1; + + _zip_unchange_data(za->entry+idx); + + return 0; +} + +ZIP_EXTERN int +zip_unchange_all(struct zip *za) +{ + int ret, i; + + ret = 0; + for (i=0; i<za->nentry; i++) + ret |= _zip_unchange(za, i, 1); + + ret |= zip_unchange_archive(za); + + return ret; +} + + +ZIP_EXTERN int +zip_set_archive_comment(struct zip *za, const char *comment, int len) +{ + char *tmpcom; + + if (len < 0 || len > MAXCOMLEN + || (len > 0 && comment == NULL)) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (len > 0) { + if ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL) + return -1; + } + else + tmpcom = NULL; + + free(za->ch_comment); + za->ch_comment = tmpcom; + za->ch_comment_len = len; + + return 0; +} + + +ZIP_EXTERN int +zip_replace(struct zip *za, int idx, struct zip_source *source) +{ + if (idx < 0 || idx >= za->nentry || source == NULL) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (_zip_replace(za, idx, NULL, source) == -1) + return -1; + + return 0; +} + + + + +int +_zip_replace(struct zip *za, int idx, const char *name, + struct zip_source *source) +{ + if (idx == -1) { + if (_zip_entry_new(za) == NULL) + return -1; + + idx = za->nentry - 1; + } + + _zip_unchange_data(za->entry+idx); + + if (name && _zip_set_name(za, idx, name) != 0) + return -1; + + za->entry[idx].state = ((za->cdir == NULL || idx >= za->cdir->nentry) + ? ZIP_ST_ADDED : ZIP_ST_REPLACED); + za->entry[idx].source = source; + + return idx; +} + + +ZIP_EXTERN int +zip_rename(struct zip *za, int idx, const char *name) +{ + const char *old_name; + int old_is_dir, new_is_dir; + + if (idx >= za->nentry || idx < 0 || name[0] == '\0') { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if ((old_name=zip_get_name(za, idx, 0)) == NULL) + return -1; + + new_is_dir = (name[strlen(name)-1] == '/'); + old_is_dir = (old_name[strlen(old_name)-1] == '/'); + + if (new_is_dir != old_is_dir) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + return _zip_set_name(za, idx, name); +} + +#include <sys/stat.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void set_error(int *, struct zip_error *, int); +static struct zip *_zip_allocate_new(const char *, int *); +static int _zip_checkcons(FILE *, struct zip_cdir *, struct zip_error *); +static void _zip_check_torrentzip(struct zip *); +static struct zip_cdir *_zip_find_central_dir(FILE *, int, int *, myoff_t); +static int _zip_file_exists(const char *, int, int *); +static int _zip_headercomp(struct zip_dirent *, int, + struct zip_dirent *, int); +static unsigned char *_zip_memmem(const unsigned char *, int, + const unsigned char *, int); +static struct zip_cdir *_zip_readcdir(FILE *, unsigned char *, unsigned char *, + int, int, struct zip_error *); + + + +ZIP_EXTERN struct zip * +zip_open(const char *fn, int flags, int *zep) +{ + FILE *fp; + struct zip *za; + struct zip_cdir *cdir; + int i; + myoff_t len; + + switch (_zip_file_exists(fn, flags, zep)) { + case -1: + return NULL; + case 0: + return _zip_allocate_new(fn, zep); + default: + break; + } + + if ((fp=fopen(fn, "rb")) == NULL) { + set_error(zep, NULL, ZIP_ER_OPEN); + return NULL; + } + + fseeko(fp, 0, SEEK_END); + len = ftello(fp); + + /* treat empty files as empty archives */ + if (len == 0) { + if ((za=_zip_allocate_new(fn, zep)) == NULL) + fclose(fp); + else + za->zp = fp; + return za; + } + + cdir = _zip_find_central_dir(fp, flags, zep, len); + if (cdir == NULL) { + fclose(fp); + return NULL; + } + + if ((za=_zip_allocate_new(fn, zep)) == NULL) { + _zip_cdir_free(cdir); + fclose(fp); + return NULL; + } + + za->cdir = cdir; + za->zp = fp; + + if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry)) + * cdir->nentry)) == NULL) { + set_error(zep, NULL, ZIP_ER_MEMORY); + _zip_free(za); + return NULL; + } + for (i=0; i<cdir->nentry; i++) + _zip_entry_new(za); + + _zip_check_torrentzip(za); + za->ch_flags = za->flags; + + return za; +} + + + +static void +set_error(int *zep, struct zip_error *err, int ze) +{ + int se; + + if (err) { + _zip_error_get(err, &ze, &se); + if (zip_error_get_sys_type(ze) == ZIP_ET_SYS) + errno = se; + } + + if (zep) + *zep = ze; +} + + + +/* _zip_readcdir: + tries to find a valid end-of-central-directory at the beginning of + buf, and then the corresponding central directory entries. + Returns a struct zip_cdir which contains the central directory + entries, or NULL if unsuccessful. */ + +static struct zip_cdir * +_zip_readcdir(FILE *fp, unsigned char *buf, unsigned char *eocd, int buflen, + int flags, struct zip_error *error) +{ + struct zip_cdir *cd; + unsigned char *cdp, **bufp; + int i, comlen, nentry; + + comlen = buf + buflen - eocd - EOCDLEN; + if (comlen < 0) { + /* not enough bytes left for comment */ + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return NULL; + } + + /* check for end-of-central-dir magic */ + if (memcmp(eocd, EOCD_MAGIC, 4) != 0) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return NULL; + } + + if (memcmp(eocd+4, "\0\0\0\0", 4) != 0) { + _zip_error_set(error, ZIP_ER_MULTIDISK, 0); + return NULL; + } + + cdp = eocd + 8; + /* number of cdir-entries on this disk */ + i = _zip_read2(&cdp); + /* number of cdir-entries */ + nentry = _zip_read2(&cdp); + + if ((cd=_zip_cdir_new(nentry, error)) == NULL) + return NULL; + + cd->size = _zip_read4(&cdp); + cd->offset = _zip_read4(&cdp); + cd->comment = NULL; + cd->comment_len = _zip_read2(&cdp); + + if ((comlen < cd->comment_len) || (cd->nentry != i)) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + free(cd); + return NULL; + } + if ((flags & ZIP_CHECKCONS) && comlen != cd->comment_len) { + _zip_error_set(error, ZIP_ER_INCONS, 0); + free(cd); + return NULL; + } + + if (cd->comment_len) { + if ((cd->comment=(char *)_zip_memdup(eocd+EOCDLEN, + cd->comment_len, error)) + == NULL) { + free(cd); + return NULL; + } + } + + cdp = eocd; + if (cd->size < (unsigned int)(eocd-buf)) { + /* if buffer already read in, use it */ + cdp = eocd - cd->size; + bufp = &cdp; + } + else { + /* go to start of cdir and read it entry by entry */ + bufp = NULL; + clearerr(fp); + fseeko(fp, cd->offset, SEEK_SET); + /* possible consistency check: cd->offset = + len-(cd->size+cd->comment_len+EOCDLEN) ? */ + if (ferror(fp) || ((unsigned long)ftello(fp) != cd->offset)) { + /* seek error or offset of cdir wrong */ + if (ferror(fp)) + _zip_error_set(error, ZIP_ER_SEEK, errno); + else + _zip_error_set(error, ZIP_ER_NOZIP, 0); + free(cd); + return NULL; + } + } + + for (i=0; i<cd->nentry; i++) { + if ((_zip_dirent_read(cd->entry+i, fp, bufp, eocd-cdp, 0, + error)) < 0) { + cd->nentry = i; + _zip_cdir_free(cd); + return NULL; + } + } + + return cd; +} + + + +/* _zip_checkcons: + Checks the consistency of the central directory by comparing central + directory entries with local headers and checking for plausible + file and header offsets. Returns -1 if not plausible, else the + difference between the lowest and the highest fileposition reached */ + +static int +_zip_checkcons(FILE *fp, struct zip_cdir *cd, struct zip_error *error) +{ + int i; + unsigned int min, max, j; + struct zip_dirent temp; + + if (cd->nentry) { + max = cd->entry[0].offset; + min = cd->entry[0].offset; + } + else + min = max = 0; + + for (i=0; i<cd->nentry; i++) { + if (cd->entry[i].offset < min) + min = cd->entry[i].offset; + if (min > cd->offset) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return -1; + } + + j = cd->entry[i].offset + cd->entry[i].comp_size + + cd->entry[i].filename_len + LENTRYSIZE; + if (j > max) + max = j; + if (max > cd->offset) { + _zip_error_set(error, ZIP_ER_NOZIP, 0); + return -1; + } + + if (fseeko(fp, cd->entry[i].offset, SEEK_SET) != 0) { + _zip_error_set(error, ZIP_ER_SEEK, 0); + return -1; + } + + if (_zip_dirent_read(&temp, fp, NULL, 0, 1, error) == -1) + return -1; + + if (_zip_headercomp(cd->entry+i, 0, &temp, 1) != 0) { + _zip_error_set(error, ZIP_ER_INCONS, 0); + _zip_dirent_finalize(&temp); + return -1; + } + _zip_dirent_finalize(&temp); + } + + return max - min; +} + + + +/* _zip_check_torrentzip: + check wether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */ + +static void +_zip_check_torrentzip(struct zip *za) +{ + uLong crc_got, crc_should; + char buf[8+1]; + char *end; + + if (za->zp == NULL || za->cdir == NULL) + return; + + if (za->cdir->comment_len != TORRENT_SIG_LEN+8 + || strncmp(za->cdir->comment, TORRENT_SIG, TORRENT_SIG_LEN) != 0) + return; + + memcpy(buf, za->cdir->comment+TORRENT_SIG_LEN, 8); + buf[8] = '\0'; + errno = 0; + crc_should = strtoul(buf, &end, 16); + if ((crc_should == UINT_MAX && errno != 0) || (end && *end)) + return; + + if (_zip_filerange_crc(za->zp, za->cdir->offset, za->cdir->size, + &crc_got, NULL) < 0) + return; + + if (crc_got == crc_should) + za->flags |= ZIP_AFL_TORRENT; +} + + + + +/* _zip_headercomp: + compares two headers h1 and h2; if they are local headers, set + local1p or local2p respectively to 1, else 0. Return 0 if they + are identical, -1 if not. */ + +static int +_zip_headercomp(struct zip_dirent *h1, int local1p, struct zip_dirent *h2, + int local2p) +{ + if ((h1->version_needed != h2->version_needed) +#if 0 + /* some zip-files have different values in local + and global headers for the bitflags */ + || (h1->bitflags != h2->bitflags) +#endif + || (h1->comp_method != h2->comp_method) + || (h1->last_mod != h2->last_mod) + || (h1->filename_len != h2->filename_len) + || !h1->filename || !h2->filename + || strcmp(h1->filename, h2->filename)) + return -1; + + /* check that CRC and sizes are zero if data descriptor is used */ + if ((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local1p + && (h1->crc != 0 + || h1->comp_size != 0 + || h1->uncomp_size != 0)) + return -1; + if ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local2p + && (h2->crc != 0 + || h2->comp_size != 0 + || h2->uncomp_size != 0)) + return -1; + + /* check that CRC and sizes are equal if no data descriptor is used */ + if (((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local1p == 0) + && ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local2p == 0)) { + if ((h1->crc != h2->crc) + || (h1->comp_size != h2->comp_size) + || (h1->uncomp_size != h2->uncomp_size)) + return -1; + } + + if ((local1p == local2p) + && ((h1->extrafield_len != h2->extrafield_len) + || (h1->extrafield_len && h2->extrafield + && memcmp(h1->extrafield, h2->extrafield, + h1->extrafield_len)))) + return -1; + + /* if either is local, nothing more to check */ + if (local1p || local2p) + return 0; + + if ((h1->version_madeby != h2->version_madeby) + || (h1->disk_number != h2->disk_number) + || (h1->int_attrib != h2->int_attrib) + || (h1->ext_attrib != h2->ext_attrib) + || (h1->offset != h2->offset) + || (h1->comment_len != h2->comment_len) + || (h1->comment_len && h2->comment + && memcmp(h1->comment, h2->comment, h1->comment_len))) + return -1; + + return 0; +} + + + +static struct zip * +_zip_allocate_new(const char *fn, int *zep) +{ + struct zip *za; + struct zip_error error; + + if ((za=_zip_new(&error)) == NULL) { + set_error(zep, &error, 0); + return NULL; + } + + za->zn = strdup(fn); + if (!za->zn) { + _zip_free(za); + set_error(zep, NULL, ZIP_ER_MEMORY); + return NULL; + } + return za; +} + + + +static int +_zip_file_exists(const char *fn, int flags, int *zep) +{ + struct stat st; + + if (fn == NULL) { + set_error(zep, NULL, ZIP_ER_INVAL); + return -1; + } + + if (stat(fn, &st) != 0) { + if (flags & ZIP_CREATE) + return 0; + else { + set_error(zep, NULL, ZIP_ER_OPEN); + return -1; + } + } + else if ((flags & ZIP_EXCL)) { + set_error(zep, NULL, ZIP_ER_EXISTS); + return -1; + } + /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, + just like open() */ + + return 1; +} + + + +static struct zip_cdir * +_zip_find_central_dir(FILE *fp, int flags, int *zep, myoff_t len) +{ + struct zip_cdir *cdir, *cdirnew; + unsigned char *buf, *match; + int a, best, buflen, i; + struct zip_error zerr; + + i = fseeko(fp, -(len < CDBUFSIZE ? len : CDBUFSIZE), SEEK_END); + if (i == -1 && errno != EFBIG) { + /* seek before start of file on my machine */ + set_error(zep, NULL, ZIP_ER_SEEK); + return NULL; + } + + /* 64k is too much for stack */ + if ((buf=(unsigned char *)malloc(CDBUFSIZE)) == NULL) { + set_error(zep, NULL, ZIP_ER_MEMORY); + return NULL; + } + + clearerr(fp); + buflen = fread(buf, 1, CDBUFSIZE, fp); + + if (ferror(fp)) { + set_error(zep, NULL, ZIP_ER_READ); + free(buf); + return NULL; + } + + best = -1; + cdir = NULL; + match = buf; + _zip_error_set(&zerr, ZIP_ER_NOZIP, 0); + + while ((match=_zip_memmem(match, buflen-(match-buf)-18, + (const unsigned char *)EOCD_MAGIC, 4))!=NULL) { + /* found match -- check, if good */ + /* to avoid finding the same match all over again */ + match++; + if ((cdirnew=_zip_readcdir(fp, buf, match-1, buflen, flags, + &zerr)) == NULL) + continue; + + if (cdir) { + if (best <= 0) + best = _zip_checkcons(fp, cdir, &zerr); + a = _zip_checkcons(fp, cdirnew, &zerr); + if (best < a) { + _zip_cdir_free(cdir); + cdir = cdirnew; + best = a; + } + else + _zip_cdir_free(cdirnew); + } + else { + cdir = cdirnew; + if (flags & ZIP_CHECKCONS) + best = _zip_checkcons(fp, cdir, &zerr); + else + best = 0; + } + cdirnew = NULL; + } + + free(buf); + + if (best < 0) { + set_error(zep, &zerr, 0); + _zip_cdir_free(cdir); + return NULL; + } + + return cdir; +} + + + +static unsigned char * +_zip_memmem(const unsigned char *big, int biglen, const unsigned char *little, + int littlelen) +{ + const unsigned char *p; + + if ((biglen < littlelen) || (littlelen == 0)) + return NULL; + p = big-1; + while ((p=(const unsigned char *) + memchr(p+1, little[0], (size_t)(big-(p+1)+biglen-littlelen+1))) + != NULL) { + if (memcmp(p+1, little+1, littlelen-1)==0) + return (unsigned char *)p; + } + + return NULL; +} + + +/* _zip_new: + creates a new zipfile struct, and sets the contents to zero; returns + the new struct. */ + +struct zip * +_zip_new(struct zip_error *error) +{ + struct zip *za; + + za = (struct zip *)malloc(sizeof(struct zip)); + if (!za) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + za->zn = NULL; + za->zp = NULL; + _zip_error_init(&za->error); + za->cdir = NULL; + za->ch_comment = NULL; + za->ch_comment_len = -1; + za->nentry = za->nentry_alloc = 0; + za->entry = NULL; + za->nfile = za->nfile_alloc = 0; + za->file = NULL; + za->flags = za->ch_flags = 0; + + return za; +} + + +void * +_zip_memdup(const void *mem, size_t len, struct zip_error *error) +{ + void *ret; + + ret = malloc(len); + if (!ret) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + memcpy(ret, mem, len); + + return ret; +} + + +ZIP_EXTERN int +zip_get_num_files(struct zip *za) +{ + if (za == NULL) + return -1; + + return za->nentry; +} + +ZIP_EXTERN const char * +zip_get_name(struct zip *za, int idx, int flags) +{ + return _zip_get_name(za, idx, flags, &za->error); +} + + + +const char * +_zip_get_name(struct zip *za, int idx, int flags, struct zip_error *error) +{ + if (idx < 0 || idx >= za->nentry) { + _zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((flags & ZIP_FL_UNCHANGED) == 0) { + if (za->entry[idx].state == ZIP_ST_DELETED) { + _zip_error_set(error, ZIP_ER_DELETED, 0); + return NULL; + } + if (za->entry[idx].ch_filename) + return za->entry[idx].ch_filename; + } + + if (za->cdir == NULL || idx >= za->cdir->nentry) { + _zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + + return za->cdir->entry[idx].filename; +} + + +ZIP_EXTERN const char * +zip_get_file_comment(struct zip *za, int idx, int *lenp, int flags) +{ + if (idx < 0 || idx >= za->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((flags & ZIP_FL_UNCHANGED) + || (za->entry[idx].ch_comment_len == -1)) { + if (lenp != NULL) + *lenp = za->cdir->entry[idx].comment_len; + return za->cdir->entry[idx].comment; + } + + if (lenp != NULL) + *lenp = za->entry[idx].ch_comment_len; + return za->entry[idx].ch_comment; +} + + +ZIP_EXTERN int +zip_get_archive_flag(struct zip *za, int flag, int flags) +{ + int fl; + + fl = (flags & ZIP_FL_UNCHANGED) ? za->flags : za->ch_flags; + + return (fl & flag) ? 1 : 0; +} + + +ZIP_EXTERN const char * +zip_get_archive_comment(struct zip *za, int *lenp, int flags) +{ + if ((flags & ZIP_FL_UNCHANGED) + || (za->ch_comment_len == -1)) { + if (za->cdir) { + if (lenp != NULL) + *lenp = za->cdir->comment_len; + return za->cdir->comment; + } + else { + if (lenp != NULL) + *lenp = -1; + return NULL; + } + } + + if (lenp != NULL) + *lenp = za->ch_comment_len; + return za->ch_comment; +} + + +/* _zip_free: + frees the space allocated to a zipfile struct, and closes the + corresponding file. */ + +void +_zip_free(struct zip *za) +{ + int i; + + if (za == NULL) + return; + + if (za->zn) + free(za->zn); + + if (za->zp) + fclose(za->zp); + + _zip_cdir_free(za->cdir); + + if (za->entry) { + for (i=0; i<za->nentry; i++) { + _zip_entry_free(za->entry+i); + } + free(za->entry); + } + + for (i=0; i<za->nfile; i++) { + if (za->file[i]->error.zip_err == ZIP_ER_OK) { + _zip_error_set(&za->file[i]->error, ZIP_ER_ZIPCLOSED, 0); + za->file[i]->za = NULL; + } + } + + free(za->file); + + free(za); + + return; +} + + +ZIP_EXTERN ssize_t +zip_fread(struct zip_file *zf, void *outbuf, size_t toread) +{ + int ret; + size_t out_before, len; + int i; + + if (!zf) + return -1; + + if (zf->error.zip_err != 0) + return -1; + + if ((zf->flags & ZIP_ZF_EOF) || (toread == 0)) + return 0; + + if (zf->bytes_left == 0) { + zf->flags |= ZIP_ZF_EOF; + if (zf->flags & ZIP_ZF_CRC) { + if (zf->crc != zf->crc_orig) { + _zip_error_set(&zf->error, ZIP_ER_CRC, 0); + return -1; + } + } + return 0; + } + + if ((zf->flags & ZIP_ZF_DECOMP) == 0) { + ret = _zip_file_fillbuf(outbuf, toread, zf); + if (ret > 0) { + if (zf->flags & ZIP_ZF_CRC) + zf->crc = crc32(zf->crc, (Bytef *)outbuf, ret); + zf->bytes_left -= ret; + } + return ret; + } + + zf->zstr->next_out = (Bytef *)outbuf; + zf->zstr->avail_out = toread; + out_before = zf->zstr->total_out; + + /* endless loop until something has been accomplished */ + for (;;) { + ret = inflate(zf->zstr, Z_SYNC_FLUSH); + + switch (ret) { + case Z_OK: + case Z_STREAM_END: + /* all ok */ + /* Z_STREAM_END probably won't happen, since we didn't + have a header */ + len = zf->zstr->total_out - out_before; + if (len >= zf->bytes_left || len >= toread) { + if (zf->flags & ZIP_ZF_CRC) + zf->crc = crc32(zf->crc, (Bytef *)outbuf, len); + zf->bytes_left -= len; + return len; + } + break; + + case Z_BUF_ERROR: + if (zf->zstr->avail_in == 0) { + i = _zip_file_fillbuf(zf->buffer, BUFSIZE, zf); + if (i == 0) { + _zip_error_set(&zf->error, ZIP_ER_INCONS, 0); + return -1; + } + else if (i < 0) + return -1; + zf->zstr->next_in = (Bytef *)zf->buffer; + zf->zstr->avail_in = i; + continue; + } + /* fallthrough */ + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_STREAM_ERROR: + case Z_MEM_ERROR: + _zip_error_set(&zf->error, ZIP_ER_ZLIB, ret); + return -1; + } + } +} + + +ZIP_EXTERN const char * +zip_strerror(struct zip *za) +{ + return _zip_error_strerror(&za->error); +} + + +ZIP_EXTERN void +zip_stat_init(struct zip_stat *st) +{ + st->name = NULL; + st->index = -1; + st->crc = 0; + st->mtime = (time_t)-1; + st->size = -1; + st->comp_size = -1; + st->comp_method = ZIP_CM_STORE; + st->encryption_method = ZIP_EM_NONE; +} + + +ZIP_EXTERN int +zip_stat_index(struct zip *za, int index, int flags, struct zip_stat *st) +{ + const char *name; + + if (index < 0 || index >= za->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + if ((name=zip_get_name(za, index, flags)) == NULL) + return -1; + + + if ((flags & ZIP_FL_UNCHANGED) == 0 + && ZIP_ENTRY_DATA_CHANGED(za->entry+index)) { + if (za->entry[index].source->f(za->entry[index].source->ud, + st, sizeof(*st), ZIP_SOURCE_STAT) < 0) { + _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); + return -1; + } + } + else { + if (za->cdir == NULL || index >= za->cdir->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + st->crc = za->cdir->entry[index].crc; + st->size = za->cdir->entry[index].uncomp_size; + st->mtime = za->cdir->entry[index].last_mod; + st->comp_size = za->cdir->entry[index].comp_size; + st->comp_method = za->cdir->entry[index].comp_method; + if (za->cdir->entry[index].bitflags & ZIP_GPBF_ENCRYPTED) { + if (za->cdir->entry[index].bitflags & ZIP_GPBF_STRONG_ENCRYPTION) { + /* XXX */ + st->encryption_method = ZIP_EM_UNKNOWN; + } + else + st->encryption_method = ZIP_EM_TRAD_PKWARE; + } + else + st->encryption_method = ZIP_EM_NONE; + /* st->bitflags = za->cdir->entry[index].bitflags; */ + } + + st->index = index; + st->name = name; + + return 0; +} + + +ZIP_EXTERN int +zip_stat(struct zip *za, const char *fname, int flags, struct zip_stat *st) +{ + int idx; + + if ((idx=zip_name_locate(za, fname, flags)) < 0) + return -1; + + return zip_stat_index(za, idx, flags, st); +} + + +struct read_zip { + struct zip_file *zf; + struct zip_stat st; + myoff_t off, len; +}; + +static ssize_t read_zip(void *st, void *data, size_t len, + enum zip_source_cmd cmd); + + + +ZIP_EXTERN struct zip_source * +zip_source_zip(struct zip *za, struct zip *srcza, int srcidx, int flags, + myoff_t start, myoff_t len) +{ + struct zip_error error; + struct zip_source *zs; + struct read_zip *p; + + /* XXX: ZIP_FL_RECOMPRESS */ + + if (za == NULL) + return NULL; + + if (srcza == NULL || start < 0 || len < -1 || srcidx < 0 || srcidx >= srcza->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((flags & ZIP_FL_UNCHANGED) == 0 + && ZIP_ENTRY_DATA_CHANGED(srcza->entry+srcidx)) { + _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); + return NULL; + } + + if (len == 0) + len = -1; + + if (start == 0 && len == -1 && (flags & ZIP_FL_RECOMPRESS) == 0) + flags |= ZIP_FL_COMPRESSED; + else + flags &= ~ZIP_FL_COMPRESSED; + + if ((p=(struct read_zip *)malloc(sizeof(*p))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + _zip_error_copy(&error, &srcza->error); + + if (zip_stat_index(srcza, srcidx, flags, &p->st) < 0 + || (p->zf=zip_fopen_index(srcza, srcidx, flags)) == NULL) { + free(p); + _zip_error_copy(&za->error, &srcza->error); + _zip_error_copy(&srcza->error, &error); + + return NULL; + } + p->off = start; + p->len = len; + + if ((flags & ZIP_FL_COMPRESSED) == 0) { + p->st.size = p->st.comp_size = len; + p->st.comp_method = ZIP_CM_STORE; + p->st.crc = 0; + } + + if ((zs=zip_source_function(za, read_zip, p)) == NULL) { + free(p); + return NULL; + } + + return zs; +} + + + +static ssize_t +read_zip(void *state, void *data, size_t len, enum zip_source_cmd cmd) +{ + struct read_zip *z; + char b[8192], *buf; + int i, n; + + z = (struct read_zip *)state; + buf = (char *)data; + + switch (cmd) { + case ZIP_SOURCE_OPEN: + for (n=0; n<z->off; n+= i) { + i = (z->off-n > sizeof(b) ? sizeof(b) : z->off-n); + if ((i=zip_fread(z->zf, b, i)) < 0) { + zip_fclose(z->zf); + z->zf = NULL; + return -1; + } + } + return 0; + + case ZIP_SOURCE_READ: + if (z->len != -1) + n = len > z->len ? z->len : len; + else + n = len; + + + if ((i=zip_fread(z->zf, buf, n)) < 0) + return -1; + + if (z->len != -1) + z->len -= i; + + return i; + + case ZIP_SOURCE_CLOSE: + return 0; + + case ZIP_SOURCE_STAT: + if (len < sizeof(z->st)) + return -1; + len = sizeof(z->st); + + memcpy(data, &z->st, len); + return len; + + case ZIP_SOURCE_ERROR: + { + int *e; + + if (len < sizeof(int)*2) + return -1; + + e = (int *)data; + zip_file_error_get(z->zf, e, e+1); + } + return sizeof(int)*2; + + case ZIP_SOURCE_FREE: + zip_fclose(z->zf); + free(z); + return 0; + + default: + ; + } + + return -1; +} + + +ZIP_EXTERN struct zip_source * +zip_source_function(struct zip *za, zip_source_callback zcb, void *ud) +{ + struct zip_source *zs; + + if (za == NULL) + return NULL; + + if ((zs=(struct zip_source *)malloc(sizeof(*zs))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + zs->f = zcb; + zs->ud = ud; + + return zs; +} + + +ZIP_EXTERN void +zip_source_free(struct zip_source *source) +{ + if (source == NULL) + return; + + (void)source->f(source->ud, NULL, 0, ZIP_SOURCE_FREE); + + free(source); +} + + +struct read_file { + char *fname; /* name of file to copy from */ + FILE *f; /* file to copy from */ + myoff_t off; /* start offset of */ + myoff_t len; /* lengt of data to copy */ + myoff_t remain; /* bytes remaining to be copied */ + int e[2]; /* error codes */ +}; + +static ssize_t read_file(void *state, void *data, size_t len, + enum zip_source_cmd cmd); + + + +ZIP_EXTERN struct zip_source * +zip_source_filep(struct zip *za, FILE *file, myoff_t start, myoff_t len) +{ + if (za == NULL) + return NULL; + + if (file == NULL || start < 0 || len < -1) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + return _zip_source_file_or_p(za, NULL, file, start, len); +} + + + +struct zip_source * +_zip_source_file_or_p(struct zip *za, const char *fname, FILE *file, + myoff_t start, myoff_t len) +{ + struct read_file *f; + struct zip_source *zs; + + if (file == NULL && fname == NULL) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return NULL; + } + + if ((f=(struct read_file *)malloc(sizeof(struct read_file))) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return NULL; + } + + f->fname = NULL; + if (fname) { + if ((f->fname=strdup(fname)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + free(f); + return NULL; + } + } + f->f = file; + f->off = start; + f->len = (len ? len : -1); + + if ((zs=zip_source_function(za, read_file, f)) == NULL) { + free(f); + return NULL; + } + + return zs; +} + + + +static ssize_t +read_file(void *state, void *data, size_t len, enum zip_source_cmd cmd) +{ + struct read_file *z; + char *buf; + int i, n; + + z = (struct read_file *)state; + buf = (char *)data; + + switch (cmd) { + case ZIP_SOURCE_OPEN: + if (z->fname) { + if ((z->f=fopen(z->fname, "rb")) == NULL) { + z->e[0] = ZIP_ER_OPEN; + z->e[1] = errno; + return -1; + } + } + + if (fseeko(z->f, z->off, SEEK_SET) < 0) { + z->e[0] = ZIP_ER_SEEK; + z->e[1] = errno; + return -1; + } + z->remain = z->len; + return 0; + + case ZIP_SOURCE_READ: + if (z->remain != -1) + n = len > z->remain ? z->remain : len; + else + n = len; + + if ((i=fread(buf, 1, n, z->f)) < 0) { + z->e[0] = ZIP_ER_READ; + z->e[1] = errno; + return -1; + } + + if (z->remain != -1) + z->remain -= i; + + return i; + + case ZIP_SOURCE_CLOSE: + if (z->fname) { + fclose(z->f); + z->f = NULL; + } + return 0; + + case ZIP_SOURCE_STAT: + { + struct zip_stat *st; + struct stat fst; + int err; + + if (len < sizeof(*st)) + return -1; + + if (z->f) + err = fstat(fileno(z->f), &fst); + else + err = stat(z->fname, &fst); + + if (err != 0) { + z->e[0] = ZIP_ER_READ; /* best match */ + z->e[1] = errno; + return -1; + } + + st = (struct zip_stat *)data; + + zip_stat_init(st); + st->mtime = fst.st_mtime; + if (z->len != -1) + st->size = z->len; + else if ((fst.st_mode&S_IFMT) == S_IFREG) + st->size = fst.st_size; + + return sizeof(*st); + } + + case ZIP_SOURCE_ERROR: + if (len < sizeof(int)*2) + return -1; + + memcpy(data, z->e, sizeof(int)*2); + return sizeof(int)*2; + + case ZIP_SOURCE_FREE: + free(z->fname); + if (z->f) + fclose(z->f); + free(z); + return 0; + + default: + ; + } + + return -1; +} + + +ZIP_EXTERN int +zip_name_locate(struct zip *za, const char *fname, int flags) +{ + return _zip_name_locate(za, fname, flags, &za->error); +} + + + +int +_zip_name_locate(struct zip *za, const char *fname, int flags, + struct zip_error *error) +{ + int (*cmp)(const char *, const char *); + const char *fn, *p; + int i, n; + + if (fname == NULL) { + _zip_error_set(error, ZIP_ER_INVAL, 0); + return -1; + } + + cmp = (flags & ZIP_FL_NOCASE) ? strcasecmp : strcmp; + + n = (flags & ZIP_FL_UNCHANGED) ? za->cdir->nentry : za->nentry; + for (i=0; i<n; i++) { + if (flags & ZIP_FL_UNCHANGED) + fn = za->cdir->entry[i].filename; + else + fn = _zip_get_name(za, i, flags, error); + + /* newly added (partially filled) entry */ + if (fn == NULL) + continue; + + if (flags & ZIP_FL_NODIR) { + p = strrchr(fn, '/'); + if (p) + fn = p+1; + } + + if (cmp(fname, fn) == 0) + return i; + } + + _zip_error_set(error, ZIP_ER_NOENT, 0); + return -1; +} + diff --git a/tests/deps/zip-0.2.1/zip/zipfiles.nim b/tests/deps/zip-0.2.1/zip/zipfiles.nim new file mode 100644 index 000000000..ca1979488 --- /dev/null +++ b/tests/deps/zip-0.2.1/zip/zipfiles.nim @@ -0,0 +1,193 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements a zip archive creator/reader/modifier. + +import + streams, libzip, times, os, strutils + +const BufSize = 8 * 1024 + +type + ZipArchive* = object of RootObj ## represents a zip archive + mode: FileMode + w: PZip +{.deprecated: [TZipArchive: ZipArchive].} + +proc zipError(z: var ZipArchive) = + var e: ref IOError + new(e) + e.msg = $zip_strerror(z.w) + raise e + +proc open*(z: var ZipArchive, filename: string, mode: FileMode = fmRead): bool = + ## Opens a zip file for reading, writing or appending. All file modes are + ## supported. Returns true iff successful, false otherwise. + var err, flags: int32 + case mode + of fmRead, fmReadWriteExisting, fmAppend: flags = 0 + of fmWrite: + if existsFile(filename): removeFile(filename) + flags = ZIP_CREATE or ZIP_EXCL + of fmReadWrite: flags = ZIP_CREATE + z.w = zip_open(filename, flags, addr(err)) + z.mode = mode + result = z.w != nil + +proc close*(z: var ZipArchive) = + ## Closes a zip file. + zip_close(z.w) + +proc createDir*(z: var ZipArchive, dir: string) = + ## Creates a directory within the `z` archive. This does not fail if the + ## directory already exists. Note that for adding a file like + ## ``"path1/path2/filename"`` it is not necessary + ## to create the ``"path/path2"`` subdirectories - it will be done + ## automatically by ``addFile``. + assert(z.mode != fmRead) + discard zip_add_dir(z.w, dir) + zip_error_clear(z.w) + +proc addFile*(z: var ZipArchive, dest, src: string) = + ## Adds the file `src` to the archive `z` with the name `dest`. `dest` + ## may contain a path that will be created. + assert(z.mode != fmRead) + if not fileExists(src): + raise newException(IOError, "File '" & src & "' does not exist") + var zipsrc = zip_source_file(z.w, src, 0, -1) + if zipsrc == nil: + #echo("Dest: " & dest) + #echo("Src: " & src) + zipError(z) + if zip_add(z.w, dest, zipsrc) < 0'i32: + zip_source_free(zipsrc) + zipError(z) + +proc addFile*(z: var ZipArchive, file: string) = + ## A shortcut for ``addFile(z, file, file)``, i.e. the name of the source is + ## the name of the destination. + addFile(z, file, file) + +proc mySourceCallback(state, data: pointer, len: int, + cmd: ZipSourceCmd): int {.cdecl.} = + var src = cast[Stream](state) + case cmd + of ZIP_SOURCE_OPEN: + if src.setPositionImpl != nil: setPosition(src, 0) # reset + of ZIP_SOURCE_READ: + result = readData(src, data, len) + of ZIP_SOURCE_CLOSE: close(src) + of ZIP_SOURCE_STAT: + var stat = cast[PZipStat](data) + zip_stat_init(stat) + stat.size = high(int32)-1 # we don't know the size + stat.mtime = getTime() + result = sizeof(ZipStat) + of ZIP_SOURCE_ERROR: + var err = cast[ptr array[0..1, cint]](data) + err[0] = ZIP_ER_INTERNAL + err[1] = 0 + result = 2*sizeof(cint) + of constZIP_SOURCE_FREE: GC_unref(src) + of ZIP_SOURCE_SUPPORTS: + # By default a read-only source is supported, which suits us. + result = -1 + else: + # An unknown command, failing + result = -1 + +proc addFile*(z: var ZipArchive, dest: string, src: Stream) = + ## 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. + assert(z.mode != fmRead) + GC_ref(src) + var zipsrc = zip_source_function(z.w, mySourceCallback, cast[pointer](src)) + if zipsrc == nil: zipError(z) + if zip_add(z.w, dest, zipsrc) < 0'i32: + zip_source_free(zipsrc) + zipError(z) + +# -------------- zip file stream --------------------------------------------- + +type + TZipFileStream = object of StreamObj + f: PZipFile + atEnd: bool + + PZipFileStream* = + ref TZipFileStream ## a reader stream of a file within a zip archive + +proc fsClose(s: Stream) = zip_fclose(PZipFileStream(s).f) +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) + if result == 0: + PZipFileStream(s).atEnd = true + +proc newZipFileStream(f: PZipFile): PZipFileStream = + new(result) + result.f = f + result.atEnd = false + result.closeImpl = fsClose + result.readDataImpl = fsReadData + result.atEndImpl = fsAtEnd + # other methods are nil! + +# ---------------------------------------------------------------------------- + +proc getStream*(z: var ZipArchive, filename: string): PZipFileStream = + ## returns a stream that can be used to read the file named `filename` + ## from the archive `z`. Returns nil in case of an error. + ## The returned stream does not support the `setPosition`, `getPosition`, + ## `writeData` or `atEnd` methods. + var x = zip_fopen(z.w, filename, 0'i32) + if x != nil: result = newZipFileStream(x) + +iterator walkFiles*(z: var ZipArchive): string = + ## walks over all files in the archive `z` and returns the filename + ## (including the path). + var i = 0'i32 + var num = zip_get_num_files(z.w) + while i < num: + yield $zip_get_name(z.w, i, 0'i32) + inc(i) + +proc extractFile*(z: var ZipArchive, srcFile: string, dest: Stream) = + ## extracts a file from the zip archive `z` to the destination stream. + var buf: array[BufSize, byte] + var strm = getStream(z, srcFile) + while true: + let bytesRead = strm.readData(addr(buf[0]), buf.len) + if bytesRead <= 0: break + dest.writeData(addr(buf[0]), bytesRead) + + dest.flush() + strm.close() + +proc extractFile*(z: var ZipArchive, srcFile: string, dest: string) = + ## extracts a file from the zip archive `z` to the destination filename. + var file = newFileStream(dest, fmWrite) + if file.isNil: + raise newException(IOError, "Failed to create output file: " & dest) + extractFile(z, srcFile, file) + file.close() + +proc extractAll*(z: var ZipArchive, dest: string) = + ## extracts all files from archive `z` to the destination directory. + createDir(dest) + for file in walkFiles(z): + if file.contains("/"): + createDir(dest / file[0..file.rfind("/")]) + extractFile(z, file, dest / file) + +when not defined(testing) and isMainModule: + var zip: ZipArchive + if not zip.open("nim-0.11.0.zip"): + raise newException(IOError, "opening zip failed") + zip.extractAll("test") diff --git a/tests/deps/zip-0.2.1/zip/zlib.nim b/tests/deps/zip-0.2.1/zip/zlib.nim new file mode 100644 index 000000000..f41ed5cfe --- /dev/null +++ b/tests/deps/zip-0.2.1/zip/zlib.nim @@ -0,0 +1,425 @@ +# Converted from Pascal + +## Interface to the zlib http://www.zlib.net/ compression library. + +when defined(windows): + const libz = "zlib1.dll" +elif defined(macosx): + const libz = "libz.dylib" +else: + const libz = "libz.so.1" + +type + Uint* = int32 + Ulong* = int + Ulongf* = int + Pulongf* = ptr Ulongf + ZOffT* = int32 + Pbyte* = cstring + Pbytef* = cstring + Allocfunc* = proc (p: pointer, items: Uint, size: Uint): pointer{.cdecl.} + FreeFunc* = proc (p: pointer, address: pointer){.cdecl.} + InternalState*{.final, pure.} = object + PInternalState* = ptr InternalState + ZStream*{.final, pure.} = object + nextIn*: Pbytef + availIn*: Uint + totalIn*: Ulong + nextOut*: Pbytef + availOut*: Uint + totalOut*: Ulong + msg*: Pbytef + state*: PInternalState + zalloc*: Allocfunc + zfree*: FreeFunc + opaque*: pointer + dataType*: int32 + adler*: Ulong + reserved*: Ulong + + ZStreamRec* = ZStream + PZstream* = ptr ZStream + GzFile* = pointer + ZStreamHeader* = enum + DETECT_STREAM, + RAW_DEFLATE, + ZLIB_STREAM, + GZIP_STREAM + + ZlibStreamError* = object of Exception + +{.deprecated: [TInternalState: InternalState, TAllocfunc: Allocfunc, + TFreeFunc: FreeFunc, TZStream: ZStream, TZStreamRec: ZStreamRec].} + +const + Z_NO_FLUSH* = 0 + Z_PARTIAL_FLUSH* = 1 + Z_SYNC_FLUSH* = 2 + Z_FULL_FLUSH* = 3 + Z_FINISH* = 4 + Z_OK* = 0 + Z_STREAM_END* = 1 + Z_NEED_DICT* = 2 + Z_ERRNO* = -1 + Z_STREAM_ERROR* = -2 + Z_DATA_ERROR* = -3 + Z_MEM_ERROR* = -4 + Z_BUF_ERROR* = -5 + Z_VERSION_ERROR* = -6 + Z_NO_COMPRESSION* = 0 + Z_BEST_SPEED* = 1 + Z_BEST_COMPRESSION* = 9 + Z_DEFAULT_COMPRESSION* = -1 + Z_FILTERED* = 1 + Z_HUFFMAN_ONLY* = 2 + Z_DEFAULT_STRATEGY* = 0 + Z_BINARY* = 0 + Z_ASCII* = 1 + Z_UNKNOWN* = 2 + Z_DEFLATED* = 8 + Z_NULL* = 0 + Z_MEM_LEVEL* = 8 + MAX_WBITS* = 15 + +proc zlibVersion*(): cstring{.cdecl, dynlib: libz, importc: "zlibVersion".} +proc deflate*(strm: var ZStream, flush: int32): int32{.cdecl, dynlib: libz, + importc: "deflate".} +proc deflateEnd*(strm: var ZStream): int32{.cdecl, dynlib: libz, + importc: "deflateEnd".} +proc inflate*(strm: var ZStream, flush: int32): int32{.cdecl, dynlib: libz, + importc: "inflate".} +proc inflateEnd*(strm: var ZStream): int32{.cdecl, dynlib: libz, + importc: "inflateEnd".} +proc deflateSetDictionary*(strm: var ZStream, dictionary: Pbytef, + dictLength: Uint): int32{.cdecl, dynlib: libz, + importc: "deflateSetDictionary".} +proc deflateCopy*(dest, source: var ZStream): int32{.cdecl, dynlib: libz, + importc: "deflateCopy".} +proc deflateReset*(strm: var ZStream): int32{.cdecl, dynlib: libz, + importc: "deflateReset".} +proc deflateParams*(strm: var ZStream, level: int32, strategy: int32): int32{. + cdecl, dynlib: libz, importc: "deflateParams".} +proc inflateSetDictionary*(strm: var ZStream, dictionary: Pbytef, + dictLength: Uint): int32{.cdecl, dynlib: libz, + importc: "inflateSetDictionary".} +proc inflateSync*(strm: var ZStream): int32{.cdecl, dynlib: libz, + importc: "inflateSync".} +proc inflateReset*(strm: var ZStream): int32{.cdecl, dynlib: libz, + importc: "inflateReset".} +proc compress*(dest: Pbytef, destLen: Pulongf, source: Pbytef, sourceLen: Ulong): cint{. + cdecl, dynlib: libz, importc: "compress".} +proc compress2*(dest: Pbytef, destLen: Pulongf, source: Pbytef, + sourceLen: Ulong, level: cint): cint{.cdecl, dynlib: libz, + importc: "compress2".} +proc uncompress*(dest: Pbytef, destLen: Pulongf, source: Pbytef, + sourceLen: Ulong): cint{.cdecl, dynlib: libz, + importc: "uncompress".} +proc compressBound*(sourceLen: Ulong): Ulong {.cdecl, dynlib: libz, importc.} +proc gzopen*(path: cstring, mode: cstring): GzFile{.cdecl, dynlib: libz, + importc: "gzopen".} +proc gzdopen*(fd: int32, mode: cstring): GzFile{.cdecl, dynlib: libz, + importc: "gzdopen".} +proc gzsetparams*(thefile: GzFile, level: int32, strategy: int32): int32{.cdecl, + dynlib: libz, importc: "gzsetparams".} +proc gzread*(thefile: GzFile, buf: pointer, length: int): int32{.cdecl, + dynlib: libz, importc: "gzread".} +proc gzwrite*(thefile: GzFile, buf: pointer, length: int): int32{.cdecl, + dynlib: libz, importc: "gzwrite".} +proc gzprintf*(thefile: GzFile, format: Pbytef): int32{.varargs, cdecl, + dynlib: libz, importc: "gzprintf".} +proc gzputs*(thefile: GzFile, s: Pbytef): int32{.cdecl, dynlib: libz, + importc: "gzputs".} +proc gzgets*(thefile: GzFile, buf: Pbytef, length: int32): Pbytef{.cdecl, + dynlib: libz, importc: "gzgets".} +proc gzputc*(thefile: GzFile, c: char): char{.cdecl, dynlib: libz, + importc: "gzputc".} +proc gzgetc*(thefile: GzFile): char{.cdecl, dynlib: libz, importc: "gzgetc".} +proc gzflush*(thefile: GzFile, flush: int32): int32{.cdecl, dynlib: libz, + importc: "gzflush".} +proc gzseek*(thefile: GzFile, offset: ZOffT, whence: int32): ZOffT{.cdecl, + dynlib: libz, importc: "gzseek".} +proc gzrewind*(thefile: GzFile): int32{.cdecl, dynlib: libz, importc: "gzrewind".} +proc gztell*(thefile: GzFile): ZOffT{.cdecl, dynlib: libz, importc: "gztell".} +proc gzeof*(thefile: GzFile): int {.cdecl, dynlib: libz, importc: "gzeof".} +proc gzclose*(thefile: GzFile): int32{.cdecl, dynlib: libz, importc: "gzclose".} +proc gzerror*(thefile: GzFile, errnum: var int32): Pbytef{.cdecl, dynlib: libz, + importc: "gzerror".} +proc adler32*(adler: Ulong, buf: Pbytef, length: Uint): Ulong{.cdecl, + dynlib: libz, importc: "adler32".} + ## **Warning**: Adler-32 requires at least a few hundred bytes to get rolling. +proc crc32*(crc: Ulong, buf: Pbytef, length: Uint): Ulong{.cdecl, dynlib: libz, + importc: "crc32".} +proc deflateInitu*(strm: var ZStream, level: int32, version: cstring, + streamSize: int32): int32{.cdecl, dynlib: libz, + importc: "deflateInit_".} +proc inflateInitu*(strm: var ZStream, version: cstring, + streamSize: int32): int32 {. + cdecl, dynlib: libz, importc: "inflateInit_".} +proc deflateInit*(strm: var ZStream, level: int32): int32 +proc inflateInit*(strm: var ZStream): int32 +proc deflateInit2u*(strm: var ZStream, level: int32, `method`: int32, + windowBits: int32, memLevel: int32, strategy: int32, + version: cstring, streamSize: int32): int32 {.cdecl, + dynlib: libz, importc: "deflateInit2_".} +proc inflateInit2u*(strm: var ZStream, windowBits: int32, version: cstring, + streamSize: int32): int32{.cdecl, dynlib: libz, + importc: "inflateInit2_".} +proc deflateInit2*(strm: var ZStream, + level, `method`, windowBits, memLevel, + strategy: int32): int32 +proc inflateInit2*(strm: var ZStream, windowBits: int32): int32 +proc zError*(err: int32): cstring{.cdecl, dynlib: libz, importc: "zError".} +proc inflateSyncPoint*(z: PZstream): int32{.cdecl, dynlib: libz, + importc: "inflateSyncPoint".} +proc getCrcTable*(): pointer{.cdecl, dynlib: libz, importc: "get_crc_table".} + +proc deflateBound*(strm: var ZStream, sourceLen: ULong): ULong {.cdecl, + dynlib: libz, importc: "deflateBound".} + +proc deflateInit(strm: var ZStream, level: int32): int32 = + result = deflateInitu(strm, level, zlibVersion(), sizeof(ZStream).cint) + +proc inflateInit(strm: var ZStream): int32 = + result = inflateInitu(strm, zlibVersion(), sizeof(ZStream).cint) + +proc deflateInit2(strm: var ZStream, + level, `method`, windowBits, memLevel, + strategy: int32): int32 = + result = deflateInit2u(strm, level, `method`, windowBits, memLevel, + strategy, zlibVersion(), sizeof(ZStream).cint) + +proc inflateInit2(strm: var ZStream, windowBits: int32): int32 = + result = inflateInit2u(strm, windowBits, zlibVersion(), + sizeof(ZStream).cint) + +proc zlibAllocMem*(appData: pointer, items, size: int): pointer {.cdecl.} = + result = alloc(items * size) + +proc zlibFreeMem*(appData, `block`: pointer) {.cdecl.} = + dealloc(`block`) + + +proc compress*(sourceBuf: cstring; sourceLen: int; level=Z_DEFAULT_COMPRESSION; stream=GZIP_STREAM): string = + ## Given a cstring, returns its deflated version with an optional header. + ## + ## Valid argument for ``stream`` are + ## - ``ZLIB_STREAM`` - add a zlib header and footer. + ## - ``GZIP_STREAM`` - add a basic gzip header and footer. + ## - ``RAW_DEFLATE`` - no header is generated. + ## + ## Passing a nil cstring will crash this proc in release mode and assert in + ## debug mode. + ## + ## Compression level can be set with ``level`` argument. Currently + ## ``Z_DEFAULT_COMPRESSION`` is 6. + ## + ## Returns "" on failure. + assert(not sourceBuf.isNil) + assert(sourceLen >= 0) + + var z: ZStream + var windowBits = MAX_WBITS + case (stream) + of RAW_DEFLATE: windowBits = -MAX_WBITS + of GZIP_STREAM: windowBits = MAX_WBITS + 16 + of ZLIB_STREAM, DETECT_STREAM: + discard # DETECT_STREAM defaults to ZLIB_STREAM + + var status = deflateInit2(z, level.int32, Z_DEFLATED.int32, + windowBits.int32, Z_MEM_LEVEL.int32, + Z_DEFAULT_STRATEGY.int32) + case status + of Z_OK: discard + of Z_MEM_ERROR: raise newException(OutOfMemError, "") + of Z_STREAM_ERROR: raise newException(ZlibStreamError, "invalid zlib stream parameter!") + of Z_VERSION_ERROR: raise newException(ZlibStreamError, "zlib version mismatch!") + else: raise newException(ZlibStreamError, "Unkown error(" & $status & ") : " & $z.msg) + + let space = deflateBound(z, sourceLen) + var compressed = newStringOfCap(space) + z.next_in = sourceBuf + z.avail_in = sourceLen.Uint + z.next_out = addr(compressed[0]) + z.avail_out = space.Uint + + status = deflate(z, Z_FINISH) + if status != Z_STREAM_END: + discard deflateEnd(z) # cleanup allocated ressources + raise newException(ZlibStreamError, "Invalid stream state(" & $status & ") : " & $z.msg) + + status = deflateEnd(z) + if status != Z_OK: # cleanup allocated ressources + raise newException(ZlibStreamError, "Invalid stream state(" & $status & ") : " & $z.msg) + + compressed.setLen(z.total_out) + swap(result, compressed) + +proc compress*(input: string; level=Z_DEFAULT_COMPRESSION; stream=GZIP_STREAM): string = + ## Given a string, returns its deflated version with an optional header. + ## + ## Valid arguments for ``stream`` are + ## - ``ZLIB_STREAM`` - add a zlib header and footer. + ## - ``GZIP_STREAM`` - add a basic gzip header and footer. + ## - ``RAW_DEFLATE`` - no header is generated. + ## + ## Compression level can be set with ``level`` argument. Currently + ## ``Z_DEFAULT_COMPRESSION`` is 6. + ## + ## Returns "" on failure. + result = compress(input, input.len, level, stream) + +proc uncompress*(sourceBuf: cstring, sourceLen: Natural; stream=DETECT_STREAM): string = + ## Given a deflated buffer returns its inflated content as a string. + ## + ## Valid arguments for ``stream`` are + ## - ``DETECT_STREAM`` - detect if zlib or gzip header is present + ## and decompress stream. Fail on raw deflate stream. + ## - ``ZLIB_STREAM`` - decompress a zlib stream. + ## - ``GZIP_STREAM`` - decompress a gzip stream. + ## - ``RAW_DEFLATE`` - decompress a raw deflate stream. + ## + ## Passing a nil cstring will crash this proc in release mode and assert in + ## debug mode. + ## + ## Returns "" on problems. Failure is a very loose concept, it could be you + ## passing a non deflated string, or it could mean not having enough memory + ## for the inflated version. + ## + ## The uncompression algorithm is based on http://zlib.net/zpipe.c. + assert(not sourceBuf.isNil) + assert(sourceLen >= 0) + var z: ZStream + var decompressed: string = "" + var sbytes = 0 + var wbytes = 0 + ## allocate inflate state + + z.availIn = 0 + var wbits = case (stream) + of RAW_DEFLATE: -MAX_WBITS + of ZLIB_STREAM: MAX_WBITS + of GZIP_STREAM: MAX_WBITS + 16 + of DETECT_STREAM: MAX_WBITS + 32 + + var status = inflateInit2(z, wbits.int32) + + case status + of Z_OK: discard + of Z_MEM_ERROR: raise newException(OutOfMemError, "") + of Z_STREAM_ERROR: raise newException(ZlibStreamError, "invalid zlib stream parameter!") + of Z_VERSION_ERROR: raise newException(ZlibStreamError, "zlib version mismatch!") + else: raise newException(ZlibStreamError, "Unkown error(" & $status & ") : " & $z.msg) + + # run loop until all input is consumed. + # handle concatenated deflated stream with header. + while true: + z.availIn = (sourceLen - sbytes).int32 + + # no more input available + if (sourceLen - sbytes) <= 0: break + z.nextIn = sourceBuf[sbytes].unsafeaddr + + # run inflate() on available input until output buffer is full + while true: + # if written bytes >= output size : resize output + if wbytes >= decompressed.len: + let cur_outlen = decompressed.len + let new_outlen = if decompressed.len == 0: sourceLen*2 else: decompressed.len*2 + if new_outlen < cur_outlen: # unsigned integer overflow, buffer too large + discard inflateEnd(z); + raise newException(OverflowError, "zlib stream decompressed size is too large! (size > " & $int.high & ")") + + decompressed.setLen(new_outlen) + + # available space for decompression + let space = decompressed.len - wbytes + z.availOut = space.Uint + z.nextOut = decompressed[wbytes].addr + + status = inflate(z, Z_NO_FLUSH) + if status.int8 notin {Z_OK.int8, Z_STREAM_END.int8, Z_BUF_ERROR.int8}: + discard inflateEnd(z) + case status + of Z_MEM_ERROR: raise newException(OutOfMemError, "") + of Z_DATA_ERROR: raise newException(ZlibStreamError, "invalid zlib stream parameter!") + else: raise newException(ZlibStreamError, "Unkown error(" & $status & ") : " & $z.msg) + + # add written bytes, if any. + wbytes += space - z.availOut.int + + # may need more input + if not (z.availOut == 0): break + + # inflate() says stream is done + if (status == Z_STREAM_END): + # may have another stream concatenated + if z.availIn != 0: + sbytes = sourceLen - z.availIn # add consumed bytes + if inflateReset(z) != Z_OK: # reset zlib struct and try again + raise newException(ZlibStreamError, "Invalid stream state(" & $status & ") : " & $z.msg) + else: + break # end of decompression + + # clean up and don't care about any error + discard inflateEnd(z) + + if status != Z_STREAM_END: + raise newException(ZlibStreamError, "Invalid stream state(" & $status & ") : " & $z.msg) + + decompressed.setLen(wbytes) + swap(result, decompressed) + + +proc uncompress*(sourceBuf: string; stream=DETECT_STREAM): string = + ## Given a GZIP-ed string return its inflated content. + ## + ## Valid arguments for ``stream`` are + ## - ``DETECT_STREAM`` - detect if zlib or gzip header is present + ## and decompress stream. Fail on raw deflate stream. + ## - ``ZLIB_STREAM`` - decompress a zlib stream. + ## - ``GZIP_STREAM`` - decompress a gzip stream. + ## - ``RAW_DEFLATE`` - decompress a raw deflate stream. + ## + ## Returns "" on failure. + result = uncompress(sourceBuf, sourceBuf.len, stream) + + + +proc deflate*(buffer: var string; level=Z_DEFAULT_COMPRESSION; stream=GZIP_STREAM): bool {.discardable.} = + ## Convenience proc which deflates a string and insert an optional header/footer. + ## + ## Valid arguments for ``stream`` are + ## - ``ZLIB_STREAM`` - add a zlib header and footer. + ## - ``GZIP_STREAM`` - add a basic gzip header and footer. + ## - ``RAW_DEFLATE`` - no header is generated. + ## + ## Compression level can be set with ``level`` argument. Currently + ## ``Z_DEFAULT_COMPRESSION`` is 6. + ## + ## Returns true if `buffer` was successfully deflated otherwise the buffer is untouched. + + var temp = compress(addr(buffer[0]), buffer.len, level, stream) + if temp.len != 0: + swap(buffer, temp) + result = true + +proc inflate*(buffer: var string; stream=DETECT_STREAM): bool {.discardable.} = + ## Convenience proc which inflates a string containing compressed data + ## with an optional header. + ## + ## Valid argument for ``stream`` are: + ## - ``DETECT_STREAM`` - detect if zlib or gzip header is present + ## and decompress stream. Fail on raw deflate stream. + ## - ``ZLIB_STREAM`` - decompress a zlib stream. + ## - ``GZIP_STREAM`` - decompress a gzip stream. + ## - ``RAW_DEFLATE`` - decompress a raw deflate stream. + ## + ## It is ok to pass a buffer which doesn't contain deflated data, + ## in this case the proc won't modify the buffer. + ## + ## Returns true if `buffer` was successfully inflated. + + var temp = uncompress(addr(buffer[0]), buffer.len, stream) + if temp.len != 0: + swap(buffer, temp) + result = true diff --git a/tests/deps/zip-0.2.1/zip/zzip.nim b/tests/deps/zip-0.2.1/zip/zzip.nim new file mode 100644 index 000000000..553970e0c --- /dev/null +++ b/tests/deps/zip-0.2.1/zip/zzip.nim @@ -0,0 +1,176 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2008 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module is an interface to the zzip library. + +# Author: +# Guido Draheim <guidod@gmx.de> +# Tomi Ollila <Tomi.Ollila@iki.fi> +# Copyright (c) 1999,2000,2001,2002,2003,2004 Guido Draheim +# All rights reserved, +# usage allowed under the restrictions of the +# Lesser GNU General Public License +# or alternatively the restrictions +# of the Mozilla Public License 1.1 + +when defined(windows): + const + dllname = "zzip.dll" +else: + const + dllname = "libzzip.so" + +type + TZZipError* = int32 # Name conflict if we drop the `T` + +const + ZZIP_ERROR* = -4096'i32 + ZZIP_NO_ERROR* = 0'i32 # no error, may be used if user sets it. + ZZIP_OUTOFMEM* = ZZIP_ERROR - 20'i32 # out of memory + ZZIP_DIR_OPEN* = ZZIP_ERROR - 21'i32 # failed to open zipfile, see errno for details + ZZIP_DIR_STAT* = ZZIP_ERROR - 22'i32 # failed to fstat zipfile, see errno for details + ZZIP_DIR_SEEK* = ZZIP_ERROR - 23'i32 # failed to lseek zipfile, see errno for details + ZZIP_DIR_READ* = ZZIP_ERROR - 24'i32 # failed to read zipfile, see errno for details + ZZIP_DIR_TOO_SHORT* = ZZIP_ERROR - 25'i32 + ZZIP_DIR_EDH_MISSING* = ZZIP_ERROR - 26'i32 + ZZIP_DIRSIZE* = ZZIP_ERROR - 27'i32 + ZZIP_ENOENT* = ZZIP_ERROR - 28'i32 + ZZIP_UNSUPP_COMPR* = ZZIP_ERROR - 29'i32 + ZZIP_CORRUPTED* = ZZIP_ERROR - 31'i32 + ZZIP_UNDEF* = ZZIP_ERROR - 32'i32 + ZZIP_DIR_LARGEFILE* = ZZIP_ERROR - 33'i32 + + ZZIP_CASELESS* = 1'i32 shl 12'i32 + ZZIP_NOPATHS* = 1'i32 shl 13'i32 + ZZIP_PREFERZIP* = 1'i32 shl 14'i32 + ZZIP_ONLYZIP* = 1'i32 shl 16'i32 + ZZIP_FACTORY* = 1'i32 shl 17'i32 + ZZIP_ALLOWREAL* = 1'i32 shl 18'i32 + ZZIP_THREADED* = 1'i32 shl 19'i32 + +type + ZZipDir* {.final, pure.} = object + ZZipFile* {.final, pure.} = object + ZZipPluginIO* {.final, pure.} = object + + ZZipDirent* {.final, pure.} = object + d_compr*: int32 ## compression method + d_csize*: int32 ## compressed size + st_size*: int32 ## file size / decompressed size + d_name*: cstring ## file name / strdupped name + + ZZipStat* = ZZipDirent +{.deprecated: [TZZipDir: ZzipDir, TZZipFile: ZzipFile, + TZZipPluginIO: ZzipPluginIO, TZZipDirent: ZzipDirent, + TZZipStat: ZZipStat].} + +proc zzip_strerror*(errcode: int32): cstring {.cdecl, dynlib: dllname, + importc: "zzip_strerror".} +proc zzip_strerror_of*(dir: ptr ZZipDir): cstring {.cdecl, dynlib: dllname, + importc: "zzip_strerror_of".} +proc zzip_errno*(errcode: int32): int32 {.cdecl, dynlib: dllname, + importc: "zzip_errno".} + +proc zzip_geterror*(dir: ptr ZZipDir): int32 {.cdecl, dynlib: dllname, + importc: "zzip_error".} +proc zzip_seterror*(dir: ptr ZZipDir, errcode: int32) {.cdecl, dynlib: dllname, + importc: "zzip_seterror".} +proc zzip_compr_str*(compr: int32): cstring {.cdecl, dynlib: dllname, + importc: "zzip_compr_str".} +proc zzip_dirhandle*(fp: ptr ZZipFile): ptr ZZipDir {.cdecl, dynlib: dllname, + importc: "zzip_dirhandle".} +proc zzip_dirfd*(dir: ptr ZZipDir): int32 {.cdecl, dynlib: dllname, + importc: "zzip_dirfd".} +proc zzip_dir_real*(dir: ptr ZZipDir): int32 {.cdecl, dynlib: dllname, + importc: "zzip_dir_real".} +proc zzip_file_real*(fp: ptr ZZipFile): int32 {.cdecl, dynlib: dllname, + importc: "zzip_file_real".} +proc zzip_realdir*(dir: ptr ZZipDir): pointer {.cdecl, dynlib: dllname, + importc: "zzip_realdir".} +proc zzip_realfd*(fp: ptr ZZipFile): int32 {.cdecl, dynlib: dllname, + importc: "zzip_realfd".} + +proc zzip_dir_alloc*(fileext: cstringArray): ptr ZZipDir {.cdecl, + dynlib: dllname, importc: "zzip_dir_alloc".} +proc zzip_dir_free*(para1: ptr ZZipDir): int32 {.cdecl, dynlib: dllname, + importc: "zzip_dir_free".} + +proc zzip_dir_fdopen*(fd: int32, errcode_p: ptr TZZipError): ptr ZZipDir {.cdecl, + dynlib: dllname, importc: "zzip_dir_fdopen".} +proc zzip_dir_open*(filename: cstring, errcode_p: ptr TZZipError): ptr ZZipDir {. + cdecl, dynlib: dllname, importc: "zzip_dir_open".} +proc zzip_dir_close*(dir: ptr ZZipDir) {.cdecl, dynlib: dllname, + importc: "zzip_dir_close".} +proc zzip_dir_read*(dir: ptr ZZipDir, dirent: ptr ZZipDirent): int32 {.cdecl, + dynlib: dllname, importc: "zzip_dir_read".} + +proc zzip_opendir*(filename: cstring): ptr ZZipDir {.cdecl, dynlib: dllname, + importc: "zzip_opendir".} +proc zzip_closedir*(dir: ptr ZZipDir) {.cdecl, dynlib: dllname, + importc: "zzip_closedir".} +proc zzip_readdir*(dir: ptr ZZipDir): ptr ZZipDirent {.cdecl, dynlib: dllname, + importc: "zzip_readdir".} +proc zzip_rewinddir*(dir: ptr ZZipDir) {.cdecl, dynlib: dllname, + importc: "zzip_rewinddir".} +proc zzip_telldir*(dir: ptr ZZipDir): int {.cdecl, dynlib: dllname, + importc: "zzip_telldir".} +proc zzip_seekdir*(dir: ptr ZZipDir, offset: int) {.cdecl, dynlib: dllname, + importc: "zzip_seekdir".} + +proc zzip_file_open*(dir: ptr ZZipDir, name: cstring, flags: int32): ptr ZZipFile {. + cdecl, dynlib: dllname, importc: "zzip_file_open".} +proc zzip_file_close*(fp: ptr ZZipFile) {.cdecl, dynlib: dllname, + importc: "zzip_file_close".} +proc zzip_file_read*(fp: ptr ZZipFile, buf: pointer, length: int): int {. + cdecl, dynlib: dllname, importc: "zzip_file_read".} +proc zzip_open*(name: cstring, flags: int32): ptr ZZipFile {.cdecl, + dynlib: dllname, importc: "zzip_open".} +proc zzip_close*(fp: ptr ZZipFile) {.cdecl, dynlib: dllname, + importc: "zzip_close".} +proc zzip_read*(fp: ptr ZZipFile, buf: pointer, length: int): int {. + cdecl, dynlib: dllname, importc: "zzip_read".} + +proc zzip_freopen*(name: cstring, mode: cstring, para3: ptr ZZipFile): ptr ZZipFile {. + cdecl, dynlib: dllname, importc: "zzip_freopen".} +proc zzip_fopen*(name: cstring, mode: cstring): ptr ZZipFile {.cdecl, + dynlib: dllname, importc: "zzip_fopen".} +proc zzip_fread*(p: pointer, size: int, nmemb: int, + file: ptr ZZipFile): int {.cdecl, dynlib: dllname, + importc: "zzip_fread".} +proc zzip_fclose*(fp: ptr ZZipFile) {.cdecl, dynlib: dllname, + importc: "zzip_fclose".} + +proc zzip_rewind*(fp: ptr ZZipFile): int32 {.cdecl, dynlib: dllname, + importc: "zzip_rewind".} +proc zzip_seek*(fp: ptr ZZipFile, offset: int, whence: int32): int {. + cdecl, dynlib: dllname, importc: "zzip_seek".} +proc zzip_tell*(fp: ptr ZZipFile): int {.cdecl, dynlib: dllname, + importc: "zzip_tell".} + +proc zzip_dir_stat*(dir: ptr ZZipDir, name: cstring, zs: ptr ZZipStat, + flags: int32): int32 {.cdecl, dynlib: dllname, + importc: "zzip_dir_stat".} +proc zzip_file_stat*(fp: ptr ZZipFile, zs: ptr ZZipStat): int32 {.cdecl, + dynlib: dllname, importc: "zzip_file_stat".} +proc zzip_fstat*(fp: ptr ZZipFile, zs: ptr ZZipStat): int32 {.cdecl, dynlib: dllname, + importc: "zzip_fstat".} + +proc zzip_open_shared_io*(stream: ptr ZZipFile, name: cstring, + o_flags: int32, o_modes: int32, ext: cstringArray, + io: ptr ZZipPluginIO): ptr ZZipFile {.cdecl, + dynlib: dllname, importc: "zzip_open_shared_io".} +proc zzip_open_ext_io*(name: cstring, o_flags: int32, o_modes: int32, + ext: cstringArray, io: ptr ZZipPluginIO): ptr ZZipFile {. + cdecl, dynlib: dllname, importc: "zzip_open_ext_io".} +proc zzip_opendir_ext_io*(name: cstring, o_modes: int32, + ext: cstringArray, io: ptr ZZipPluginIO): ptr ZZipDir {. + cdecl, dynlib: dllname, importc: "zzip_opendir_ext_io".} +proc zzip_dir_open_ext_io*(filename: cstring, errcode_p: ptr TZZipError, + ext: cstringArray, io: ptr ZZipPluginIO): ptr ZZipDir {. + cdecl, dynlib: dllname, importc: "zzip_dir_open_ext_io".} |