├── tests ├── files │ ├── .gitignore │ ├── тест.xlsx │ ├── gzipfiletest.txt.gz │ └── gzipfiletest.txt ├── .gitignore ├── ziptests.nim ├── gziptests.nim └── zlibtests.nim ├── .gitignore ├── zip.nimble ├── LICENSE ├── README.md └── zip ├── gzipfiles.nim ├── zzip.nim ├── zipfiles.nim ├── libzip.nim ├── zlib.nim └── private └── libzip_all.c /tests/files/.gitignore: -------------------------------------------------------------------------------- 1 | td 2 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | nimcache 2 | ziptests 3 | -------------------------------------------------------------------------------- /tests/files/тест.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nim-lang/zip/HEAD/tests/files/тест.xlsx -------------------------------------------------------------------------------- /tests/files/gzipfiletest.txt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nim-lang/zip/HEAD/tests/files/gzipfiletest.txt.gz -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nimcache/ 2 | /tests/files/gzipfiletest.data.gz 3 | /tests/files/gzipfiletest.data2.gz 4 | /tests/gziptests 5 | /tests/zlibtests 6 | -------------------------------------------------------------------------------- /zip.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "0.3.1" 4 | author = "Anonymous" 5 | description = "Wrapper for the zip library" 6 | license = "MIT" 7 | 8 | skipDirs = @["tests"] 9 | 10 | # Dependencies 11 | 12 | requires "nim >= 0.10.0" 13 | 14 | task tests, "Run lib tests": 15 | withDir "tests": 16 | exec "nim c -r ziptests" 17 | exec "nim c -r zlibtests" 18 | exec "nim c -r gziptests" 19 | 20 | when defined(nimdistros) and not defined(useLibzipSrc): 21 | import distros 22 | if detectOs(MacOSX): 23 | foreignDep "libzip" 24 | else: 25 | foreignDep "libzip" 26 | -------------------------------------------------------------------------------- /tests/files/gzipfiletest.txt: -------------------------------------------------------------------------------- 1 | The quick brown fox jumps over the lazy dog 2 | Portez ce vieux whisky au juge blond qui fume 3 | Съешь ещё этих мягких французских булок, да выпей чаю 4 | The quick brown fox jumps over the lazy dog 5 | Portez ce vieux whisky au juge blond qui fume 6 | Съешь ещё этих мягких французских булок, да выпей чаю 7 | The quick brown fox jumps over the lazy dog 8 | Portez ce vieux whisky au juge blond qui fume 9 | Съешь ещё этих мягких французских булок, да выпей чаю 10 | The quick brown fox jumps over the lazy dog 11 | Portez ce vieux whisky au juge blond qui fume 12 | Съешь ещё этих мягких французских булок, да выпей чаю 13 | Съешь ещё этих мягких французских булок, да выпей чаю 14 | The quick brown fox jumps over the lazy dog 15 | Portez ce vieux whisky au juge blond qui fume 16 | Съешь ещё этих мягких французских булок, да выпей чаю 17 | Съешь ещё этих мягких французских булок, да выпей чаю 18 | The quick brown fox jumps over the lazy dog 19 | Portez ce vieux whisky au juge blond qui fume 20 | Съешь ещё этих мягких французских булок, да выпей чаю 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /tests/ziptests.nim: -------------------------------------------------------------------------------- 1 | import os, osproc, streams, unittest, strutils, ../zip/zipfiles 2 | 3 | const path = splitPath(currentSourcePath()).head & "/../zip/zipfiles" 4 | 5 | test "can compile zipfiles": 6 | check execCmdEx("nim -o:./nimcache/zipfiles --nimcache:./nimcache c " & 7 | path).exitCode == QuitSuccess 8 | 9 | test "zipfiles extractAll": 10 | var filename = "files/тест.xlsx" 11 | var z: ZipArchive 12 | if not z.open(filename): 13 | echo "Opening zip failed" 14 | quit(1) 15 | z.extractAll("files/td") 16 | z.close() 17 | check existsDir("files/td/xl/worksheets") 18 | check existsFile("files/td/xl/worksheets/sheet1.xml") 19 | 20 | test "zipfiles read and write using Stream": 21 | let filename = getTempDir() / "zipfiles_test_archive.zip" 22 | defer: filename.removeFile 23 | 24 | var z: ZipArchive 25 | require z.open(filename, fmWrite) 26 | z.addFile("foo.bar", newStringStream("content")) 27 | z.close 28 | 29 | require filename.existsFile 30 | 31 | require z.open(filename, fmRead) 32 | let outStream = newStringStream("") 33 | z.extractFile("foo.bar", outStream) 34 | z.close() 35 | 36 | check: outStream.data == "content" 37 | 38 | test "zipfiles read and write archive comment": 39 | let filename = getTempDir() / "zipfiles_test_archive.zip" 40 | defer: filename.removeFile 41 | 42 | var z: ZipArchive 43 | require z.open(filename, fmWrite) 44 | 45 | z.setArchiveComment("TEST123123") 46 | doAssert z.getArchiveComment() == "TEST123123" 47 | 48 | expect IOError: z.setArchiveComment('x'.repeat(65535 + 1)) 49 | 50 | z.close() 51 | -------------------------------------------------------------------------------- /tests/gziptests.nim: -------------------------------------------------------------------------------- 1 | import ../zip/gzipfiles 2 | 3 | proc readAllAndClose(f: Stream): string = 4 | shallowCopy result, f.readAll() 5 | f.close() 6 | 7 | proc main() = 8 | # reference text data 9 | let text = newFileStream("files/gzipfiletest.txt").readAllAndClose() 10 | # reference GZIP archive (made with GNU gzip on linux x64) 11 | let arch_gz = newGzFileStream("files/gzipfiletest.txt.gz").readAllAndClose() 12 | 13 | doAssert(arch_gz == text) 14 | 15 | # write data to a new archive. 16 | block: 17 | let w = newGzFileStream("files/gzipfiletest.data.gz", fmWrite) 18 | let chunk_size = 32 19 | var num_bytes = text.len 20 | var idx = 0 21 | while true: 22 | w.writeData(text[idx].unsafeAddr, min(num_bytes, chunk_size)) 23 | if num_bytes < chunk_size: 24 | break 25 | dec(num_bytes, chunk_size) 26 | inc(idx, chunk_size) 27 | w.close() 28 | 29 | # readall from new archive & check that data is corrupted. 30 | let new_data = newGzFileStream("files/gzipfiletest.data.gz").readAllAndClose() 31 | doAssert(new_data == text) 32 | 33 | # read from archive and write to new archive. 34 | block: 35 | let s = newGzFileStream("files/gzipfiletest.data.gz") 36 | let w = newGzFileStream("files/gzipfiletest.data2.gz", fmWrite) 37 | var buffer: array[32, uint8] # chunk_size 38 | while true: 39 | let bytes = s.readData(buffer[0].addr, buffer.len) 40 | # do something 41 | w.writeData(buffer[0].addr, bytes) 42 | if bytes < buffer.len: 43 | break 44 | s.close() 45 | w.close() 46 | 47 | # read line by line confirming that behavior of atEnd is consistent with standard FileStream 48 | block: 49 | let fs = newFileStream("files/gzipfiletest.txt") 50 | let gzfs = newGzFileStream("files/gzipfiletest.txt.gz") 51 | 52 | var fs_lines = 0 53 | while not fs.atEnd(): 54 | discard fs.readLine() 55 | inc(fs_lines) 56 | 57 | var gzfs_lines = 0 58 | while not gzfs.atEnd(): 59 | discard gzfs.readLine() 60 | inc(gzfs_lines) 61 | 62 | doAssert(fs_lines == gzfs_lines) 63 | 64 | fs.close() 65 | gzfs.close() 66 | 67 | main() 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zip 2 | Wrapper for the zip library 3 | 4 | ## Usage 5 | zip 6 | 7 | ``` Nim 8 | import zip/zipfiles 9 | # Opens a zip file for reading, writing or appending. 10 | var z: ZipArchive 11 | if not z.open(filename): 12 | echo "Opening zip failed" 13 | quit(1) 14 | 15 | # extracts all files from archive z to the destination directory. 16 | z.extractAll("files/td") 17 | ``` 18 | read and write using Stream 19 | 20 | ``` Nim 21 | import zip/zipfiles 22 | import streams 23 | var z: ZipArchive 24 | # add new file 25 | z.open(filename, fmWrite) 26 | z.addFile("foo.bar", newStringStream("content")) 27 | 28 | # read file to string stream 29 | z.open(filename, fmRead) 30 | let outStream = newStringStream("") 31 | z.extractFile("foo.bar", outStream) 32 | ``` 33 | load archive from memory 34 | 35 | ``` Nim 36 | var z: ZipArchive 37 | z.fromBuffer(archiveData) 38 | ``` 39 | 40 | zlib 41 | ``` Nim 42 | import zip/zlib 43 | uncompress(compress(text, stream=RAW_DEFLATE), stream=RAW_DEFLATE) 44 | uncompress(compress(text, stream=ZLIB_STREAM), stream=ZLIB_STREAM) 45 | uncompress(compress(text, stream=GZIP_STREAM), stream=GZIP_STREAM) 46 | uncompress(compress(text, stream=ZLIB_STREAM), stream=DETECT_STREAM) 47 | uncompress(compress(text, stream=GZIP_STREAM), stream=DETECT_STREAM) 48 | compress(text, stream=RAW_DEFLATE) 49 | compress(text, stream=GZIP_STREAM) 50 | compress(text, stream=ZLIB_STREAM) 51 | ``` 52 | 53 | gzip 54 | ``` Nim 55 | import zip/gzipfiles 56 | # read text data 57 | let arch_gz = newGzFileStream("files/gzipfiletest.txt.gz").readAllAndClose() 58 | 59 | ``` 60 | 61 | read from archive and write to new archive. 62 | 63 | ``` Nim 64 | let w = newGzFileStream("files/gzipfiletest.data.gz", fmWrite) 65 | let chunk_size = 32 66 | var num_bytes = text.len 67 | var idx = 0 68 | while true: 69 | w.writeData(text[idx].unsafeAddr, min(num_bytes, chunk_size)) 70 | if num_bytes < chunk_size: 71 | break 72 | dec(num_bytes, chunk_size) 73 | inc(idx, chunk_size) 74 | w.close() 75 | ``` 76 | 77 | read line by line confirming that behavior of atEnd is consistent with standard FileStream 78 | 79 | ``` Nim 80 | let gzfs = newGzFileStream("files/gzipfiletest.txt.gz") 81 | while not gzfs.atEnd(): 82 | discard gzfs.readLine() 83 | ``` 84 | -------------------------------------------------------------------------------- /zip/gzipfiles.nim: -------------------------------------------------------------------------------- 1 | import os 2 | import zlib 3 | import streams 4 | export streams 5 | 6 | ## This module implements a gzipfile stream for reading, writing, appending. 7 | 8 | type 9 | GzFileStream* = ref object of Stream 10 | mode: FileMode 11 | f: GzFile 12 | 13 | const SEEK_SET = 0.int32 # Seek from beginning of file. 14 | 15 | proc fsClose(s: Stream) = 16 | if not GzFileStream(s).f.isNil: 17 | discard gzclose(GzFileStream(s).f) 18 | GzFileStream(s).f = nil 19 | 20 | proc fsFlush(s: Stream) = 21 | # compiler flushFile also discard c_fflush 22 | discard gzflush(GzFileStream(s).f, Z_FINISH) 23 | 24 | proc fsAtEnd(s: Stream): bool = 25 | let c = gzgetc(GzFileStream(s).f) 26 | discard gzungetc(c, GzFileStream(s).f) 27 | result = c < 0'i32 28 | 29 | proc fsSetPosition(s: Stream, pos: int) = 30 | if gzseek(GzFileStream(s).f, pos.ZOffT, SEEK_SET) == -1: 31 | if GzFileStream(s).mode in {fmWrite, fmAppend}: 32 | raise newException(IOError, "error in gzip stream while seeking! (file is in write/append mode!") 33 | else: 34 | raise newException(IOError, "error in gzip stream while seeking!") 35 | 36 | proc fsGetPosition(s: Stream): int = 37 | result = gztell(GzFileStream(s).f).int 38 | 39 | proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = 40 | result = gzread(GzFileStream(s).f, buffer, bufLen.cuint).int 41 | if result == -1: 42 | if GzFileStream(s).mode in {fmWrite, fmAppend}: 43 | raise newException(IOError, "cannot read data from write-only gzip stream!") 44 | else: 45 | raise newException(IOError, "cannot read from stream!") 46 | 47 | proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int = 48 | let gz = GzFileStream(s) 49 | if gz.mode in {fmWrite, fmAppend}: 50 | raise newException(IOError, "cannot peek data from write-only gzip stream!") 51 | let pos = int(gztell(gz.f)) 52 | result = fsReadData(s, buffer, bufLen) 53 | fsSetPosition(s, pos) 54 | 55 | proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) = 56 | if gzwrite(GzFileStream(s).f, buffer, bufLen.cuint).int != bufLen: 57 | if GzFileStream(s).mode in {fmWrite, fmAppend}: 58 | raise newException(IOError, "cannot write data to gzip stream!") 59 | else: 60 | raise newException(IOError, "cannot write data to read-only gzip stream!") 61 | 62 | 63 | proc newGzFileStream*(filename: string; mode=fmRead; level=Z_DEFAULT_COMPRESSION): GzFileStream = 64 | ## Opens a Gzipfile as a file stream. `mode` can be 65 | ## ``fmRead``, ``fmWrite`` or ``fmAppend``. 66 | ## 67 | ## Compression level can be set with ``level`` argument. Currently 68 | ## ``Z_DEFAULT_COMPRESSION`` is 6. 69 | ## 70 | ## Note: ``level`` is ignored if ``mode`` is `fmRead` 71 | ## 72 | ## Note: There is only partial support for file seeking 73 | ## - in fmRead mode, seeking randomly inside the gzip 74 | ## file will lead to poor performance. 75 | ## - in fmWrite, fmAppend mode, only forward seeking 76 | ## is supported. 77 | new(result) 78 | case mode 79 | of fmRead: result.f = gzopen(filename, "rb") 80 | of fmWrite: result.f = gzopen(filename, "wb") 81 | of fmAppend: result.f = gzopen(filename, "ab") 82 | else: raise newException(IOError, "unsupported file mode '" & $mode & 83 | "' for GzFileStream!") 84 | if result.f.isNil: 85 | let err = osLastError() 86 | if err != OSErrorCode(0'i32): 87 | raiseOSError(err) 88 | if mode in {fmWrite, fmAppend}: 89 | discard gzsetparams(result.f, level.int32, Z_DEFAULT_STRATEGY.int32) 90 | 91 | result.mode = mode 92 | result.closeImpl = fsClose 93 | result.atEndImpl = fsAtEnd 94 | result.setPositionImpl = fsSetPosition 95 | result.getPositionImpl = fsGetPosition 96 | result.readDataImpl = fsReadData 97 | result.peekDataImpl = fsPeekData 98 | result.writeDataImpl = fsWriteData 99 | result.flushImpl = fsFlush 100 | -------------------------------------------------------------------------------- /tests/zlibtests.nim: -------------------------------------------------------------------------------- 1 | import unittest 2 | import ../zip/zlib 3 | from strutils import repeat 4 | 5 | test "test stream compression": 6 | # pangramms 7 | let text = "The quick brown fox jumps over the lazy dog" 8 | let text2 = "Portez ce vieux whisky au juge blond qui fume" 9 | let text3 = "Съешь ещё этих мягких французских булок, да выпей чаю" 10 | # generated from text with python3.6 zlib module 11 | # import zlib # GZIP | ZLIB | RAW 12 | # z = zlib.compressobj(wbits=WBITS) # WBITS = (16+15 | 15 | -15 ) 13 | # print repr(z.compress(text)+z.flush()) 14 | let raw_deflate = "\x0b\xc9HU(,\xcdL\xceVH*\xca/\xcfSH\xcb\xafP\xc8*\xcd-(V\xc8/K-R(\x01J\xe7$VU*\xa4\xe4\xa7\x03\x00" 15 | let gzip_deflate = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x0b\xc9HU(,\xcdL\xceVH*\xca/\xcfSH\xcb\xafP\xc8*\xcd-(V\xc8/K-R(\x01J\xe7$VU*\xa4\xe4\xa7\x03\x009\xa3OA+\x00\x00\x00" 16 | let zlib_deflate = "x\x9c\x0b\xc9HU(,\xcdL\xceVH*\xca/\xcfSH\xcb\xafP\xc8*\xcd-(V\xc8/K-R(\x01J\xe7$VU*\xa4\xe4\xa7\x03\x00[\xdc\x0f\xda" 17 | 18 | # zlib stream of text2. 19 | let zlib_deflate2 = "x\x9c\x0b\xc8/*I\xadRHNU(\xcbL-\xadP(\xcf\xc8,\xce\xaeTH,U\xc8*MOUH\xca\xc9\xcfKQ(,\xcdTH+\xcdM\x05\x00\x81!\x10\xa9" 20 | 21 | # zlib stream of text3. (encoded with UTF-8) 22 | let zlib_deflate3 = "x\x9c-\xc8\xeb\x11CP\x18\x06\xe1V\xbe\x02Rd\xc4\x9d`\x94\xa0\x83\xe3r&\x08\xd2\xc2\xbe\x1d1&\xbfv\x9e\xa5S\x81W\xa6\xb7]\xc9\xd5\x9a*\xbd\x98\x15\x1b\x9b\x1aF\xd6\x1b\x8a\xf4\xc4\xb1+Q\xc8G\xc1\x7f\xd3_\xfcr\xb0>\x8c\tg\x0c*\xf9\xe1YL)N\xf5\t_\x12@\xa8" 23 | 24 | # generated from empty string 25 | let raw_deflate_empty="\x03\x00" 26 | let gzip_deflate_empty="\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00" 27 | let zlib_deflate_empty="x\x9c\x03\x00\x00\x00\x00\x01" 28 | 29 | check uncompress(compress(text)) == text 30 | check uncompress(compress(text, stream=RAW_DEFLATE), stream=RAW_DEFLATE) == text 31 | check uncompress(compress(text, stream=ZLIB_STREAM), stream=ZLIB_STREAM) == text 32 | check uncompress(compress(text, stream=GZIP_STREAM), stream=GZIP_STREAM) == text 33 | check uncompress(compress(text, stream=ZLIB_STREAM), stream=DETECT_STREAM) == text 34 | check uncompress(compress(text, stream=GZIP_STREAM), stream=DETECT_STREAM) == text 35 | check compress(text, stream=RAW_DEFLATE) == raw_deflate 36 | check compress(text, stream=GZIP_STREAM) == gzip_deflate 37 | check compress(text, stream=ZLIB_STREAM) == zlib_deflate 38 | 39 | # check support for concatenated gzip & zlib streams 40 | check uncompress(gzip_deflate.repeat(5)) == text.repeat(5) 41 | check uncompress(zlib_deflate.repeat(5)) == text.repeat(5) 42 | check uncompress(zlib_deflate & zlib_deflate2 & zlib_deflate3) == text & text2 & text3 43 | 44 | # generated from array of 160000 zero bytes with 100 random bytes 45 | let encoded_data = "x\x9c\xed\xdc?\xa8Nq\x1c\xc7\xf1\xbb\xc8\x9f\xe8\x96L\xca\xcc@J,\xfed\xf1\xa7,&J\x06)\x9b2*d0P\xb7d\xb0\x1aE\xb2(\xd9L\xbaw\xd0\x9d\xc4b\xb8\x19\xc4\xa0\x1b\x06I\x922(u\xf3\xdc\xfb<\xcf}\x9es>\xe7\xf7\xfc^\xaf\xf1W\xe7\xf7}O\xa7\xdf\xa9s\xce\xd4\x140\xbc\xe9t\x00\x00\x00@7}\x0b\xcf?\x1e\x9e\xcf\xea\xf5}\xd4^\xdfF\x05\xd4\xe4e\xcf\xd5\x1d-W\x00P\x80\x8d\xbd\x16\xd7\xb6]\x01\x14\xe9~:\x00\x00\x00\xba\xe5t:\x00\xdaq5\x1d\x00\x00\x0c\xecW:\x00\xa8\xd2\xc9t\xc0\xc8>\x9fI\x174\xe5b:\x00\x00\x00\x00\x00\x18\xc1\\:\xa0a\xfb\xd2\x01\x00\x00\xd0\xcf\x9at@\xa9\x0e\xad\xee\xb27\xe3\xad\x00\x00\x00\x00\x00\x00\xa0Vo\xd3\x01\x00@=\x1e\xa7\x03\x00\x00\x00\x00\x00&\xd5L:\xa0\x97\xcd\xe9\x00\x80\xce8\x95\x0e\x00\x80\x1a\xcd\xa6\x03\x00\x00\x00\xe8\xac\xa3\xe9\x00\x00\x00\x80%^\xa5\x03\x00\x00\x00\x80\xa4\xd7\xe9\x00\x00\x80\x95\xfdH\x07\x00@U\x9e\xa5\x03\x00\x00\x8a\xb3\x98\x0eX\xeaw:\x00\xa0\xe3\x1e\xa5\x03\xa0C\x16Bs?\x84\xe6\x02\x00t\xcf|:\xa0E\x17\xd2\x01\x00\x00\x00\x00\x00\xd4\xe0S:\x00\x00\x00\x80\xc9\xf5 \x1d\x00\x00\x00ex2\xf2\x0e;\xc7P\x01\x00\xc0\xa8\x0e\xa6\x03\x00\xe8\xb2\xeb\xe9\x00\xfa:\x91\x0e\x00\x96s;\x1d@=\xae\xa5\x03\xfes+\x1d\x00\x00\x00@\xd3\xf6\xa7\x03\x00`%\x0f\xd3\x01\x00\x00P\xb2/\xe9\x00\x00\xf8\xebf:\x00\xba\xe0R:\x00\x80\xa1-\xf6X{\xdez\x05\x00\xb4\xc4O\xe4\xa0.\xef\xd2\x01\x00\x00\x00\xb0=\x1d@\xde\xe1t\x00\xe3\xb5)\x1d\x00\x14\xaa\xd7\xdb\x19P\xb3c\xe9\x00\x00rn\xa4\x03\x00\x80&mM\x07\x00\x00\x00\xfcs>\x1d\x00\x00\x00\x00Tn:\x1d\x90\xb4%\x1d@\x95^\xa4\x03\x80\xa6\x1c\x18\xfb\x8eO\xc7\xbe#\xb4l.\x1d@\x87\x9cK\x07\x94\xe3g:\x00\x80I\xf1>\x1d\x00\x00\xc0`\xce\xa6\x03\x00\xa0xw\xd2\x01\x00\x00\x00\x000\x8c+\xe9\x00\xa0\\\x1b\xd2\x01\x00\x00\x00\x00\x0clO:\x00\x00\xc6l6\x1d\x00\x00t\xd3L:\x00\x00\xa0y\x1f\xd3\x01\x00P\x96\xaf\xe9\x00\x00` 14 | # Tomi Ollila 15 | # Copyright (c) 1999,2000,2001,2002,2003,2004 Guido Draheim 16 | # All rights reserved, 17 | # usage allowed under the restrictions of the 18 | # Lesser GNU General Public License 19 | # or alternatively the restrictions 20 | # of the Mozilla Public License 1.1 21 | 22 | when defined(windows): 23 | const 24 | dllname = "zzip.dll" 25 | else: 26 | const 27 | dllname = "libzzip.so" 28 | 29 | type 30 | TZZipError* = int32 # Name conflict if we drop the `T` 31 | 32 | const 33 | ZZIP_ERROR* = -4096'i32 34 | ZZIP_NO_ERROR* = 0'i32 # no error, may be used if user sets it. 35 | ZZIP_OUTOFMEM* = ZZIP_ERROR - 20'i32 # out of memory 36 | ZZIP_DIR_OPEN* = ZZIP_ERROR - 21'i32 # failed to open zipfile, see errno for details 37 | ZZIP_DIR_STAT* = ZZIP_ERROR - 22'i32 # failed to fstat zipfile, see errno for details 38 | ZZIP_DIR_SEEK* = ZZIP_ERROR - 23'i32 # failed to lseek zipfile, see errno for details 39 | ZZIP_DIR_READ* = ZZIP_ERROR - 24'i32 # failed to read zipfile, see errno for details 40 | ZZIP_DIR_TOO_SHORT* = ZZIP_ERROR - 25'i32 41 | ZZIP_DIR_EDH_MISSING* = ZZIP_ERROR - 26'i32 42 | ZZIP_DIRSIZE* = ZZIP_ERROR - 27'i32 43 | ZZIP_ENOENT* = ZZIP_ERROR - 28'i32 44 | ZZIP_UNSUPP_COMPR* = ZZIP_ERROR - 29'i32 45 | ZZIP_CORRUPTED* = ZZIP_ERROR - 31'i32 46 | ZZIP_UNDEF* = ZZIP_ERROR - 32'i32 47 | ZZIP_DIR_LARGEFILE* = ZZIP_ERROR - 33'i32 48 | 49 | ZZIP_CASELESS* = 1'i32 shl 12'i32 50 | ZZIP_NOPATHS* = 1'i32 shl 13'i32 51 | ZZIP_PREFERZIP* = 1'i32 shl 14'i32 52 | ZZIP_ONLYZIP* = 1'i32 shl 16'i32 53 | ZZIP_FACTORY* = 1'i32 shl 17'i32 54 | ZZIP_ALLOWREAL* = 1'i32 shl 18'i32 55 | ZZIP_THREADED* = 1'i32 shl 19'i32 56 | 57 | type 58 | ZZipDir* {.final, pure.} = object 59 | ZZipFile* {.final, pure.} = object 60 | ZZipPluginIO* {.final, pure.} = object 61 | 62 | ZZipDirent* {.final, pure.} = object 63 | d_compr*: int32 ## compression method 64 | d_csize*: int32 ## compressed size 65 | st_size*: int32 ## file size / decompressed size 66 | d_name*: cstring ## file name / strdupped name 67 | 68 | ZZipStat* = ZZipDirent 69 | {.deprecated: [TZZipDir: ZzipDir, TZZipFile: ZzipFile, 70 | TZZipPluginIO: ZzipPluginIO, TZZipDirent: ZzipDirent, 71 | TZZipStat: ZZipStat].} 72 | 73 | proc zzip_strerror*(errcode: int32): cstring {.cdecl, dynlib: dllname, 74 | importc: "zzip_strerror".} 75 | proc zzip_strerror_of*(dir: ptr ZZipDir): cstring {.cdecl, dynlib: dllname, 76 | importc: "zzip_strerror_of".} 77 | proc zzip_errno*(errcode: int32): int32 {.cdecl, dynlib: dllname, 78 | importc: "zzip_errno".} 79 | 80 | proc zzip_geterror*(dir: ptr ZZipDir): int32 {.cdecl, dynlib: dllname, 81 | importc: "zzip_error".} 82 | proc zzip_seterror*(dir: ptr ZZipDir, errcode: int32) {.cdecl, dynlib: dllname, 83 | importc: "zzip_seterror".} 84 | proc zzip_compr_str*(compr: int32): cstring {.cdecl, dynlib: dllname, 85 | importc: "zzip_compr_str".} 86 | proc zzip_dirhandle*(fp: ptr ZZipFile): ptr ZZipDir {.cdecl, dynlib: dllname, 87 | importc: "zzip_dirhandle".} 88 | proc zzip_dirfd*(dir: ptr ZZipDir): int32 {.cdecl, dynlib: dllname, 89 | importc: "zzip_dirfd".} 90 | proc zzip_dir_real*(dir: ptr ZZipDir): int32 {.cdecl, dynlib: dllname, 91 | importc: "zzip_dir_real".} 92 | proc zzip_file_real*(fp: ptr ZZipFile): int32 {.cdecl, dynlib: dllname, 93 | importc: "zzip_file_real".} 94 | proc zzip_realdir*(dir: ptr ZZipDir): pointer {.cdecl, dynlib: dllname, 95 | importc: "zzip_realdir".} 96 | proc zzip_realfd*(fp: ptr ZZipFile): int32 {.cdecl, dynlib: dllname, 97 | importc: "zzip_realfd".} 98 | 99 | proc zzip_dir_alloc*(fileext: cstringArray): ptr ZZipDir {.cdecl, 100 | dynlib: dllname, importc: "zzip_dir_alloc".} 101 | proc zzip_dir_free*(para1: ptr ZZipDir): int32 {.cdecl, dynlib: dllname, 102 | importc: "zzip_dir_free".} 103 | 104 | proc zzip_dir_fdopen*(fd: int32, errcode_p: ptr TZZipError): ptr ZZipDir {.cdecl, 105 | dynlib: dllname, importc: "zzip_dir_fdopen".} 106 | proc zzip_dir_open*(filename: cstring, errcode_p: ptr TZZipError): ptr ZZipDir {. 107 | cdecl, dynlib: dllname, importc: "zzip_dir_open".} 108 | proc zzip_dir_close*(dir: ptr ZZipDir) {.cdecl, dynlib: dllname, 109 | importc: "zzip_dir_close".} 110 | proc zzip_dir_read*(dir: ptr ZZipDir, dirent: ptr ZZipDirent): int32 {.cdecl, 111 | dynlib: dllname, importc: "zzip_dir_read".} 112 | 113 | proc zzip_opendir*(filename: cstring): ptr ZZipDir {.cdecl, dynlib: dllname, 114 | importc: "zzip_opendir".} 115 | proc zzip_closedir*(dir: ptr ZZipDir) {.cdecl, dynlib: dllname, 116 | importc: "zzip_closedir".} 117 | proc zzip_readdir*(dir: ptr ZZipDir): ptr ZZipDirent {.cdecl, dynlib: dllname, 118 | importc: "zzip_readdir".} 119 | proc zzip_rewinddir*(dir: ptr ZZipDir) {.cdecl, dynlib: dllname, 120 | importc: "zzip_rewinddir".} 121 | proc zzip_telldir*(dir: ptr ZZipDir): int {.cdecl, dynlib: dllname, 122 | importc: "zzip_telldir".} 123 | proc zzip_seekdir*(dir: ptr ZZipDir, offset: int) {.cdecl, dynlib: dllname, 124 | importc: "zzip_seekdir".} 125 | 126 | proc zzip_file_open*(dir: ptr ZZipDir, name: cstring, flags: int32): ptr ZZipFile {. 127 | cdecl, dynlib: dllname, importc: "zzip_file_open".} 128 | proc zzip_file_close*(fp: ptr ZZipFile) {.cdecl, dynlib: dllname, 129 | importc: "zzip_file_close".} 130 | proc zzip_file_read*(fp: ptr ZZipFile, buf: pointer, length: int): int {. 131 | cdecl, dynlib: dllname, importc: "zzip_file_read".} 132 | proc zzip_open*(name: cstring, flags: int32): ptr ZZipFile {.cdecl, 133 | dynlib: dllname, importc: "zzip_open".} 134 | proc zzip_close*(fp: ptr ZZipFile) {.cdecl, dynlib: dllname, 135 | importc: "zzip_close".} 136 | proc zzip_read*(fp: ptr ZZipFile, buf: pointer, length: int): int {. 137 | cdecl, dynlib: dllname, importc: "zzip_read".} 138 | 139 | proc zzip_freopen*(name: cstring, mode: cstring, para3: ptr ZZipFile): ptr ZZipFile {. 140 | cdecl, dynlib: dllname, importc: "zzip_freopen".} 141 | proc zzip_fopen*(name: cstring, mode: cstring): ptr ZZipFile {.cdecl, 142 | dynlib: dllname, importc: "zzip_fopen".} 143 | proc zzip_fread*(p: pointer, size: int, nmemb: int, 144 | file: ptr ZZipFile): int {.cdecl, dynlib: dllname, 145 | importc: "zzip_fread".} 146 | proc zzip_fclose*(fp: ptr ZZipFile) {.cdecl, dynlib: dllname, 147 | importc: "zzip_fclose".} 148 | 149 | proc zzip_rewind*(fp: ptr ZZipFile): int32 {.cdecl, dynlib: dllname, 150 | importc: "zzip_rewind".} 151 | proc zzip_seek*(fp: ptr ZZipFile, offset: int, whence: int32): int {. 152 | cdecl, dynlib: dllname, importc: "zzip_seek".} 153 | proc zzip_tell*(fp: ptr ZZipFile): int {.cdecl, dynlib: dllname, 154 | importc: "zzip_tell".} 155 | 156 | proc zzip_dir_stat*(dir: ptr ZZipDir, name: cstring, zs: ptr ZZipStat, 157 | flags: int32): int32 {.cdecl, dynlib: dllname, 158 | importc: "zzip_dir_stat".} 159 | proc zzip_file_stat*(fp: ptr ZZipFile, zs: ptr ZZipStat): int32 {.cdecl, 160 | dynlib: dllname, importc: "zzip_file_stat".} 161 | proc zzip_fstat*(fp: ptr ZZipFile, zs: ptr ZZipStat): int32 {.cdecl, dynlib: dllname, 162 | importc: "zzip_fstat".} 163 | 164 | proc zzip_open_shared_io*(stream: ptr ZZipFile, name: cstring, 165 | o_flags: int32, o_modes: int32, ext: cstringArray, 166 | io: ptr ZZipPluginIO): ptr ZZipFile {.cdecl, 167 | dynlib: dllname, importc: "zzip_open_shared_io".} 168 | proc zzip_open_ext_io*(name: cstring, o_flags: int32, o_modes: int32, 169 | ext: cstringArray, io: ptr ZZipPluginIO): ptr ZZipFile {. 170 | cdecl, dynlib: dllname, importc: "zzip_open_ext_io".} 171 | proc zzip_opendir_ext_io*(name: cstring, o_modes: int32, 172 | ext: cstringArray, io: ptr ZZipPluginIO): ptr ZZipDir {. 173 | cdecl, dynlib: dllname, importc: "zzip_opendir_ext_io".} 174 | proc zzip_dir_open_ext_io*(filename: cstring, errcode_p: ptr TZZipError, 175 | ext: cstringArray, io: ptr ZZipPluginIO): ptr ZZipDir {. 176 | cdecl, dynlib: dllname, importc: "zzip_dir_open_ext_io".} 177 | -------------------------------------------------------------------------------- /zip/zipfiles.nim: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | # Nim's Runtime Library 4 | # (c) Copyright 2012 Andreas Rumpf 5 | # 6 | # See the file "copying.txt", included in this 7 | # distribution, for details about the copyright. 8 | # 9 | 10 | ## This module implements a zip archive creator/reader/modifier. 11 | 12 | import std/[streams, times, os, strutils, paths] 13 | import libzip 14 | 15 | 16 | const BufSize = 8 * 1024 17 | 18 | type 19 | ZipArchive* = object of RootObj ## represents a zip archive 20 | mode: FileMode 21 | w: PZip 22 | {.deprecated: [TZipArchive: ZipArchive].} 23 | 24 | proc zipError(z: var ZipArchive) = 25 | var e: ref IOError 26 | new(e) 27 | e.msg = $zip_strerror(z.w) 28 | raise e 29 | 30 | proc open*(z: var ZipArchive, filename: string, mode: FileMode = fmRead): bool = 31 | ## Opens a zip file for reading, writing or appending. All file modes are 32 | ## supported. Returns true iff successful, false otherwise. 33 | var err, flags: int32 34 | case mode 35 | of fmRead, fmReadWriteExisting, fmAppend: flags = 0 36 | of fmWrite: 37 | if existsFile(filename): removeFile(filename) 38 | flags = ZIP_CREATE or ZIP_EXCL 39 | of fmReadWrite: flags = ZIP_CREATE 40 | z.w = zip_open(filename, flags, addr(err)) 41 | z.mode = mode 42 | result = z.w != nil 43 | 44 | proc close*(z: var ZipArchive) = 45 | ## Closes a zip file. 46 | zip_close(z.w) 47 | 48 | proc createDir*(z: var ZipArchive, dir: string) = 49 | ## Creates a directory within the `z` archive. This does not fail if the 50 | ## directory already exists. Note that for adding a file like 51 | ## ``"path1/path2/filename"`` it is not necessary 52 | ## to create the ``"path/path2"`` subdirectories - it will be done 53 | ## automatically by ``addFile``. 54 | assert(z.mode != fmRead) 55 | discard zip_add_dir(z.w, dir) 56 | zip_error_clear(z.w) 57 | 58 | proc addFile*(z: var ZipArchive, dest, src: string) = 59 | ## Adds the file `src` to the archive `z` with the name `dest`. `dest` 60 | ## may contain a path that will be created. 61 | assert(z.mode != fmRead) 62 | if not fileExists(src): 63 | raise newException(IOError, "File '" & src & "' does not exist") 64 | var zipsrc = zip_source_file(z.w, src, 0, -1) 65 | if zipsrc == nil: 66 | #echo("Dest: " & dest) 67 | #echo("Src: " & src) 68 | zipError(z) 69 | if zip_add(z.w, dest, zipsrc) < 0'i32: 70 | zip_source_free(zipsrc) 71 | zipError(z) 72 | 73 | proc addFile*(z: var ZipArchive, file: string) = 74 | ## A shortcut for ``addFile(z, file, file)``, i.e. the name of the source is 75 | ## the name of the destination. 76 | addFile(z, file, file) 77 | 78 | proc mySourceCallback(state, data: pointer, len: int, 79 | cmd: ZipSourceCmd): int {.cdecl.} = 80 | var src = cast[Stream](state) 81 | case cmd 82 | of ZIP_SOURCE_OPEN: 83 | if src.setPositionImpl != nil: setPosition(src, 0) # reset 84 | of ZIP_SOURCE_READ: 85 | result = readData(src, data, len) 86 | of ZIP_SOURCE_CLOSE: close(src) 87 | of ZIP_SOURCE_STAT: 88 | var stat = cast[PZipStat](data) 89 | zip_stat_init(stat) 90 | stat.size = high(int32)-1 # we don't know the size 91 | stat.mtime = getTime() 92 | result = sizeof(ZipStat) 93 | of ZIP_SOURCE_ERROR: 94 | var err = cast[ptr array[0..1, cint]](data) 95 | err[0] = ZIP_ER_INTERNAL 96 | err[1] = 0 97 | result = 2*sizeof(cint) 98 | of constZIP_SOURCE_FREE: GC_unref(src) 99 | of ZIP_SOURCE_SUPPORTS: 100 | # By default a read-only source is supported, which suits us. 101 | result = -1 102 | else: 103 | # An unknown command, failing 104 | result = -1 105 | 106 | proc addFile*(z: var ZipArchive, dest: string, src: Stream) = 107 | ## Adds a file named with `dest` to the archive `z`. `dest` 108 | ## may contain a path. The file's content is read from the `src` stream. 109 | assert(z.mode != fmRead) 110 | GC_ref(src) 111 | var zipsrc = zip_source_function(z.w, mySourceCallback, cast[pointer](src)) 112 | if zipsrc == nil: zipError(z) 113 | if zip_add(z.w, dest, zipsrc) < 0'i32: 114 | zip_source_free(zipsrc) 115 | zipError(z) 116 | 117 | proc getArchiveComment*(z: var ZipArchive): string = 118 | ## Reads the comment from the archive ``z``. 119 | ## Throws a IOError exception if the comment cannot be read. 120 | let comm = zip_get_archive_comment(z.w, nil, 0) 121 | if comm == nil: 122 | raise newException(IOError, "Could not read the archive comment") 123 | result = $comm 124 | 125 | proc setArchiveComment*(z: var ZipArchive, comm: string) = 126 | ## Sets the contents of the string ``comm`` as the archive ``z`` comment. 127 | assert(z.mode != fmRead) 128 | if comm.len > 65535: 129 | raise newException(IOError, "The comment string is too long (max 65535 bytes)") 130 | if zip_set_archive_comment(z.w, comm, int32(comm.len)) != 0: 131 | zipError(z) 132 | 133 | # -------------- zip file stream --------------------------------------------- 134 | 135 | type 136 | TZipFileStream = object of StreamObj 137 | f: PZipFile 138 | atEnd: bool 139 | 140 | PZipFileStream* = 141 | ref TZipFileStream ## a reader stream of a file within a zip archive 142 | 143 | proc fsClose(s: Stream) = zip_fclose(PZipFileStream(s).f) 144 | proc fsAtEnd(s: Stream): bool = PZipFileStream(s).atEnd 145 | proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = 146 | result = zip_fread(PZipFileStream(s).f, buffer, bufLen) 147 | if result == 0: 148 | PZipFileStream(s).atEnd = true 149 | 150 | proc newZipFileStream(f: PZipFile): PZipFileStream = 151 | new(result) 152 | result.f = f 153 | result.atEnd = false 154 | result.closeImpl = fsClose 155 | result.readDataImpl = fsReadData 156 | result.atEndImpl = fsAtEnd 157 | # other methods are nil! 158 | 159 | # ---------------------------------------------------------------------------- 160 | 161 | proc getStream*(z: var ZipArchive, filename: string): PZipFileStream = 162 | ## returns a stream that can be used to read the file named `filename` 163 | ## from the archive `z`. Returns nil in case of an error. 164 | ## The returned stream does not support the `setPosition`, `getPosition`, 165 | ## `writeData` or `atEnd` methods. 166 | var x = zip_fopen(z.w, filename, 0'i32) 167 | if x != nil: result = newZipFileStream(x) 168 | 169 | iterator walkFiles*(z: var ZipArchive): string = 170 | ## walks over all files in the archive `z` and returns the filename 171 | ## (including the path). 172 | var i = 0'i32 173 | var num = zip_get_num_files(z.w) 174 | while i < num: 175 | yield $zip_get_name(z.w, i, 0'i32) 176 | inc(i) 177 | 178 | proc extractFile*(z: var ZipArchive, srcFile: string, dest: Stream) = 179 | ## extracts a file from the zip archive `z` to the destination stream. 180 | var buf: array[BufSize, byte] 181 | var strm = getStream(z, srcFile) 182 | if strm.isNil: 183 | raise newException(IOError, "Failed to create stream from " & srcFile) 184 | while true: 185 | let bytesRead = strm.readData(addr(buf[0]), buf.len) 186 | if bytesRead <= 0: break 187 | dest.writeData(addr(buf[0]), bytesRead) 188 | 189 | dest.flush() 190 | strm.close() 191 | 192 | proc extractFileImpl(z: var ZipArchive, srcFile: string, dest: string) = 193 | # To avoid check duplication when using extractAll 194 | var file = newFileStream(dest, fmWrite) 195 | if file.isNil: 196 | raise newException(IOError, "Failed to create output file: " & dest) 197 | extractFile(z, srcFile, file) 198 | file.close() 199 | 200 | proc checkPath(dest: string) : bool = 201 | let 202 | dest = expandTilde(dest) 203 | path = Path(dest.splitFile().dir) 204 | base = paths.getCurrentDir() 205 | if isRelativeTo(path, base): 206 | result = true 207 | 208 | proc raiseOnNonRelativePath(dest: string) = 209 | if not checkPath(dest): 210 | raise newException(IOError, "Error, trying to extract in non-relative path") 211 | 212 | proc extractFile*(z: var ZipArchive, srcFile: string, dest: string) = 213 | ## extracts a file from the zip archive `z` to the destination filename. 214 | when not defined(allowRelativePath): 215 | raiseOnNonRelativePath(dest) 216 | extractFileImpl(z, srcFile, dest) 217 | 218 | proc extractAll*(z: var ZipArchive, dest: string) = 219 | ## extracts all files from archive `z` to the destination directory. 220 | when not defined(allowRelativePath): 221 | raiseOnNonRelativePath(dest) 222 | 223 | createDir(dest) 224 | for file in walkFiles(z): 225 | if file.contains("/"): 226 | createDir(dest / file[0..file.rfind("/")]) 227 | if file[^1] != '/': # current file not a folder 228 | extractFileImpl(z, file, dest / file) 229 | 230 | proc fromBuffer*(z: var ZipArchive,data:string) = 231 | var error: int32 232 | var zipSource:PZipSource = zip_source_buffer_create(data,len(data).uint64, 1'i32,error.addr) 233 | if isNil(zipSource): 234 | raise newException(IOError,$error) 235 | z.w = zip_open_from_source(zipSource, 0'i32, error.addr); 236 | if isNil(z.w): 237 | raise newException(IOError,$error) 238 | 239 | when not defined(testing) and isMainModule: 240 | var zip: ZipArchive 241 | if not zip.open("nim-0.11.0.zip"): 242 | raise newException(IOError, "opening zip failed") 243 | zip.extractAll("test") 244 | -------------------------------------------------------------------------------- /zip/libzip.nim: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | # Nim's Runtime Library 4 | # (c) Copyright 2013 Andreas Rumpf 5 | # 6 | # See the file "copying.txt", included in this 7 | # distribution, for details about the copyright. 8 | # 9 | 10 | ## Interface to the `libzip `_ library by 11 | ## Dieter Baron and Thomas Klausner. This version links 12 | ## against ``libzip2.so.2`` unless you define the symbol ``useLibzipSrc``; then 13 | ## it is compiled against some old ``libizp_all.c`` file. 14 | 15 | # 16 | # zip.h -- exported declarations. 17 | # Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner 18 | # 19 | # This file is part of libzip, a library to manipulate ZIP archives. 20 | # The authors can be contacted at 21 | # 22 | # Redistribution and use in source and binary forms, with or without 23 | # modification, are permitted provided that the following conditions 24 | # are met: 25 | # 1. Redistributions of source code must retain the above copyright 26 | # notice, this list of conditions and the following disclaimer. 27 | # 2. Redistributions in binary form must reproduce the above copyright 28 | # notice, this list of conditions and the following disclaimer in 29 | # the documentation and/or other materials provided with the 30 | # distribution. 31 | # 3. The names of the authors may not be used to endorse or promote 32 | # products derived from this software without specific prior 33 | # written permission. 34 | # 35 | # THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS 36 | # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 37 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 38 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 39 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 40 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 41 | # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 42 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 43 | # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 44 | # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 45 | # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | # 47 | 48 | import times 49 | 50 | when defined(unix) and not defined(useLibzipSrc): 51 | when defined(macosx): 52 | {.pragma: mydll, dynlib: "libzip(|2|4).dylib".} 53 | else: 54 | {.pragma: mydll, dynlib: "libzip(|2).so(|.4|.2|.1|.0)".} 55 | else: 56 | when defined(unix): 57 | {.passl: "-lz".} 58 | {.compile: "zip/private/libzip_all.c".} 59 | {.pragma: mydll.} 60 | 61 | type 62 | ZipSourceCmd* = int32 63 | 64 | ZipSourceCallback* = proc (state: pointer, data: pointer, length: int, 65 | cmd: ZipSourceCmd): int {.cdecl.} 66 | PZipStat* = ptr ZipStat 67 | ZipStat* = object ## the 'zip_stat' struct 68 | name*: cstring ## name of the file 69 | index*: int32 ## index within archive 70 | crc*: int32 ## crc of file data 71 | mtime*: Time ## modification time 72 | size*: int ## size of file (uncompressed) 73 | compSize*: int ## size of file (compressed) 74 | compMethod*: int16 ## compression method used 75 | encryptionMethod*: int16 ## encryption method used 76 | 77 | Zip = object 78 | ZipSource = object 79 | ZipFile = object 80 | 81 | PZip* = ptr Zip ## represents a zip archive 82 | PZipFile* = ptr ZipFile ## represents a file within an archive 83 | PZipSource* = ptr ZipSource ## represents a source for an archive 84 | {.deprecated: [TZipSourceCmd: ZipSourceCmd, TZipStat: ZipStat, TZip: Zip, 85 | TZipSourceCallback: ZipSourceCallback, TZipSource: ZipSource, 86 | TZipFile: ZipFile].} 87 | 88 | # flags for zip_name_locate, zip_fopen, zip_stat, ... 89 | const 90 | ZIP_CREATE* = 1'i32 91 | ZIP_EXCL* = 2'i32 92 | ZIP_CHECKCONS* = 4'i32 93 | ZIP_FL_NOCASE* = 1'i32 ## ignore case on name lookup 94 | ZIP_FL_NODIR* = 2'i32 ## ignore directory component 95 | ZIP_FL_COMPRESSED* = 4'i32 ## read compressed data 96 | ZIP_FL_UNCHANGED* = 8'i32 ## use original data, ignoring changes 97 | ZIP_FL_RECOMPRESS* = 16'i32 ## force recompression of data 98 | 99 | const # archive global flags flags 100 | ZIP_AFL_TORRENT* = 1'i32 ## torrent zipped 101 | 102 | const # libzip error codes 103 | ZIP_ER_OK* = 0'i32 ## N No error 104 | ZIP_ER_MULTIDISK* = 1'i32 ## N Multi-disk zip archives not supported 105 | ZIP_ER_RENAME* = 2'i32 ## S Renaming temporary file failed 106 | ZIP_ER_CLOSE* = 3'i32 ## S Closing zip archive failed 107 | ZIP_ER_SEEK* = 4'i32 ## S Seek error 108 | ZIP_ER_READ* = 5'i32 ## S Read error 109 | ZIP_ER_WRITE* = 6'i32 ## S Write error 110 | ZIP_ER_CRC* = 7'i32 ## N CRC error 111 | ZIP_ER_ZIPCLOSED* = 8'i32 ## N Containing zip archive was closed 112 | ZIP_ER_NOENT* = 9'i32 ## N No such file 113 | ZIP_ER_EXISTS* = 10'i32 ## N File already exists 114 | ZIP_ER_OPEN* = 11'i32 ## S Can't open file 115 | ZIP_ER_TMPOPEN* = 12'i32 ## S Failure to create temporary file 116 | ZIP_ER_ZLIB* = 13'i32 ## Z Zlib error 117 | ZIP_ER_MEMORY* = 14'i32 ## N Malloc failure 118 | ZIP_ER_CHANGED* = 15'i32 ## N Entry has been changed 119 | ZIP_ER_COMPNOTSUPP* = 16'i32 ## N Compression method not supported 120 | ZIP_ER_EOF* = 17'i32 ## N Premature EOF 121 | ZIP_ER_INVAL* = 18'i32 ## N Invalid argument 122 | ZIP_ER_NOZIP* = 19'i32 ## N Not a zip archive 123 | ZIP_ER_INTERNAL* = 20'i32 ## N Internal error 124 | ZIP_ER_INCONS* = 21'i32 ## N Zip archive inconsistent 125 | ZIP_ER_REMOVE* = 22'i32 ## S Can't remove file 126 | ZIP_ER_DELETED* = 23'i32 ## N Entry has been deleted 127 | 128 | const # type of system error value 129 | ZIP_ET_NONE* = 0'i32 ## sys_err unused 130 | ZIP_ET_SYS* = 1'i32 ## sys_err is errno 131 | ZIP_ET_ZLIB* = 2'i32 ## sys_err is zlib error code 132 | 133 | const # compression methods 134 | ZIP_CM_DEFAULT* = -1'i32 ## better of deflate or store 135 | ZIP_CM_STORE* = 0'i32 ## stored (uncompressed) 136 | ZIP_CM_SHRINK* = 1'i32 ## shrunk 137 | ZIP_CM_REDUCE_1* = 2'i32 ## reduced with factor 1 138 | ZIP_CM_REDUCE_2* = 3'i32 ## reduced with factor 2 139 | ZIP_CM_REDUCE_3* = 4'i32 ## reduced with factor 3 140 | ZIP_CM_REDUCE_4* = 5'i32 ## reduced with factor 4 141 | ZIP_CM_IMPLODE* = 6'i32 ## imploded 142 | ## 7 - Reserved for Tokenizing compression algorithm 143 | ZIP_CM_DEFLATE* = 8'i32 ## deflated 144 | ZIP_CM_DEFLATE64* = 9'i32 ## deflate64 145 | ZIP_CM_PKWARE_IMPLODE* = 10'i32 ## PKWARE imploding 146 | ## 11 - Reserved by PKWARE 147 | ZIP_CM_BZIP2* = 12'i32 ## compressed using BZIP2 algorithm 148 | ## 13 - Reserved by PKWARE 149 | ZIP_CM_LZMA* = 14'i32 ## LZMA (EFS) 150 | ## 15-17 - Reserved by PKWARE 151 | ZIP_CM_TERSE* = 18'i32 ## compressed using IBM TERSE (new) 152 | ZIP_CM_LZ77* = 19'i32 ## IBM LZ77 z Architecture (PFS) 153 | ZIP_CM_WAVPACK* = 97'i32 ## WavPack compressed data 154 | ZIP_CM_PPMD* = 98'i32 ## PPMd version I, Rev 1 155 | 156 | const # encryption methods 157 | ZIP_EM_NONE* = 0'i32 ## not encrypted 158 | ZIP_EM_TRAD_PKWARE* = 1'i32 ## traditional PKWARE encryption 159 | 160 | const 161 | ZIP_EM_UNKNOWN* = 0x0000FFFF'i32 ## unknown algorithm 162 | 163 | const 164 | ZIP_SOURCE_OPEN* = 0'i32 ## prepare for reading 165 | ZIP_SOURCE_READ* = 1'i32 ## read data 166 | ZIP_SOURCE_CLOSE* = 2'i32 ## reading is done 167 | ZIP_SOURCE_STAT* = 3'i32 ## get meta information 168 | ZIP_SOURCE_ERROR* = 4'i32 ## get error information 169 | constZIP_SOURCE_FREE* = 5'i32 ## cleanup and free resources 170 | ZIP_SOURCE_SUPPORTS* = 14'i32 ## check supported commands 171 | 172 | proc zip_add*(para1: PZip, para2: cstring, para3: PZipSource): int32 {.cdecl, 173 | importc: "zip_add", mydll.} 174 | proc zip_add_dir*(para1: PZip, para2: cstring): int32 {.cdecl, 175 | importc: "zip_add_dir", mydll.} 176 | proc zip_close*(para1: PZip) {.cdecl, importc: "zip_close", mydll.} 177 | proc zip_delete*(para1: PZip, para2: int32): int32 {.cdecl, mydll, 178 | importc: "zip_delete".} 179 | proc zip_error_clear*(para1: PZip) {.cdecl, importc: "zip_error_clear", mydll.} 180 | proc zip_error_get*(para1: PZip, para2: ptr int32, para3: ptr int32) {.cdecl, 181 | importc: "zip_error_get", mydll.} 182 | proc zip_error_get_sys_type*(para1: int32): int32 {.cdecl, mydll, 183 | importc: "zip_error_get_sys_type".} 184 | proc zip_error_to_str*(para1: cstring, para2: int, para3: int32, 185 | para4: int32): int32 {.cdecl, mydll, 186 | importc: "zip_error_to_str".} 187 | proc zip_fclose*(para1: PZipFile) {.cdecl, mydll, 188 | importc: "zip_fclose".} 189 | proc zip_file_error_clear*(para1: PZipFile) {.cdecl, mydll, 190 | importc: "zip_file_error_clear".} 191 | proc zip_file_error_get*(para1: PZipFile, para2: ptr int32, para3: ptr int32) {. 192 | cdecl, mydll, importc: "zip_file_error_get".} 193 | proc zip_file_strerror*(para1: PZipFile): cstring {.cdecl, mydll, 194 | importc: "zip_file_strerror".} 195 | proc zip_fopen*(para1: PZip, para2: cstring, para3: int32): PZipFile {.cdecl, 196 | mydll, importc: "zip_fopen".} 197 | proc zip_fopen_encrypted*(para1: PZip, para2: cstring, para3: int32,password: cstring): PZipFile {.cdecl, 198 | mydll, importc: "zip_fopen_encrypted".} 199 | proc zip_fopen_index*(para1: PZip, para2: uint, para3: int32): PZipFile {. 200 | cdecl, mydll, importc: "zip_fopen_index".} 201 | proc zip_fopen_index_encrypted*(para1: PZip, para2: uint, para3: int32,password: cstring): PZipFile {. 202 | cdecl, mydll, importc: "zip_fopen_index_encrypted".} 203 | proc zip_fread*(para1: PZipFile, para2: pointer, para3: int): int {. 204 | cdecl, mydll, importc: "zip_fread".} 205 | proc zip_get_archive_comment*(para1: PZip, para2: ptr int32, para3: int32): cstring {. 206 | cdecl, mydll, importc: "zip_get_archive_comment".} 207 | proc zip_get_archive_flag*(para1: PZip, para2: int32, para3: int32): int32 {. 208 | cdecl, mydll, importc: "zip_get_archive_flag".} 209 | proc zip_get_file_comment*(para1: PZip, para2: int32, para3: ptr int32, 210 | para4: int32): cstring {.cdecl, mydll, 211 | importc: "zip_get_file_comment".} 212 | proc zip_get_name*(para1: PZip, para2: int32, para3: int32): cstring {.cdecl, 213 | mydll, importc: "zip_get_name".} 214 | proc zip_get_num_files*(para1: PZip): int32 {.cdecl, 215 | mydll, importc: "zip_get_num_files".} 216 | proc zip_name_locate*(para1: PZip, para2: cstring, para3: int32): int32 {.cdecl, 217 | mydll, importc: "zip_name_locate".} 218 | proc zip_open*(para1: cstring, para2: int32, para3: ptr int32): PZip {.cdecl, 219 | mydll, importc: "zip_open".} 220 | proc zip_rename*(para1: PZip, para2: int32, para3: cstring): int32 {.cdecl, 221 | mydll, importc: "zip_rename".} 222 | proc zip_replace*(para1: PZip, para2: int32, para3: PZipSource): int32 {.cdecl, 223 | mydll, importc: "zip_replace".} 224 | proc zip_set_archive_comment*(para1: PZip, para2: cstring, para3: int32): int32 {. 225 | cdecl, mydll, importc: "zip_set_archive_comment".} 226 | proc zip_set_archive_flag*(para1: PZip, para2: int32, para3: int32): int32 {. 227 | cdecl, mydll, importc: "zip_set_archive_flag".} 228 | proc zip_set_file_comment*(para1: PZip, para2: int32, para3: cstring, 229 | para4: int32): int32 {.cdecl, mydll, 230 | importc: "zip_set_file_comment".} 231 | proc zip_set_default_password*(para1: PZip, password: cstring): int32 {. 232 | cdecl, mydll, importc: "zip_set_default_password".} 233 | proc zip_source_buffer*(para1: PZip, para2: pointer, para3: int, para4: int32): PZipSource {. 234 | cdecl, mydll, importc: "zip_source_buffer".} 235 | proc zip_source_buffer_create*(data:cstring,len:uint64,freep:int32,error:pointer): PZipSource {.cdecl, mydll, 236 | importc: "zip_source_buffer_create".} 237 | proc zip_open_from_source*(source:PZipSource,flags:int32,error:pointer): PZip {.cdecl, mydll, 238 | importc: "zip_open_from_source".} 239 | proc zip_source_file*(para1: PZip, para2: cstring, para3: int, para4: int): PZipSource {. 240 | cdecl, mydll, importc: "zip_source_file".} 241 | proc zip_source_filep*(para1: PZip, para2: File, para3: int, para4: int): PZipSource {. 242 | cdecl, mydll, importc: "zip_source_filep".} 243 | proc zip_source_free*(para1: PZipSource) {.cdecl, mydll, 244 | importc: "zip_source_free".} 245 | proc zip_source_function*(para1: PZip, para2: ZipSourceCallback, 246 | para3: pointer): PZipSource {.cdecl, mydll, 247 | importc: "zip_source_function".} 248 | proc zip_source_zip*(para1: PZip, para2: PZip, para3: int32, para4: int32, 249 | para5: int, para6: int): PZipSource {.cdecl, mydll, 250 | importc: "zip_source_zip".} 251 | proc zip_stat*(para1: PZip, para2: cstring, para3: int32, para4: PZipStat): int32 {. 252 | cdecl, mydll, importc: "zip_stat".} 253 | proc zip_stat_index*(para1: PZip, para2: int32, para3: int32, para4: PZipStat): int32 {. 254 | cdecl, mydll, importc: "zip_stat_index".} 255 | proc zip_stat_init*(para1: PZipStat) {.cdecl, mydll, importc: "zip_stat_init".} 256 | proc zip_strerror*(para1: PZip): cstring {.cdecl, mydll, importc: "zip_strerror".} 257 | proc zip_unchange*(para1: PZip, para2: int32): int32 {.cdecl, mydll, 258 | importc: "zip_unchange".} 259 | proc zip_unchange_all*(para1: PZip): int32 {.cdecl, mydll, 260 | importc: "zip_unchange_all".} 261 | proc zip_unchange_archive*(para1: PZip): int32 {.cdecl, mydll, 262 | importc: "zip_unchange_archive".} 263 | -------------------------------------------------------------------------------- /zip/zlib.nim: -------------------------------------------------------------------------------- 1 | # Converted from Pascal 2 | 3 | ## Interface to the zlib http://www.zlib.net/ compression library. 4 | 5 | when defined(windows): 6 | const libz = "zlib1.dll" 7 | elif defined(macosx): 8 | const libz = "libz.dylib" 9 | else: 10 | const libz = "libz.so.1" 11 | 12 | type 13 | Uint* = cuint 14 | Ulong* = culong 15 | Ulongf* = culong 16 | Pulongf* = ptr Ulongf 17 | ZOffT* = clong 18 | Pbyte* = cstring 19 | Pbytef* = cstring 20 | Allocfunc* = proc (p: pointer, items: Uint, size: Uint): pointer{.cdecl.} 21 | FreeFunc* = proc (p: pointer, address: pointer){.cdecl.} 22 | InternalState*{.final, pure.} = object 23 | PInternalState* = ptr InternalState 24 | ZStream*{.final, pure.} = object 25 | nextIn*: Pbytef 26 | availIn*: Uint 27 | totalIn*: Ulong 28 | nextOut*: Pbytef 29 | availOut*: Uint 30 | totalOut*: Ulong 31 | msg*: Pbytef 32 | state*: PInternalState 33 | zalloc*: Allocfunc 34 | zfree*: FreeFunc 35 | opaque*: pointer 36 | dataType*: cint 37 | adler*: Ulong 38 | reserved*: Ulong 39 | GZHeader*{.final, pure.} = object # not defined yet (see zlib.h) 40 | 41 | ZStreamRec* = ZStream 42 | PZstream* = ptr ZStream 43 | GzFile* = pointer 44 | ZStreamHeader* = enum 45 | DETECT_STREAM, 46 | RAW_DEFLATE, 47 | ZLIB_STREAM, 48 | GZIP_STREAM 49 | 50 | ZlibStreamError* = object of Exception 51 | 52 | {.deprecated: [TInternalState: InternalState, TAllocfunc: Allocfunc, 53 | TFreeFunc: FreeFunc, TZStream: ZStream, TZStreamRec: ZStreamRec].} 54 | 55 | const 56 | ZLIB_VERSION = "1.2.11" 57 | 58 | Z_NO_FLUSH* = 0 59 | Z_PARTIAL_FLUSH* = 1 60 | Z_SYNC_FLUSH* = 2 61 | Z_FULL_FLUSH* = 3 62 | Z_FINISH* = 4 63 | Z_OK* = 0 64 | Z_STREAM_END* = 1 65 | Z_NEED_DICT* = 2 66 | Z_ERRNO* = -1 67 | Z_STREAM_ERROR* = -2 68 | Z_DATA_ERROR* = -3 69 | Z_MEM_ERROR* = -4 70 | Z_BUF_ERROR* = -5 71 | Z_VERSION_ERROR* = -6 72 | Z_NO_COMPRESSION* = 0 73 | Z_BEST_SPEED* = 1 74 | Z_BEST_COMPRESSION* = 9 75 | Z_DEFAULT_COMPRESSION* = -1 76 | Z_FILTERED* = 1 77 | Z_HUFFMAN_ONLY* = 2 78 | Z_DEFAULT_STRATEGY* = 0 79 | Z_BINARY* = 0 80 | Z_ASCII* = 1 81 | Z_UNKNOWN* = 2 82 | Z_DEFLATED* = 8 83 | Z_NULL* = 0 84 | Z_MEM_LEVEL* = 8 85 | MAX_WBITS* = 15 86 | 87 | proc zlibVersion*(): cstring{.cdecl, dynlib: libz, importc: "zlibVersion".} 88 | proc deflate*(strm: var ZStream, flush: cint): cint{.cdecl, dynlib: libz, 89 | importc: "deflate".} 90 | proc deflateEnd*(strm: var ZStream): cint{.cdecl, dynlib: libz, 91 | importc: "deflateEnd".} 92 | proc inflate*(strm: var ZStream, flush: cint): cint{.cdecl, dynlib: libz, 93 | importc: "inflate".} 94 | proc inflateEnd*(strm: var ZStream): cint{.cdecl, dynlib: libz, 95 | importc: "inflateEnd".} 96 | proc deflateSetDictionary*(strm: var ZStream, dictionary: Pbytef, 97 | dictLength: Uint): cint{.cdecl, dynlib: libz, 98 | importc: "deflateSetDictionary".} 99 | proc deflateCopy*(dest, source: var ZStream): cint{.cdecl, dynlib: libz, 100 | importc: "deflateCopy".} 101 | proc deflateReset*(strm: var ZStream): cint{.cdecl, dynlib: libz, 102 | importc: "deflateReset".} 103 | proc deflateParams*(strm: var ZStream, level: cint, strategy: cint): cint{. 104 | cdecl, dynlib: libz, importc: "deflateParams".} 105 | proc deflateTune*(strm: var ZStream, goodLength, maxLazy, niceLength, maxChain: cint): cint {. 106 | cdecl, dynlib: libz, importc: "deflateTune".} 107 | proc deflatePending*(strm: var ZStream, pending: var cuint, bits: var cint): cint {. 108 | cdecl, dynlib: libz, importc: "deflatePending".} 109 | proc deflatePrime*(strm: var ZStream, bits, value: cint): cint {. 110 | cdecl, dynlib: libz, importc: "deflatePrime".} 111 | proc deflateSetHeader*(strm: var ZStream, head: ptr GZHeader): cint {. 112 | cdecl, dynlib: libz, importc: "deflateSetHeader".} 113 | proc inflateSetDictionary*(strm: var ZStream, dictionary: Pbytef, 114 | dictLength: Uint): cint{.cdecl, dynlib: libz, 115 | importc: "inflateSetDictionary".} 116 | proc inflateGetDictionary*(strm: var ZStream, dictionary: Pbytef, 117 | dictLength: ptr Uint): cint{.cdecl, dynlib: libz, 118 | importc: "inflateGetDictionary".} 119 | proc inflateSync*(strm: var ZStream): cint{.cdecl, dynlib: libz, 120 | importc: "inflateSync".} 121 | proc inflateCopy*(dest, source: var ZStream): cint{.cdecl, dynlib: libz, 122 | importc: "inflateCopy".} 123 | proc inflateReset*(strm: var ZStream): cint{.cdecl, dynlib: libz, 124 | importc: "inflateReset".} 125 | proc inflateReset2*(strm: var ZStream, windowBits: cint): cint{.cdecl, dynlib: libz, 126 | importc: "inflateReset2".} 127 | proc inflatePrime*(strm: var ZStream, bits: cint, value: cint): cint{.cdecl, dynlib: libz, 128 | importc: "inflatePrime".} 129 | proc inflateMark*(strm: var ZStream): cint{.cdecl, dynlib: libz, 130 | importc: "inflateMark".} 131 | proc inflateGetHeader*(strm: var ZStream, head: ptr GZHeader): cint{.cdecl, dynlib: libz, 132 | importc: "inflateGetHeader".} 133 | proc zlibCompileFlags*(): Ulong{.cdecl, dynlib: libz, 134 | importc: "zlibCompileFlags".} 135 | proc compress*(dest: Pbytef, destLen: Pulongf, source: Pbytef, sourceLen: Ulong): cint{. 136 | cdecl, dynlib: libz, importc: "compress".} 137 | proc compress2*(dest: Pbytef, destLen: Pulongf, source: Pbytef, 138 | sourceLen: Ulong, level: cint): cint{.cdecl, dynlib: libz, 139 | importc: "compress2".} 140 | proc uncompress*(dest: Pbytef, destLen: Pulongf, source: Pbytef, 141 | sourceLen: Ulong): cint{.cdecl, dynlib: libz, 142 | importc: "uncompress".} 143 | proc compressBound*(sourceLen: Ulong): Ulong {.cdecl, dynlib: libz, importc.} 144 | proc gzopen*(path: cstring, mode: cstring): GzFile{.cdecl, dynlib: libz, 145 | importc: "gzopen".} 146 | proc gzdopen*(fd: cint, mode: cstring): GzFile{.cdecl, dynlib: libz, 147 | importc: "gzdopen".} 148 | proc gzsetparams*(thefile: GzFile, level: cint, strategy: cint): cint{.cdecl, 149 | dynlib: libz, importc: "gzsetparams".} 150 | proc gzread*(thefile: GzFile, buf: pointer, length: cuint): cint{.cdecl, 151 | dynlib: libz, importc: "gzread".} 152 | proc gzwrite*(thefile: GzFile, buf: pointer, length: cuint): cint{.cdecl, 153 | dynlib: libz, importc: "gzwrite".} 154 | proc gzprintf*(thefile: GzFile, format: Pbytef): cint{.varargs, cdecl, 155 | dynlib: libz, importc: "gzprintf".} 156 | proc gzputs*(thefile: GzFile, s: Pbytef): cint{.cdecl, dynlib: libz, 157 | importc: "gzputs".} 158 | proc gzgets*(thefile: GzFile, buf: Pbytef, length: cint): Pbytef{.cdecl, 159 | dynlib: libz, importc: "gzgets".} 160 | proc gzputc*(thefile: GzFile, c: cint): cint {.cdecl, dynlib: libz, 161 | importc: "gzputc".} 162 | proc gzgetc*(thefile: GzFile): cint {.cdecl, dynlib: libz, importc: "gzgetc".} 163 | proc gzungetc*(c: cint; thefile: GzFile): cint {.cdecl, dynlib: libz, importc: "gzungetc".} 164 | proc gzflush*(thefile: GzFile, flush: cint): cint{.cdecl, dynlib: libz, 165 | importc: "gzflush".} 166 | proc gzseek*(thefile: GzFile, offset: ZOffT, whence: cint): ZOffT{.cdecl, 167 | dynlib: libz, importc: "gzseek".} 168 | proc gzrewind*(thefile: GzFile): cint{.cdecl, dynlib: libz, importc: "gzrewind".} 169 | proc gztell*(thefile: GzFile): ZOffT{.cdecl, dynlib: libz, importc: "gztell".} 170 | proc gzeof*(thefile: GzFile): int {.cdecl, dynlib: libz, importc: "gzeof".} 171 | proc gzclose*(thefile: GzFile): cint{.cdecl, dynlib: libz, importc: "gzclose".} 172 | proc gzerror*(thefile: GzFile, errnum: var cint): Pbytef{.cdecl, dynlib: libz, 173 | importc: "gzerror".} 174 | proc adler32*(adler: Ulong, buf: Pbytef, length: Uint): Ulong{.cdecl, 175 | dynlib: libz, importc: "adler32".} 176 | ## **Warning**: Adler-32 requires at least a few hundred bytes to get rolling. 177 | proc crc32*(crc: Ulong, buf: Pbytef, length: Uint): Ulong{.cdecl, dynlib: libz, 178 | importc: "crc32".} 179 | proc deflateInitu*(strm: var ZStream, level: cint, version: cstring, 180 | streamSize: cint): cint{.cdecl, dynlib: libz, 181 | importc: "deflateInit_".} 182 | proc inflateInitu*(strm: var ZStream, version: cstring, 183 | streamSize: cint): cint {. 184 | cdecl, dynlib: libz, importc: "inflateInit_".} 185 | proc deflateInit*(strm: var ZStream, level: cint): cint 186 | proc inflateInit*(strm: var ZStream): cint 187 | proc deflateInit2u*(strm: var ZStream, level: cint, `method`: cint, 188 | windowBits: cint, memLevel: cint, strategy: cint, 189 | version: cstring, streamSize: cint): cint {.cdecl, 190 | dynlib: libz, importc: "deflateInit2_".} 191 | proc inflateInit2u*(strm: var ZStream, windowBits: cint, version: cstring, 192 | streamSize: cint): cint{.cdecl, dynlib: libz, 193 | importc: "inflateInit2_".} 194 | proc deflateInit2*(strm: var ZStream, 195 | level, `method`, windowBits, memLevel, 196 | strategy: cint): cint 197 | proc inflateInit2*(strm: var ZStream, windowBits: cint): cint 198 | proc zError*(err: cint): cstring{.cdecl, dynlib: libz, importc: "zError".} 199 | proc inflateSyncPoint*(z: PZstream): cint{.cdecl, dynlib: libz, 200 | importc: "inflateSyncPoint".} 201 | proc getCrcTable*(): pointer{.cdecl, dynlib: libz, importc: "get_crc_table".} 202 | 203 | proc deflateBound*(strm: var ZStream, sourceLen: ULong): ULong {.cdecl, 204 | dynlib: libz, importc: "deflateBound".} 205 | 206 | proc deflateInit(strm: var ZStream, level: cint): cint = 207 | result = deflateInitu(strm, level, ZLIB_VERSION, sizeof(ZStream).cint) 208 | 209 | proc inflateInit(strm: var ZStream): cint = 210 | result = inflateInitu(strm, ZLIB_VERSION, sizeof(ZStream).cint) 211 | 212 | proc deflateInit2(strm: var ZStream, 213 | level, `method`, windowBits, memLevel, 214 | strategy: cint): cint = 215 | result = deflateInit2u(strm, level, `method`, windowBits, memLevel, 216 | strategy, ZLIB_VERSION, sizeof(ZStream).cint) 217 | 218 | proc inflateInit2(strm: var ZStream, windowBits: cint): cint = 219 | result = inflateInit2u(strm, windowBits, ZLIB_VERSION, 220 | sizeof(ZStream).cint) 221 | 222 | proc zlibAllocMem*(appData: pointer, items, size: int): pointer {.cdecl.} = 223 | result = alloc(items * size) 224 | 225 | proc zlibFreeMem*(appData, `block`: pointer) {.cdecl.} = 226 | dealloc(`block`) 227 | 228 | 229 | proc compress*(sourceBuf: cstring; sourceLen: int; level=Z_DEFAULT_COMPRESSION; stream=GZIP_STREAM): string = 230 | ## Given a cstring, returns its deflated version with an optional header. 231 | ## 232 | ## Valid argument for ``stream`` are 233 | ## - ``ZLIB_STREAM`` - add a zlib header and footer. 234 | ## - ``GZIP_STREAM`` - add a basic gzip header and footer. 235 | ## - ``RAW_DEFLATE`` - no header is generated. 236 | ## 237 | ## Passing a nil cstring will crash this proc in release mode and assert in 238 | ## debug mode. 239 | ## 240 | ## Compression level can be set with ``level`` argument. Currently 241 | ## ``Z_DEFAULT_COMPRESSION`` is 6. 242 | ## 243 | ## Returns "" on failure. 244 | assert(not sourceBuf.isNil) 245 | assert(sourceLen >= 0) 246 | 247 | var z: ZStream 248 | var windowBits = MAX_WBITS 249 | case (stream) 250 | of RAW_DEFLATE: windowBits = -MAX_WBITS 251 | of GZIP_STREAM: windowBits = MAX_WBITS + 16 252 | of ZLIB_STREAM, DETECT_STREAM: 253 | discard # DETECT_STREAM defaults to ZLIB_STREAM 254 | 255 | var status = deflateInit2(z, level.cint, Z_DEFLATED.cint, 256 | windowBits.cint, Z_MEM_LEVEL.cint, 257 | Z_DEFAULT_STRATEGY.cint) 258 | case status 259 | of Z_OK: discard 260 | of Z_MEM_ERROR: raise newException(OutOfMemError, "") 261 | of Z_STREAM_ERROR: raise newException(ZlibStreamError, "invalid zlib stream parameter!") 262 | of Z_VERSION_ERROR: raise newException(ZlibStreamError, "zlib version mismatch!") 263 | else: raise newException(ZlibStreamError, "Unknown error(" & $status & ") : " & $z.msg) 264 | 265 | let space = deflateBound(z, sourceLen.Ulong) 266 | var compressed = newString(space) 267 | z.next_in = sourceBuf 268 | z.avail_in = sourceLen.Uint 269 | z.next_out = addr(compressed[0]) 270 | z.avail_out = space.Uint 271 | 272 | status = deflate(z, Z_FINISH) 273 | if status != Z_STREAM_END: 274 | discard deflateEnd(z) # cleanup allocated ressources 275 | raise newException(ZlibStreamError, "Invalid stream state(" & $status & ") : " & $z.msg) 276 | 277 | status = deflateEnd(z) 278 | if status != Z_OK: # cleanup allocated ressources 279 | raise newException(ZlibStreamError, "Invalid stream state(" & $status & ") : " & $z.msg) 280 | 281 | compressed.setLen(z.total_out) 282 | swap(result, compressed) 283 | 284 | proc compress*(input: string; level=Z_DEFAULT_COMPRESSION; stream=GZIP_STREAM): string = 285 | ## Given a string, returns its deflated version with an optional header. 286 | ## 287 | ## Valid arguments for ``stream`` are 288 | ## - ``ZLIB_STREAM`` - add a zlib header and footer. 289 | ## - ``GZIP_STREAM`` - add a basic gzip header and footer. 290 | ## - ``RAW_DEFLATE`` - no header is generated. 291 | ## 292 | ## Compression level can be set with ``level`` argument. Currently 293 | ## ``Z_DEFAULT_COMPRESSION`` is 6. 294 | ## 295 | ## Returns "" on failure. 296 | result = compress(input, input.len, level, stream) 297 | 298 | proc uncompress*(sourceBuf: cstring, sourceLen: Natural; stream=DETECT_STREAM): string = 299 | ## Given a deflated buffer returns its inflated content as a string. 300 | ## 301 | ## Valid arguments for ``stream`` are 302 | ## - ``DETECT_STREAM`` - detect if zlib or gzip header is present 303 | ## and decompress stream. Fail on raw deflate stream. 304 | ## - ``ZLIB_STREAM`` - decompress a zlib stream. 305 | ## - ``GZIP_STREAM`` - decompress a gzip stream. 306 | ## - ``RAW_DEFLATE`` - decompress a raw deflate stream. 307 | ## 308 | ## Passing a nil cstring will crash this proc in release mode and assert in 309 | ## debug mode. 310 | ## 311 | ## Returns "" on problems. Failure is a very loose concept, it could be you 312 | ## passing a non deflated string, or it could mean not having enough memory 313 | ## for the inflated version. 314 | ## 315 | ## The uncompression algorithm is based on http://zlib.net/zpipe.c. 316 | assert(not sourceBuf.isNil) 317 | assert(sourceLen >= 0) 318 | var z: ZStream 319 | var decompressed: string = "" 320 | var sbytes = 0 321 | var wbytes = 0 322 | ## allocate inflate state 323 | 324 | z.availIn = 0 325 | var wbits = case (stream) 326 | of RAW_DEFLATE: -MAX_WBITS 327 | of ZLIB_STREAM: MAX_WBITS 328 | of GZIP_STREAM: MAX_WBITS + 16 329 | of DETECT_STREAM: MAX_WBITS + 32 330 | 331 | var status = inflateInit2(z, wbits.cint) 332 | 333 | case status 334 | of Z_OK: discard 335 | of Z_MEM_ERROR: raise newException(OutOfMemError, "") 336 | of Z_STREAM_ERROR: raise newException(ZlibStreamError, "invalid zlib stream parameter!") 337 | of Z_VERSION_ERROR: raise newException(ZlibStreamError, "zlib version mismatch!") 338 | else: raise newException(ZlibStreamError, "Unkown error(" & $status & ") : " & $z.msg) 339 | 340 | # run loop until all input is consumed. 341 | # handle concatenated deflated stream with header. 342 | while true: 343 | z.availIn = (sourceLen - sbytes).Uint 344 | 345 | # no more input available 346 | if (sourceLen - sbytes) <= 0: break 347 | z.nextIn = sourceBuf[sbytes].unsafeaddr 348 | 349 | # run inflate() on available input until output buffer is full 350 | while true: 351 | # if written bytes >= output size : resize output 352 | if wbytes >= decompressed.len: 353 | let cur_outlen = decompressed.len 354 | let new_outlen = if decompressed.len == 0: sourceLen*2 else: decompressed.len*2 355 | if new_outlen < cur_outlen: # unsigned integer overflow, buffer too large 356 | discard inflateEnd(z); 357 | raise newException(OverflowError, "zlib stream decompressed size is too large! (size > " & $int.high & ")") 358 | 359 | decompressed.setLen(new_outlen) 360 | 361 | # available space for decompression 362 | let space = decompressed.len - wbytes 363 | z.availOut = space.Uint 364 | z.nextOut = decompressed[wbytes].addr 365 | 366 | status = inflate(z, Z_NO_FLUSH) 367 | if status.int8 notin {Z_OK.int8, Z_STREAM_END.int8, Z_BUF_ERROR.int8}: 368 | discard inflateEnd(z) 369 | case status 370 | of Z_MEM_ERROR: raise newException(OutOfMemError, "") 371 | of Z_DATA_ERROR: raise newException(ZlibStreamError, "invalid zlib stream parameter!") 372 | else: raise newException(ZlibStreamError, "Unkown error(" & $status & ") : " & $z.msg) 373 | 374 | # add written bytes, if any. 375 | wbytes += space - z.availOut.int 376 | 377 | # may need more input 378 | if not (z.availOut == 0): break 379 | 380 | # inflate() says stream is done 381 | if (status == Z_STREAM_END): 382 | # may have another stream concatenated 383 | if z.availIn != 0: 384 | sbytes = sourceLen - z.availIn.Natural # add consumed bytes 385 | if inflateReset(z) != Z_OK: # reset zlib struct and try again 386 | raise newException(ZlibStreamError, "Invalid stream state(" & $status & ") : " & $z.msg) 387 | else: 388 | break # end of decompression 389 | 390 | # clean up and don't care about any error 391 | discard inflateEnd(z) 392 | 393 | if status != Z_STREAM_END: 394 | raise newException(ZlibStreamError, "Invalid stream state(" & $status & ") : " & $z.msg) 395 | 396 | decompressed.setLen(wbytes) 397 | swap(result, decompressed) 398 | 399 | 400 | proc uncompress*(sourceBuf: string; stream=DETECT_STREAM): string = 401 | ## Given a GZIP-ed string return its inflated content. 402 | ## 403 | ## Valid arguments for ``stream`` are 404 | ## - ``DETECT_STREAM`` - detect if zlib or gzip header is present 405 | ## and decompress stream. Fail on raw deflate stream. 406 | ## - ``ZLIB_STREAM`` - decompress a zlib stream. 407 | ## - ``GZIP_STREAM`` - decompress a gzip stream. 408 | ## - ``RAW_DEFLATE`` - decompress a raw deflate stream. 409 | ## 410 | ## Returns "" on failure. 411 | result = uncompress(sourceBuf, sourceBuf.len, stream) 412 | 413 | 414 | 415 | proc deflate*(buffer: var string; level=Z_DEFAULT_COMPRESSION; stream=GZIP_STREAM): bool {.discardable.} = 416 | ## Convenience proc which deflates a string and insert an optional header/footer. 417 | ## 418 | ## Valid arguments for ``stream`` are 419 | ## - ``ZLIB_STREAM`` - add a zlib header and footer. 420 | ## - ``GZIP_STREAM`` - add a basic gzip header and footer. 421 | ## - ``RAW_DEFLATE`` - no header is generated. 422 | ## 423 | ## Compression level can be set with ``level`` argument. Currently 424 | ## ``Z_DEFAULT_COMPRESSION`` is 6. 425 | ## 426 | ## Returns true if `buffer` was successfully deflated otherwise the buffer is untouched. 427 | 428 | var temp = compress(addr(buffer[0]), buffer.len, level, stream) 429 | if temp.len != 0: 430 | swap(buffer, temp) 431 | result = true 432 | 433 | proc inflate*(buffer: var string; stream=DETECT_STREAM): bool {.discardable.} = 434 | ## Convenience proc which inflates a string containing compressed data 435 | ## with an optional header. 436 | ## 437 | ## Valid argument for ``stream`` are: 438 | ## - ``DETECT_STREAM`` - detect if zlib or gzip header is present 439 | ## and decompress stream. Fail on raw deflate stream. 440 | ## - ``ZLIB_STREAM`` - decompress a zlib stream. 441 | ## - ``GZIP_STREAM`` - decompress a gzip stream. 442 | ## - ``RAW_DEFLATE`` - decompress a raw deflate stream. 443 | ## 444 | ## It is ok to pass a buffer which doesn't contain deflated data, 445 | ## in this case the proc won't modify the buffer. 446 | ## 447 | ## Returns true if `buffer` was successfully inflated. 448 | 449 | var temp = uncompress(addr(buffer[0]), buffer.len, stream) 450 | if temp.len != 0: 451 | swap(buffer, temp) 452 | result = true 453 | -------------------------------------------------------------------------------- /zip/private/libzip_all.c: -------------------------------------------------------------------------------- 1 | /* 2 | zipint.h -- internal declarations. 3 | Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner 4 | 5 | This file is part of libzip, a library to manipulate ZIP archives. 6 | The authors can be contacted at 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 1. Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the 16 | distribution. 17 | 3. The names of the authors may not be used to endorse or promote 18 | products derived from this software without specific prior 19 | written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS 22 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 25 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 29 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 31 | IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | #include 35 | 36 | /* 37 | #ifdef _MSC_VER 38 | #define ZIP_EXTERN __declspec(dllimport) 39 | #endif 40 | */ 41 | 42 | /* 43 | zip.h -- exported declarations. 44 | Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner 45 | 46 | This file is part of libzip, a library to manipulate ZIP archives. 47 | The authors can be contacted at 48 | 49 | Redistribution and use in source and binary forms, with or without 50 | modification, are permitted provided that the following conditions 51 | are met: 52 | 1. Redistributions of source code must retain the above copyright 53 | notice, this list of conditions and the following disclaimer. 54 | 2. Redistributions in binary form must reproduce the above copyright 55 | notice, this list of conditions and the following disclaimer in 56 | the documentation and/or other materials provided with the 57 | distribution. 58 | 3. The names of the authors may not be used to endorse or promote 59 | products derived from this software without specific prior 60 | written permission. 61 | 62 | THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS 63 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 64 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 66 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 67 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 68 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 69 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 70 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 71 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 72 | IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 | */ 74 | 75 | 76 | #ifndef ZIP_EXTERN 77 | #define ZIP_EXTERN 78 | #endif 79 | 80 | #ifdef __cplusplus 81 | extern "C" { 82 | #endif 83 | 84 | #include 85 | #include 86 | #include 87 | 88 | /* flags for zip_open */ 89 | 90 | #define ZIP_CREATE 1 91 | #define ZIP_EXCL 2 92 | #define ZIP_CHECKCONS 4 93 | 94 | 95 | /* flags for zip_name_locate, zip_fopen, zip_stat, ... */ 96 | 97 | #define ZIP_FL_NOCASE 1 /* ignore case on name lookup */ 98 | #define ZIP_FL_NODIR 2 /* ignore directory component */ 99 | #define ZIP_FL_COMPRESSED 4 /* read compressed data */ 100 | #define ZIP_FL_UNCHANGED 8 /* use original data, ignoring changes */ 101 | #define ZIP_FL_RECOMPRESS 16 /* force recompression of data */ 102 | 103 | /* archive global flags flags */ 104 | 105 | #define ZIP_AFL_TORRENT 1 /* torrent zipped */ 106 | 107 | /* libzip error codes */ 108 | 109 | #define ZIP_ER_OK 0 /* N No error */ 110 | #define ZIP_ER_MULTIDISK 1 /* N Multi-disk zip archives not supported */ 111 | #define ZIP_ER_RENAME 2 /* S Renaming temporary file failed */ 112 | #define ZIP_ER_CLOSE 3 /* S Closing zip archive failed */ 113 | #define ZIP_ER_SEEK 4 /* S Seek error */ 114 | #define ZIP_ER_READ 5 /* S Read error */ 115 | #define ZIP_ER_WRITE 6 /* S Write error */ 116 | #define ZIP_ER_CRC 7 /* N CRC error */ 117 | #define ZIP_ER_ZIPCLOSED 8 /* N Containing zip archive was closed */ 118 | #define ZIP_ER_NOENT 9 /* N No such file */ 119 | #define ZIP_ER_EXISTS 10 /* N File already exists */ 120 | #define ZIP_ER_OPEN 11 /* S Can't open file */ 121 | #define ZIP_ER_TMPOPEN 12 /* S Failure to create temporary file */ 122 | #define ZIP_ER_ZLIB 13 /* Z Zlib error */ 123 | #define ZIP_ER_MEMORY 14 /* N Malloc failure */ 124 | #define ZIP_ER_CHANGED 15 /* N Entry has been changed */ 125 | #define ZIP_ER_COMPNOTSUPP 16 /* N Compression method not supported */ 126 | #define ZIP_ER_EOF 17 /* N Premature EOF */ 127 | #define ZIP_ER_INVAL 18 /* N Invalid argument */ 128 | #define ZIP_ER_NOZIP 19 /* N Not a zip archive */ 129 | #define ZIP_ER_INTERNAL 20 /* N Internal error */ 130 | #define ZIP_ER_INCONS 21 /* N Zip archive inconsistent */ 131 | #define ZIP_ER_REMOVE 22 /* S Can't remove file */ 132 | #define ZIP_ER_DELETED 23 /* N Entry has been deleted */ 133 | 134 | 135 | /* type of system error value */ 136 | 137 | #define ZIP_ET_NONE 0 /* sys_err unused */ 138 | #define ZIP_ET_SYS 1 /* sys_err is errno */ 139 | #define ZIP_ET_ZLIB 2 /* sys_err is zlib error code */ 140 | 141 | /* compression methods */ 142 | 143 | #define ZIP_CM_DEFAULT -1 /* better of deflate or store */ 144 | #define ZIP_CM_STORE 0 /* stored (uncompressed) */ 145 | #define ZIP_CM_SHRINK 1 /* shrunk */ 146 | #define ZIP_CM_REDUCE_1 2 /* reduced with factor 1 */ 147 | #define ZIP_CM_REDUCE_2 3 /* reduced with factor 2 */ 148 | #define ZIP_CM_REDUCE_3 4 /* reduced with factor 3 */ 149 | #define ZIP_CM_REDUCE_4 5 /* reduced with factor 4 */ 150 | #define ZIP_CM_IMPLODE 6 /* imploded */ 151 | /* 7 - Reserved for Tokenizing compression algorithm */ 152 | #define ZIP_CM_DEFLATE 8 /* deflated */ 153 | #define ZIP_CM_DEFLATE64 9 /* deflate64 */ 154 | #define ZIP_CM_PKWARE_IMPLODE 10 /* PKWARE imploding */ 155 | /* 11 - Reserved by PKWARE */ 156 | #define ZIP_CM_BZIP2 12 /* compressed using BZIP2 algorithm */ 157 | /* 13 - Reserved by PKWARE */ 158 | #define ZIP_CM_LZMA 14 /* LZMA (EFS) */ 159 | /* 15-17 - Reserved by PKWARE */ 160 | #define ZIP_CM_TERSE 18 /* compressed using IBM TERSE (new) */ 161 | #define ZIP_CM_LZ77 19 /* IBM LZ77 z Architecture (PFS) */ 162 | #define ZIP_CM_WAVPACK 97 /* WavPack compressed data */ 163 | #define ZIP_CM_PPMD 98 /* PPMd version I, Rev 1 */ 164 | 165 | /* encryption methods */ 166 | 167 | #define ZIP_EM_NONE 0 /* not encrypted */ 168 | #define ZIP_EM_TRAD_PKWARE 1 /* traditional PKWARE encryption */ 169 | #if 0 /* Strong Encryption Header not parsed yet */ 170 | #define ZIP_EM_DES 0x6601 /* strong encryption: DES */ 171 | #define ZIP_EM_RC2_OLD 0x6602 /* strong encryption: RC2, version < 5.2 */ 172 | #define ZIP_EM_3DES_168 0x6603 173 | #define ZIP_EM_3DES_112 0x6609 174 | #define ZIP_EM_AES_128 0x660e 175 | #define ZIP_EM_AES_192 0x660f 176 | #define ZIP_EM_AES_256 0x6610 177 | #define ZIP_EM_RC2 0x6702 /* strong encryption: RC2, version >= 5.2 */ 178 | #define ZIP_EM_RC4 0x6801 179 | #endif 180 | #define ZIP_EM_UNKNOWN 0xffff /* unknown algorithm */ 181 | 182 | typedef long myoff_t; /* XXX: 64 bit support */ 183 | 184 | enum zip_source_cmd { 185 | ZIP_SOURCE_OPEN, /* prepare for reading */ 186 | ZIP_SOURCE_READ, /* read data */ 187 | ZIP_SOURCE_CLOSE, /* reading is done */ 188 | ZIP_SOURCE_STAT, /* get meta information */ 189 | ZIP_SOURCE_ERROR, /* get error information */ 190 | ZIP_SOURCE_FREE /* cleanup and free resources */ 191 | }; 192 | 193 | typedef ssize_t (*zip_source_callback)(void *state, void *data, 194 | size_t len, enum zip_source_cmd cmd); 195 | 196 | struct zip_stat { 197 | const char *name; /* name of the file */ 198 | int index; /* index within archive */ 199 | unsigned int crc; /* crc of file data */ 200 | time_t mtime; /* modification time */ 201 | myoff_t size; /* size of file (uncompressed) */ 202 | myoff_t comp_size; /* size of file (compressed) */ 203 | unsigned short comp_method; /* compression method used */ 204 | unsigned short encryption_method; /* encryption method used */ 205 | }; 206 | 207 | struct zip; 208 | struct zip_file; 209 | struct zip_source; 210 | 211 | 212 | ZIP_EXTERN int zip_add(struct zip *, const char *, struct zip_source *); 213 | ZIP_EXTERN int zip_add_dir(struct zip *, const char *); 214 | ZIP_EXTERN int zip_close(struct zip *); 215 | ZIP_EXTERN int zip_delete(struct zip *, int); 216 | ZIP_EXTERN void zip_error_clear(struct zip *); 217 | ZIP_EXTERN void zip_error_get(struct zip *, int *, int *); 218 | ZIP_EXTERN int zip_error_get_sys_type(int); 219 | ZIP_EXTERN int zip_error_to_str(char *, size_t, int, int); 220 | ZIP_EXTERN int zip_fclose(struct zip_file *); 221 | ZIP_EXTERN void zip_file_error_clear(struct zip_file *); 222 | ZIP_EXTERN void zip_file_error_get(struct zip_file *, int *, int *); 223 | ZIP_EXTERN const char *zip_file_strerror(struct zip_file *); 224 | ZIP_EXTERN struct zip_file *zip_fopen(struct zip *, const char *, int); 225 | ZIP_EXTERN struct zip_file *zip_fopen_index(struct zip *, int, int); 226 | ZIP_EXTERN ssize_t zip_fread(struct zip_file *, void *, size_t); 227 | ZIP_EXTERN const char *zip_get_archive_comment(struct zip *, int *, int); 228 | ZIP_EXTERN int zip_get_archive_flag(struct zip *, int, int); 229 | ZIP_EXTERN const char *zip_get_file_comment(struct zip *, int, int *, int); 230 | ZIP_EXTERN const char *zip_get_name(struct zip *, int, int); 231 | ZIP_EXTERN int zip_get_num_files(struct zip *); 232 | ZIP_EXTERN int zip_name_locate(struct zip *, const char *, int); 233 | ZIP_EXTERN struct zip *zip_open(const char *, int, int *); 234 | ZIP_EXTERN int zip_rename(struct zip *, int, const char *); 235 | ZIP_EXTERN int zip_replace(struct zip *, int, struct zip_source *); 236 | ZIP_EXTERN int zip_set_archive_comment(struct zip *, const char *, int); 237 | ZIP_EXTERN int zip_set_archive_flag(struct zip *, int, int); 238 | ZIP_EXTERN int zip_set_file_comment(struct zip *, int, const char *, int); 239 | ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *, 240 | myoff_t, int); 241 | ZIP_EXTERN struct zip_source *zip_source_file(struct zip *, const char *, 242 | myoff_t, myoff_t); 243 | ZIP_EXTERN struct zip_source *zip_source_filep(struct zip *, FILE *, 244 | myoff_t, myoff_t); 245 | ZIP_EXTERN void zip_source_free(struct zip_source *); 246 | ZIP_EXTERN struct zip_source *zip_source_function(struct zip *, 247 | zip_source_callback, void *); 248 | ZIP_EXTERN struct zip_source *zip_source_zip(struct zip *, struct zip *, 249 | int, int, myoff_t, myoff_t); 250 | ZIP_EXTERN int zip_stat(struct zip *, const char *, int, struct zip_stat *); 251 | ZIP_EXTERN int zip_stat_index(struct zip *, int, int, struct zip_stat *); 252 | ZIP_EXTERN void zip_stat_init(struct zip_stat *); 253 | ZIP_EXTERN const char *zip_strerror(struct zip *); 254 | ZIP_EXTERN int zip_unchange(struct zip *, int); 255 | ZIP_EXTERN int zip_unchange_all(struct zip *); 256 | ZIP_EXTERN int zip_unchange_archive(struct zip *); 257 | 258 | #ifdef __cplusplus 259 | } 260 | #endif 261 | 262 | 263 | /* config.h. Generated from config.h.in by configure. */ 264 | /* config.h.in. Generated from configure.ac by autoheader. */ 265 | 266 | /* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. 267 | */ 268 | /* #undef HAVE_DECL_TZNAME */ 269 | 270 | #define HAVE_CONFIG_H 1 271 | 272 | /* Define to 1 if you have the header file. */ 273 | #define HAVE_DLFCN_H 1 274 | 275 | /* Define to 1 if you have the `fseeko' function. */ 276 | #define HAVE_FSEEKO 1 277 | 278 | /* Define to 1 if you have the `ftello' function. */ 279 | #define HAVE_FTELLO 1 280 | 281 | /* Define to 1 if you have the header file. */ 282 | #define HAVE_INTTYPES_H 1 283 | 284 | /* Define to 1 if you have the `z' library (-lz). */ 285 | #define HAVE_LIBZ 1 286 | 287 | /* Define to 1 if you have the header file. */ 288 | #define HAVE_MEMORY_H 1 289 | 290 | /* Define to 1 if you have the `mkstemp' function. */ 291 | #define HAVE_MKSTEMP 1 292 | 293 | /* Define to 1 if you have the `MoveFileExA' function. */ 294 | /* #undef HAVE_MOVEFILEEXA */ 295 | 296 | /* Define to 1 if you have the header file. */ 297 | #define HAVE_STDINT_H 1 298 | 299 | /* Define to 1 if you have the header file. */ 300 | #define HAVE_STDLIB_H 1 301 | 302 | /* Define to 1 if you have the header file. */ 303 | #define HAVE_STRINGS_H 1 304 | 305 | /* Define to 1 if you have the header file. */ 306 | #define HAVE_STRING_H 1 307 | 308 | /* Define to 1 if `tm_zone' is member of `struct tm'. */ 309 | #ifdef WIN32 310 | #undef HAVE_STRUCT_TM_TM_ZONE 311 | #else 312 | #define HAVE_STRUCT_TM_TM_ZONE 1 313 | #endif 314 | 315 | /* Define to 1 if you have the header file. */ 316 | #define HAVE_SYS_STAT_H 1 317 | 318 | /* Define to 1 if you have the header file. */ 319 | #define HAVE_SYS_TYPES_H 1 320 | 321 | /* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use 322 | `HAVE_STRUCT_TM_TM_ZONE' instead. */ 323 | #define HAVE_TM_ZONE 1 324 | 325 | /* Define to 1 if you don't have `tm_zone' but do have the external array 326 | `tzname'. */ 327 | /* #undef HAVE_TZNAME */ 328 | 329 | /* Define to 1 if you have the header file. */ 330 | #define HAVE_UNISTD_H 1 331 | 332 | /* Define to 1 if your C compiler doesn't accept -c and -o together. */ 333 | /* #undef NO_MINUS_C_MINUS_O */ 334 | 335 | /* Name of package */ 336 | #define PACKAGE "libzip" 337 | 338 | /* Define to the address where bug reports for this package should be sent. */ 339 | #define PACKAGE_BUGREPORT "libzip@nih.at" 340 | 341 | /* Define to the full name of this package. */ 342 | #define PACKAGE_NAME "libzip" 343 | 344 | /* Define to the full name and version of this package. */ 345 | #define PACKAGE_STRING "libzip 0.9" 346 | 347 | /* Define to the one symbol short name of this package. */ 348 | #define PACKAGE_TARNAME "libzip" 349 | 350 | /* Define to the version of this package. */ 351 | #define PACKAGE_VERSION "0.9" 352 | 353 | /* Define to 1 if you have the ANSI C header files. */ 354 | #define STDC_HEADERS 1 355 | 356 | /* Define to 1 if your declares `struct tm'. */ 357 | /* #undef TM_IN_SYS_TIME */ 358 | 359 | /* Version number of package */ 360 | #define VERSION "0.9" 361 | 362 | 363 | #ifndef HAVE_MKSTEMP 364 | int _zip_mkstemp(char *); 365 | #define mkstemp _zip_mkstemp 366 | #endif 367 | 368 | #ifdef HAVE_MOVEFILEEXA 369 | #include 370 | #define _zip_rename(s, t) \ 371 | (!MoveFileExA((s), (t), \ 372 | MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING)) 373 | #else 374 | #define _zip_rename rename 375 | #endif 376 | 377 | #ifndef HAVE_FSEEKO 378 | #define fseeko(s, o, w) (fseek((s), (long int)(o), (w))) 379 | #endif 380 | #ifndef HAVE_FTELLO 381 | #define ftello(s) ((long)ftell((s))) 382 | #endif 383 | 384 | 385 | #define CENTRAL_MAGIC "PK\1\2" 386 | #define LOCAL_MAGIC "PK\3\4" 387 | #define EOCD_MAGIC "PK\5\6" 388 | #define DATADES_MAGIC "PK\7\8" 389 | #define TORRENT_SIG "TORRENTZIPPED-" 390 | #define TORRENT_SIG_LEN 14 391 | #define TORRENT_CRC_LEN 8 392 | #define TORRENT_MEM_LEVEL 8 393 | #define CDENTRYSIZE 46u 394 | #define LENTRYSIZE 30 395 | #define MAXCOMLEN 65536 396 | #define EOCDLEN 22 397 | #define CDBUFSIZE (MAXCOMLEN+EOCDLEN) 398 | #define BUFSIZE 8192 399 | 400 | 401 | /* state of change of a file in zip archive */ 402 | 403 | enum zip_state { ZIP_ST_UNCHANGED, ZIP_ST_DELETED, ZIP_ST_REPLACED, 404 | ZIP_ST_ADDED, ZIP_ST_RENAMED }; 405 | 406 | /* constants for struct zip_file's member flags */ 407 | 408 | #define ZIP_ZF_EOF 1 /* EOF reached */ 409 | #define ZIP_ZF_DECOMP 2 /* decompress data */ 410 | #define ZIP_ZF_CRC 4 /* compute and compare CRC */ 411 | 412 | /* directory entry: general purpose bit flags */ 413 | 414 | #define ZIP_GPBF_ENCRYPTED 0x0001 /* is encrypted */ 415 | #define ZIP_GPBF_DATA_DESCRIPTOR 0x0008 /* crc/size after file data */ 416 | #define ZIP_GPBF_STRONG_ENCRYPTION 0x0040 /* uses strong encryption */ 417 | 418 | /* error information */ 419 | 420 | struct zip_error { 421 | int zip_err; /* libzip error code (ZIP_ER_*) */ 422 | int sys_err; /* copy of errno (E*) or zlib error code */ 423 | char *str; /* string representation or NULL */ 424 | }; 425 | 426 | /* zip archive, part of API */ 427 | 428 | struct zip { 429 | char *zn; /* file name */ 430 | FILE *zp; /* file */ 431 | struct zip_error error; /* error information */ 432 | 433 | unsigned int flags; /* archive global flags */ 434 | unsigned int ch_flags; /* changed archive global flags */ 435 | 436 | struct zip_cdir *cdir; /* central directory */ 437 | char *ch_comment; /* changed archive comment */ 438 | int ch_comment_len; /* length of changed zip archive 439 | * comment, -1 if unchanged */ 440 | int nentry; /* number of entries */ 441 | int nentry_alloc; /* number of entries allocated */ 442 | struct zip_entry *entry; /* entries */ 443 | int nfile; /* number of opened files within archive */ 444 | int nfile_alloc; /* number of files allocated */ 445 | struct zip_file **file; /* opened files within archive */ 446 | }; 447 | 448 | /* file in zip archive, part of API */ 449 | 450 | struct zip_file { 451 | struct zip *za; /* zip archive containing this file */ 452 | struct zip_error error; /* error information */ 453 | int flags; /* -1: eof, >0: error */ 454 | 455 | int method; /* compression method */ 456 | myoff_t fpos; /* position within zip file (fread/fwrite) */ 457 | unsigned long bytes_left; /* number of bytes left to read */ 458 | unsigned long cbytes_left; /* number of bytes of compressed data left */ 459 | 460 | unsigned long crc; /* CRC so far */ 461 | unsigned long crc_orig; /* CRC recorded in archive */ 462 | 463 | char *buffer; 464 | z_stream *zstr; 465 | }; 466 | 467 | /* zip archive directory entry (central or local) */ 468 | 469 | struct zip_dirent { 470 | unsigned short version_madeby; /* (c) version of creator */ 471 | unsigned short version_needed; /* (cl) version needed to extract */ 472 | unsigned short bitflags; /* (cl) general purpose bit flag */ 473 | unsigned short comp_method; /* (cl) compression method used */ 474 | time_t last_mod; /* (cl) time of last modification */ 475 | unsigned int crc; /* (cl) CRC-32 of uncompressed data */ 476 | unsigned int comp_size; /* (cl) size of commpressed data */ 477 | unsigned int uncomp_size; /* (cl) size of uncommpressed data */ 478 | char *filename; /* (cl) file name (NUL-terminated) */ 479 | unsigned short filename_len; /* (cl) length of filename (w/o NUL) */ 480 | char *extrafield; /* (cl) extra field */ 481 | unsigned short extrafield_len; /* (cl) length of extra field */ 482 | char *comment; /* (c) file comment */ 483 | unsigned short comment_len; /* (c) length of file comment */ 484 | unsigned short disk_number; /* (c) disk number start */ 485 | unsigned short int_attrib; /* (c) internal file attributes */ 486 | unsigned int ext_attrib; /* (c) external file attributes */ 487 | unsigned int offset; /* (c) offset of local header */ 488 | }; 489 | 490 | /* zip archive central directory */ 491 | 492 | struct zip_cdir { 493 | struct zip_dirent *entry; /* directory entries */ 494 | int nentry; /* number of entries */ 495 | 496 | unsigned int size; /* size of central direcotry */ 497 | unsigned int offset; /* offset of central directory in file */ 498 | char *comment; /* zip archive comment */ 499 | unsigned short comment_len; /* length of zip archive comment */ 500 | }; 501 | 502 | 503 | 504 | struct zip_source { 505 | zip_source_callback f; 506 | void *ud; 507 | }; 508 | 509 | /* entry in zip archive directory */ 510 | 511 | struct zip_entry { 512 | enum zip_state state; 513 | struct zip_source *source; 514 | char *ch_filename; 515 | char *ch_comment; 516 | int ch_comment_len; 517 | }; 518 | 519 | 520 | 521 | extern const char * const _zip_err_str[]; 522 | extern const int _zip_nerr_str; 523 | extern const int _zip_err_type[]; 524 | 525 | 526 | 527 | #define ZIP_ENTRY_DATA_CHANGED(x) \ 528 | ((x)->state == ZIP_ST_REPLACED \ 529 | || (x)->state == ZIP_ST_ADDED) 530 | 531 | 532 | 533 | int _zip_cdir_compute_crc(struct zip *, uLong *); 534 | void _zip_cdir_free(struct zip_cdir *); 535 | struct zip_cdir *_zip_cdir_new(int, struct zip_error *); 536 | int _zip_cdir_write(struct zip_cdir *, FILE *, struct zip_error *); 537 | 538 | void _zip_dirent_finalize(struct zip_dirent *); 539 | void _zip_dirent_init(struct zip_dirent *); 540 | int _zip_dirent_read(struct zip_dirent *, FILE *, 541 | unsigned char **, unsigned int, int, struct zip_error *); 542 | void _zip_dirent_torrent_normalize(struct zip_dirent *); 543 | int _zip_dirent_write(struct zip_dirent *, FILE *, int, struct zip_error *); 544 | 545 | void _zip_entry_free(struct zip_entry *); 546 | void _zip_entry_init(struct zip *, int); 547 | struct zip_entry *_zip_entry_new(struct zip *); 548 | 549 | void _zip_error_clear(struct zip_error *); 550 | void _zip_error_copy(struct zip_error *, struct zip_error *); 551 | void _zip_error_fini(struct zip_error *); 552 | void _zip_error_get(struct zip_error *, int *, int *); 553 | void _zip_error_init(struct zip_error *); 554 | void _zip_error_set(struct zip_error *, int, int); 555 | const char *_zip_error_strerror(struct zip_error *); 556 | 557 | int _zip_file_fillbuf(void *, size_t, struct zip_file *); 558 | unsigned int _zip_file_get_offset(struct zip *, int); 559 | 560 | int _zip_filerange_crc(FILE *, myoff_t, myoff_t, uLong *, struct zip_error *); 561 | 562 | struct zip_source *_zip_source_file_or_p(struct zip *, const char *, FILE *, 563 | myoff_t, myoff_t); 564 | 565 | void _zip_free(struct zip *); 566 | const char *_zip_get_name(struct zip *, int, int, struct zip_error *); 567 | int _zip_local_header_read(struct zip *, int); 568 | void *_zip_memdup(const void *, size_t, struct zip_error *); 569 | int _zip_name_locate(struct zip *, const char *, int, struct zip_error *); 570 | struct zip *_zip_new(struct zip_error *); 571 | unsigned short _zip_read2(unsigned char **); 572 | unsigned int _zip_read4(unsigned char **); 573 | int _zip_replace(struct zip *, int, const char *, struct zip_source *); 574 | int _zip_set_name(struct zip *, int, const char *); 575 | int _zip_unchange(struct zip *, int, int); 576 | void _zip_unchange_data(struct zip_entry *); 577 | 578 | 579 | #include 580 | #include 581 | #include 582 | #include 583 | 584 | const char * 585 | _zip_error_strerror(struct zip_error *err) 586 | { 587 | const char *zs, *ss; 588 | char buf[128], *s; 589 | 590 | _zip_error_fini(err); 591 | 592 | if (err->zip_err < 0 || err->zip_err >= _zip_nerr_str) { 593 | sprintf(buf, "Unknown error %d", err->zip_err); 594 | zs = NULL; 595 | ss = buf; 596 | } 597 | else { 598 | zs = _zip_err_str[err->zip_err]; 599 | 600 | switch (_zip_err_type[err->zip_err]) { 601 | case ZIP_ET_SYS: 602 | ss = strerror(err->sys_err); 603 | break; 604 | 605 | case ZIP_ET_ZLIB: 606 | ss = zError(err->sys_err); 607 | break; 608 | 609 | default: 610 | ss = NULL; 611 | } 612 | } 613 | 614 | if (ss == NULL) 615 | return zs; 616 | else { 617 | if ((s=(char *)malloc(strlen(ss) 618 | + (zs ? strlen(zs)+2 : 0) + 1)) == NULL) 619 | return _zip_err_str[ZIP_ER_MEMORY]; 620 | 621 | sprintf(s, "%s%s%s", 622 | (zs ? zs : ""), 623 | (zs ? ": " : ""), 624 | ss); 625 | err->str = s; 626 | 627 | return s; 628 | } 629 | } 630 | 631 | #include 632 | 633 | 634 | 635 | void 636 | _zip_error_clear(struct zip_error *err) 637 | { 638 | err->zip_err = ZIP_ER_OK; 639 | err->sys_err = 0; 640 | } 641 | 642 | 643 | 644 | void 645 | _zip_error_copy(struct zip_error *dst, struct zip_error *src) 646 | { 647 | dst->zip_err = src->zip_err; 648 | dst->sys_err = src->sys_err; 649 | } 650 | 651 | 652 | 653 | void 654 | _zip_error_fini(struct zip_error *err) 655 | { 656 | free(err->str); 657 | err->str = NULL; 658 | } 659 | 660 | 661 | 662 | void 663 | _zip_error_get(struct zip_error *err, int *zep, int *sep) 664 | { 665 | if (zep) 666 | *zep = err->zip_err; 667 | if (sep) { 668 | if (zip_error_get_sys_type(err->zip_err) != ZIP_ET_NONE) 669 | *sep = err->sys_err; 670 | else 671 | *sep = 0; 672 | } 673 | } 674 | 675 | 676 | 677 | void 678 | _zip_error_init(struct zip_error *err) 679 | { 680 | err->zip_err = ZIP_ER_OK; 681 | err->sys_err = 0; 682 | err->str = NULL; 683 | } 684 | 685 | 686 | 687 | void 688 | _zip_error_set(struct zip_error *err, int ze, int se) 689 | { 690 | if (err) { 691 | err->zip_err = ze; 692 | err->sys_err = se; 693 | } 694 | } 695 | 696 | 697 | #include 698 | #include 699 | 700 | #include 701 | #include 702 | #include 703 | #include 704 | #include 705 | #include 706 | 707 | #ifndef O_BINARY 708 | #define O_BINARY 0 709 | #endif 710 | 711 | 712 | 713 | int 714 | _zip_mkstemp(char *path) 715 | { 716 | int fd; 717 | char *start, *trv; 718 | struct stat sbuf; 719 | pid_t pid; 720 | 721 | /* To guarantee multiple calls generate unique names even if 722 | the file is not created. 676 different possibilities with 7 723 | or more X's, 26 with 6 or less. */ 724 | static char xtra[2] = "aa"; 725 | int xcnt = 0; 726 | 727 | pid = getpid(); 728 | 729 | /* Move to end of path and count trailing X's. */ 730 | for (trv = path; *trv; ++trv) 731 | if (*trv == 'X') 732 | xcnt++; 733 | else 734 | xcnt = 0; 735 | 736 | /* Use at least one from xtra. Use 2 if more than 6 X's. */ 737 | if (*(trv - 1) == 'X') 738 | *--trv = xtra[0]; 739 | if (xcnt > 6 && *(trv - 1) == 'X') 740 | *--trv = xtra[1]; 741 | 742 | /* Set remaining X's to pid digits with 0's to the left. */ 743 | while (*--trv == 'X') { 744 | *trv = (pid % 10) + '0'; 745 | pid /= 10; 746 | } 747 | 748 | /* update xtra for next call. */ 749 | if (xtra[0] != 'z') 750 | xtra[0]++; 751 | else { 752 | xtra[0] = 'a'; 753 | if (xtra[1] != 'z') 754 | xtra[1]++; 755 | else 756 | xtra[1] = 'a'; 757 | } 758 | 759 | /* 760 | * check the target directory; if you have six X's and it 761 | * doesn't exist this runs for a *very* long time. 762 | */ 763 | for (start = trv + 1;; --trv) { 764 | if (trv <= path) 765 | break; 766 | if (*trv == '/') { 767 | *trv = '\0'; 768 | if (stat(path, &sbuf)) 769 | return (0); 770 | if (!S_ISDIR(sbuf.st_mode)) { 771 | errno = ENOTDIR; 772 | return (0); 773 | } 774 | *trv = '/'; 775 | break; 776 | } 777 | } 778 | 779 | for (;;) { 780 | if ((fd=open(path, O_CREAT|O_EXCL|O_RDWR|O_BINARY, 0600)) >= 0) 781 | return (fd); 782 | if (errno != EEXIST) 783 | return (0); 784 | 785 | /* tricky little algorithm for backward compatibility */ 786 | for (trv = start;;) { 787 | if (!*trv) 788 | return (0); 789 | if (*trv == 'z') 790 | *trv++ = 'a'; 791 | else { 792 | if (isdigit((unsigned char)*trv)) 793 | *trv = 'a'; 794 | else 795 | ++*trv; 796 | break; 797 | } 798 | } 799 | } 800 | /*NOTREACHED*/ 801 | } 802 | 803 | 804 | #include 805 | #include 806 | #include 807 | #include 808 | #include 809 | #include 810 | 811 | static time_t _zip_d2u_time(int, int); 812 | static char *_zip_readfpstr(FILE *, unsigned int, int, struct zip_error *); 813 | static char *_zip_readstr(unsigned char **, int, int, struct zip_error *); 814 | static void _zip_u2d_time(time_t, unsigned short *, unsigned short *); 815 | static void _zip_write2(unsigned short, FILE *); 816 | static void _zip_write4(unsigned int, FILE *); 817 | 818 | 819 | 820 | void 821 | _zip_cdir_free(struct zip_cdir *cd) 822 | { 823 | int i; 824 | 825 | if (!cd) 826 | return; 827 | 828 | for (i=0; inentry; i++) 829 | _zip_dirent_finalize(cd->entry+i); 830 | free(cd->comment); 831 | free(cd->entry); 832 | free(cd); 833 | } 834 | 835 | 836 | 837 | struct zip_cdir * 838 | _zip_cdir_new(int nentry, struct zip_error *error) 839 | { 840 | struct zip_cdir *cd; 841 | 842 | if ((cd=(struct zip_cdir *)malloc(sizeof(*cd))) == NULL) { 843 | _zip_error_set(error, ZIP_ER_MEMORY, 0); 844 | return NULL; 845 | } 846 | 847 | if ((cd->entry=(struct zip_dirent *)malloc(sizeof(*(cd->entry))*nentry)) 848 | == NULL) { 849 | _zip_error_set(error, ZIP_ER_MEMORY, 0); 850 | free(cd); 851 | return NULL; 852 | } 853 | 854 | /* entries must be initialized by caller */ 855 | 856 | cd->nentry = nentry; 857 | cd->size = cd->offset = 0; 858 | cd->comment = NULL; 859 | cd->comment_len = 0; 860 | 861 | return cd; 862 | } 863 | 864 | 865 | 866 | int 867 | _zip_cdir_write(struct zip_cdir *cd, FILE *fp, struct zip_error *error) 868 | { 869 | int i; 870 | 871 | cd->offset = ftello(fp); 872 | 873 | for (i=0; inentry; i++) { 874 | if (_zip_dirent_write(cd->entry+i, fp, 0, error) != 0) 875 | return -1; 876 | } 877 | 878 | cd->size = ftello(fp) - cd->offset; 879 | 880 | /* clearerr(fp); */ 881 | fwrite(EOCD_MAGIC, 1, 4, fp); 882 | _zip_write4(0, fp); 883 | _zip_write2((unsigned short)cd->nentry, fp); 884 | _zip_write2((unsigned short)cd->nentry, fp); 885 | _zip_write4(cd->size, fp); 886 | _zip_write4(cd->offset, fp); 887 | _zip_write2(cd->comment_len, fp); 888 | fwrite(cd->comment, 1, cd->comment_len, fp); 889 | 890 | if (ferror(fp)) { 891 | _zip_error_set(error, ZIP_ER_WRITE, errno); 892 | return -1; 893 | } 894 | 895 | return 0; 896 | } 897 | 898 | 899 | 900 | void 901 | _zip_dirent_finalize(struct zip_dirent *zde) 902 | { 903 | free(zde->filename); 904 | zde->filename = NULL; 905 | free(zde->extrafield); 906 | zde->extrafield = NULL; 907 | free(zde->comment); 908 | zde->comment = NULL; 909 | } 910 | 911 | 912 | 913 | void 914 | _zip_dirent_init(struct zip_dirent *de) 915 | { 916 | de->version_madeby = 0; 917 | de->version_needed = 20; /* 2.0 */ 918 | de->bitflags = 0; 919 | de->comp_method = 0; 920 | de->last_mod = 0; 921 | de->crc = 0; 922 | de->comp_size = 0; 923 | de->uncomp_size = 0; 924 | de->filename = NULL; 925 | de->filename_len = 0; 926 | de->extrafield = NULL; 927 | de->extrafield_len = 0; 928 | de->comment = NULL; 929 | de->comment_len = 0; 930 | de->disk_number = 0; 931 | de->int_attrib = 0; 932 | de->ext_attrib = 0; 933 | de->offset = 0; 934 | } 935 | 936 | 937 | 938 | /* _zip_dirent_read(zde, fp, bufp, left, localp, error): 939 | Fills the zip directory entry zde. 940 | 941 | If bufp is non-NULL, data is taken from there and bufp is advanced 942 | by the amount of data used; no more than left bytes are used. 943 | Otherwise data is read from fp as needed. 944 | 945 | If localp != 0, it reads a local header instead of a central 946 | directory entry. 947 | 948 | Returns 0 if successful. On error, error is filled in and -1 is 949 | returned. 950 | */ 951 | 952 | int 953 | _zip_dirent_read(struct zip_dirent *zde, FILE *fp, 954 | unsigned char **bufp, unsigned int left, int localp, 955 | struct zip_error *error) 956 | { 957 | unsigned char buf[CDENTRYSIZE]; 958 | unsigned char *cur; 959 | unsigned short dostime, dosdate; 960 | unsigned int size; 961 | 962 | if (localp) 963 | size = LENTRYSIZE; 964 | else 965 | size = CDENTRYSIZE; 966 | 967 | if (bufp) { 968 | /* use data from buffer */ 969 | cur = *bufp; 970 | if (left < size) { 971 | _zip_error_set(error, ZIP_ER_NOZIP, 0); 972 | return -1; 973 | } 974 | } 975 | else { 976 | /* read entry from disk */ 977 | if ((fread(buf, 1, size, fp)version_madeby = _zip_read2(&cur); 996 | else 997 | zde->version_madeby = 0; 998 | zde->version_needed = _zip_read2(&cur); 999 | zde->bitflags = _zip_read2(&cur); 1000 | zde->comp_method = _zip_read2(&cur); 1001 | 1002 | /* convert to time_t */ 1003 | dostime = _zip_read2(&cur); 1004 | dosdate = _zip_read2(&cur); 1005 | zde->last_mod = _zip_d2u_time(dostime, dosdate); 1006 | 1007 | zde->crc = _zip_read4(&cur); 1008 | zde->comp_size = _zip_read4(&cur); 1009 | zde->uncomp_size = _zip_read4(&cur); 1010 | 1011 | zde->filename_len = _zip_read2(&cur); 1012 | zde->extrafield_len = _zip_read2(&cur); 1013 | 1014 | if (localp) { 1015 | zde->comment_len = 0; 1016 | zde->disk_number = 0; 1017 | zde->int_attrib = 0; 1018 | zde->ext_attrib = 0; 1019 | zde->offset = 0; 1020 | } else { 1021 | zde->comment_len = _zip_read2(&cur); 1022 | zde->disk_number = _zip_read2(&cur); 1023 | zde->int_attrib = _zip_read2(&cur); 1024 | zde->ext_attrib = _zip_read4(&cur); 1025 | zde->offset = _zip_read4(&cur); 1026 | } 1027 | 1028 | zde->filename = NULL; 1029 | zde->extrafield = NULL; 1030 | zde->comment = NULL; 1031 | 1032 | if (bufp) { 1033 | if (left < CDENTRYSIZE + (zde->filename_len+zde->extrafield_len 1034 | +zde->comment_len)) { 1035 | _zip_error_set(error, ZIP_ER_NOZIP, 0); 1036 | return -1; 1037 | } 1038 | 1039 | if (zde->filename_len) { 1040 | zde->filename = _zip_readstr(&cur, zde->filename_len, 1, error); 1041 | if (!zde->filename) 1042 | return -1; 1043 | } 1044 | 1045 | if (zde->extrafield_len) { 1046 | zde->extrafield = _zip_readstr(&cur, zde->extrafield_len, 0, 1047 | error); 1048 | if (!zde->extrafield) 1049 | return -1; 1050 | } 1051 | 1052 | if (zde->comment_len) { 1053 | zde->comment = _zip_readstr(&cur, zde->comment_len, 0, error); 1054 | if (!zde->comment) 1055 | return -1; 1056 | } 1057 | } 1058 | else { 1059 | if (zde->filename_len) { 1060 | zde->filename = _zip_readfpstr(fp, zde->filename_len, 1, error); 1061 | if (!zde->filename) 1062 | return -1; 1063 | } 1064 | 1065 | if (zde->extrafield_len) { 1066 | zde->extrafield = _zip_readfpstr(fp, zde->extrafield_len, 0, 1067 | error); 1068 | if (!zde->extrafield) 1069 | return -1; 1070 | } 1071 | 1072 | if (zde->comment_len) { 1073 | zde->comment = _zip_readfpstr(fp, zde->comment_len, 0, error); 1074 | if (!zde->comment) 1075 | return -1; 1076 | } 1077 | } 1078 | 1079 | if (bufp) 1080 | *bufp = cur; 1081 | 1082 | return 0; 1083 | } 1084 | 1085 | 1086 | 1087 | /* _zip_dirent_torrent_normalize(de); 1088 | Set values suitable for torrentzip. 1089 | */ 1090 | 1091 | void 1092 | _zip_dirent_torrent_normalize(struct zip_dirent *de) 1093 | { 1094 | static struct tm torrenttime; 1095 | static time_t last_mod = 0; 1096 | 1097 | if (last_mod == 0) { 1098 | #ifdef HAVE_STRUCT_TM_TM_ZONE 1099 | time_t now; 1100 | struct tm *l; 1101 | #endif 1102 | 1103 | torrenttime.tm_sec = 0; 1104 | torrenttime.tm_min = 32; 1105 | torrenttime.tm_hour = 23; 1106 | torrenttime.tm_mday = 24; 1107 | torrenttime.tm_mon = 11; 1108 | torrenttime.tm_year = 96; 1109 | torrenttime.tm_wday = 0; 1110 | torrenttime.tm_yday = 0; 1111 | torrenttime.tm_isdst = 0; 1112 | 1113 | #ifdef HAVE_STRUCT_TM_TM_ZONE 1114 | time(&now); 1115 | l = localtime(&now); 1116 | torrenttime.tm_gmtoff = l->tm_gmtoff; 1117 | torrenttime.tm_zone = l->tm_zone; 1118 | #endif 1119 | 1120 | last_mod = mktime(&torrenttime); 1121 | } 1122 | 1123 | de->version_madeby = 0; 1124 | de->version_needed = 20; /* 2.0 */ 1125 | de->bitflags = 2; /* maximum compression */ 1126 | de->comp_method = ZIP_CM_DEFLATE; 1127 | de->last_mod = last_mod; 1128 | 1129 | de->disk_number = 0; 1130 | de->int_attrib = 0; 1131 | de->ext_attrib = 0; 1132 | de->offset = 0; 1133 | 1134 | free(de->extrafield); 1135 | de->extrafield = NULL; 1136 | de->extrafield_len = 0; 1137 | free(de->comment); 1138 | de->comment = NULL; 1139 | de->comment_len = 0; 1140 | } 1141 | 1142 | 1143 | 1144 | /* _zip_dirent_write(zde, fp, localp, error): 1145 | Writes zip directory entry zde to file fp. 1146 | 1147 | If localp != 0, it writes a local header instead of a central 1148 | directory entry. 1149 | 1150 | Returns 0 if successful. On error, error is filled in and -1 is 1151 | returned. 1152 | */ 1153 | 1154 | int 1155 | _zip_dirent_write(struct zip_dirent *zde, FILE *fp, int localp, 1156 | struct zip_error *error) 1157 | { 1158 | unsigned short dostime, dosdate; 1159 | 1160 | fwrite(localp ? LOCAL_MAGIC : CENTRAL_MAGIC, 1, 4, fp); 1161 | 1162 | if (!localp) 1163 | _zip_write2(zde->version_madeby, fp); 1164 | _zip_write2(zde->version_needed, fp); 1165 | _zip_write2(zde->bitflags, fp); 1166 | _zip_write2(zde->comp_method, fp); 1167 | 1168 | _zip_u2d_time(zde->last_mod, &dostime, &dosdate); 1169 | _zip_write2(dostime, fp); 1170 | _zip_write2(dosdate, fp); 1171 | 1172 | _zip_write4(zde->crc, fp); 1173 | _zip_write4(zde->comp_size, fp); 1174 | _zip_write4(zde->uncomp_size, fp); 1175 | 1176 | _zip_write2(zde->filename_len, fp); 1177 | _zip_write2(zde->extrafield_len, fp); 1178 | 1179 | if (!localp) { 1180 | _zip_write2(zde->comment_len, fp); 1181 | _zip_write2(zde->disk_number, fp); 1182 | _zip_write2(zde->int_attrib, fp); 1183 | _zip_write4(zde->ext_attrib, fp); 1184 | _zip_write4(zde->offset, fp); 1185 | } 1186 | 1187 | if (zde->filename_len) 1188 | fwrite(zde->filename, 1, zde->filename_len, fp); 1189 | 1190 | if (zde->extrafield_len) 1191 | fwrite(zde->extrafield, 1, zde->extrafield_len, fp); 1192 | 1193 | if (!localp) { 1194 | if (zde->comment_len) 1195 | fwrite(zde->comment, 1, zde->comment_len, fp); 1196 | } 1197 | 1198 | if (ferror(fp)) { 1199 | _zip_error_set(error, ZIP_ER_WRITE, errno); 1200 | return -1; 1201 | } 1202 | 1203 | return 0; 1204 | } 1205 | 1206 | 1207 | 1208 | static time_t 1209 | _zip_d2u_time(int dtime, int ddate) 1210 | { 1211 | struct tm *tm; 1212 | time_t now; 1213 | 1214 | now = time(NULL); 1215 | tm = localtime(&now); 1216 | /* let mktime decide if DST is in effect */ 1217 | tm->tm_isdst = -1; 1218 | 1219 | tm->tm_year = ((ddate>>9)&127) + 1980 - 1900; 1220 | tm->tm_mon = ((ddate>>5)&15) - 1; 1221 | tm->tm_mday = ddate&31; 1222 | 1223 | tm->tm_hour = (dtime>>11)&31; 1224 | tm->tm_min = (dtime>>5)&63; 1225 | tm->tm_sec = (dtime<<1)&62; 1226 | 1227 | return mktime(tm); 1228 | } 1229 | 1230 | 1231 | 1232 | unsigned short 1233 | _zip_read2(unsigned char **a) 1234 | { 1235 | unsigned short ret; 1236 | 1237 | ret = (*a)[0]+((*a)[1]<<8); 1238 | *a += 2; 1239 | 1240 | return ret; 1241 | } 1242 | 1243 | 1244 | 1245 | unsigned int 1246 | _zip_read4(unsigned char **a) 1247 | { 1248 | unsigned int ret; 1249 | 1250 | ret = ((((((*a)[3]<<8)+(*a)[2])<<8)+(*a)[1])<<8)+(*a)[0]; 1251 | *a += 4; 1252 | 1253 | return ret; 1254 | } 1255 | 1256 | 1257 | 1258 | static char * 1259 | _zip_readfpstr(FILE *fp, unsigned int len, int nulp, struct zip_error *error) 1260 | { 1261 | char *r, *o; 1262 | 1263 | r = (char *)malloc(nulp ? len+1 : len); 1264 | if (!r) { 1265 | _zip_error_set(error, ZIP_ER_MEMORY, 0); 1266 | return NULL; 1267 | } 1268 | 1269 | if (fread(r, 1, len, fp)>8)&0xff, fp); 1320 | 1321 | return; 1322 | } 1323 | 1324 | 1325 | 1326 | static void 1327 | _zip_write4(unsigned int i, FILE *fp) 1328 | { 1329 | putc(i&0xff, fp); 1330 | putc((i>>8)&0xff, fp); 1331 | putc((i>>16)&0xff, fp); 1332 | putc((i>>24)&0xff, fp); 1333 | 1334 | return; 1335 | } 1336 | 1337 | 1338 | 1339 | static void 1340 | _zip_u2d_time(time_t time, unsigned short *dtime, unsigned short *ddate) 1341 | { 1342 | struct tm *tm; 1343 | 1344 | tm = localtime(&time); 1345 | *ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) 1346 | + tm->tm_mday; 1347 | *dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) 1348 | + ((tm->tm_sec)>>1); 1349 | 1350 | return; 1351 | } 1352 | 1353 | 1354 | 1355 | ZIP_EXTERN int 1356 | zip_delete(struct zip *za, int idx) 1357 | { 1358 | if (idx < 0 || idx >= za->nentry) { 1359 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 1360 | return -1; 1361 | } 1362 | 1363 | /* allow duplicate file names, because the file will 1364 | * be removed directly afterwards */ 1365 | if (_zip_unchange(za, idx, 1) != 0) 1366 | return -1; 1367 | 1368 | za->entry[idx].state = ZIP_ST_DELETED; 1369 | 1370 | return 0; 1371 | } 1372 | 1373 | 1374 | 1375 | ZIP_EXTERN void 1376 | zip_error_clear(struct zip *za) 1377 | { 1378 | _zip_error_clear(&za->error); 1379 | } 1380 | 1381 | 1382 | ZIP_EXTERN int 1383 | zip_add(struct zip *za, const char *name, struct zip_source *source) 1384 | { 1385 | if (name == NULL || source == NULL) { 1386 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 1387 | return -1; 1388 | } 1389 | 1390 | return _zip_replace(za, -1, name, source); 1391 | } 1392 | 1393 | 1394 | ZIP_EXTERN int 1395 | zip_error_get_sys_type(int ze) 1396 | { 1397 | if (ze < 0 || ze >= _zip_nerr_str) 1398 | return 0; 1399 | 1400 | return _zip_err_type[ze]; 1401 | } 1402 | 1403 | 1404 | ZIP_EXTERN void 1405 | zip_error_get(struct zip *za, int *zep, int *sep) 1406 | { 1407 | _zip_error_get(&za->error, zep, sep); 1408 | } 1409 | 1410 | 1411 | const char * const _zip_err_str[] = { 1412 | "No error", 1413 | "Multi-disk zip archives not supported", 1414 | "Renaming temporary file failed", 1415 | "Closing zip archive failed", 1416 | "Seek error", 1417 | "Read error", 1418 | "Write error", 1419 | "CRC error", 1420 | "Containing zip archive was closed", 1421 | "No such file", 1422 | "File already exists", 1423 | "Can't open file", 1424 | "Failure to create temporary file", 1425 | "Zlib error", 1426 | "Malloc failure", 1427 | "Entry has been changed", 1428 | "Compression method not supported", 1429 | "Premature EOF", 1430 | "Invalid argument", 1431 | "Not a zip archive", 1432 | "Internal error", 1433 | "Zip archive inconsistent", 1434 | "Can't remove file", 1435 | "Entry has been deleted", 1436 | }; 1437 | 1438 | const int _zip_nerr_str = sizeof(_zip_err_str)/sizeof(_zip_err_str[0]); 1439 | 1440 | #define N ZIP_ET_NONE 1441 | #define S ZIP_ET_SYS 1442 | #define Z ZIP_ET_ZLIB 1443 | 1444 | const int _zip_err_type[] = { 1445 | N, 1446 | N, 1447 | S, 1448 | S, 1449 | S, 1450 | S, 1451 | S, 1452 | N, 1453 | N, 1454 | N, 1455 | N, 1456 | S, 1457 | S, 1458 | Z, 1459 | N, 1460 | N, 1461 | N, 1462 | N, 1463 | N, 1464 | N, 1465 | N, 1466 | N, 1467 | S, 1468 | N, 1469 | }; 1470 | 1471 | 1472 | struct zip_entry * 1473 | _zip_entry_new(struct zip *za) 1474 | { 1475 | struct zip_entry *ze; 1476 | if (!za) { 1477 | ze = (struct zip_entry *)malloc(sizeof(struct zip_entry)); 1478 | if (!ze) { 1479 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 1480 | return NULL; 1481 | } 1482 | } 1483 | else { 1484 | if (za->nentry >= za->nentry_alloc-1) { 1485 | za->nentry_alloc += 16; 1486 | za->entry = (struct zip_entry *)realloc(za->entry, 1487 | sizeof(struct zip_entry) 1488 | * za->nentry_alloc); 1489 | if (!za->entry) { 1490 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 1491 | return NULL; 1492 | } 1493 | } 1494 | ze = za->entry+za->nentry; 1495 | } 1496 | 1497 | ze->state = ZIP_ST_UNCHANGED; 1498 | 1499 | ze->ch_filename = NULL; 1500 | ze->ch_comment = NULL; 1501 | ze->ch_comment_len = -1; 1502 | ze->source = NULL; 1503 | 1504 | if (za) 1505 | za->nentry++; 1506 | 1507 | return ze; 1508 | } 1509 | 1510 | 1511 | void 1512 | _zip_entry_free(struct zip_entry *ze) 1513 | { 1514 | free(ze->ch_filename); 1515 | ze->ch_filename = NULL; 1516 | free(ze->ch_comment); 1517 | ze->ch_comment = NULL; 1518 | ze->ch_comment_len = -1; 1519 | 1520 | _zip_unchange_data(ze); 1521 | } 1522 | 1523 | 1524 | static int add_data(struct zip *, struct zip_source *, struct zip_dirent *, 1525 | FILE *); 1526 | static int add_data_comp(zip_source_callback, void *, struct zip_stat *, 1527 | FILE *, struct zip_error *); 1528 | static int add_data_uncomp(struct zip *, zip_source_callback, void *, 1529 | struct zip_stat *, FILE *); 1530 | static void ch_set_error(struct zip_error *, zip_source_callback, void *); 1531 | static int copy_data(FILE *, myoff_t, FILE *, struct zip_error *); 1532 | static int write_cdir(struct zip *, struct zip_cdir *, FILE *); 1533 | static int _zip_cdir_set_comment(struct zip_cdir *, struct zip *); 1534 | static int _zip_changed(struct zip *, int *); 1535 | static char *_zip_create_temp_output(struct zip *, FILE **); 1536 | static int _zip_torrentzip_cmp(const void *, const void *); 1537 | 1538 | 1539 | 1540 | struct filelist { 1541 | int idx; 1542 | const char *name; 1543 | }; 1544 | 1545 | 1546 | 1547 | ZIP_EXTERN int 1548 | zip_close(struct zip *za) 1549 | { 1550 | int survivors; 1551 | int i, j, error; 1552 | char *temp; 1553 | FILE *out; 1554 | mode_t mask; 1555 | struct zip_cdir *cd; 1556 | struct zip_dirent de; 1557 | struct filelist *filelist; 1558 | int reopen_on_error; 1559 | int new_torrentzip; 1560 | 1561 | reopen_on_error = 0; 1562 | 1563 | if (za == NULL) 1564 | return -1; 1565 | 1566 | if (!_zip_changed(za, &survivors)) { 1567 | _zip_free(za); 1568 | return 0; 1569 | } 1570 | 1571 | /* don't create zip files with no entries */ 1572 | if (survivors == 0) { 1573 | if (za->zn && za->zp) { 1574 | if (remove(za->zn) != 0) { 1575 | _zip_error_set(&za->error, ZIP_ER_REMOVE, errno); 1576 | return -1; 1577 | } 1578 | } 1579 | _zip_free(za); 1580 | return 0; 1581 | } 1582 | 1583 | if ((filelist=(struct filelist *)malloc(sizeof(filelist[0])*survivors)) 1584 | == NULL) 1585 | return -1; 1586 | 1587 | if ((cd=_zip_cdir_new(survivors, &za->error)) == NULL) { 1588 | free(filelist); 1589 | return -1; 1590 | } 1591 | 1592 | for (i=0; ientry[i]); 1594 | 1595 | /* archive comment is special for torrentzip */ 1596 | if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) { 1597 | cd->comment = _zip_memdup(TORRENT_SIG "XXXXXXXX", 1598 | TORRENT_SIG_LEN + TORRENT_CRC_LEN, 1599 | &za->error); 1600 | if (cd->comment == NULL) { 1601 | _zip_cdir_free(cd); 1602 | free(filelist); 1603 | return -1; 1604 | } 1605 | cd->comment_len = TORRENT_SIG_LEN + TORRENT_CRC_LEN; 1606 | } 1607 | else if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, ZIP_FL_UNCHANGED) == 0) { 1608 | if (_zip_cdir_set_comment(cd, za) == -1) { 1609 | _zip_cdir_free(cd); 1610 | free(filelist); 1611 | return -1; 1612 | } 1613 | } 1614 | 1615 | if ((temp=_zip_create_temp_output(za, &out)) == NULL) { 1616 | _zip_cdir_free(cd); 1617 | return -1; 1618 | } 1619 | 1620 | 1621 | /* create list of files with index into original archive */ 1622 | for (i=j=0; inentry; i++) { 1623 | if (za->entry[i].state == ZIP_ST_DELETED) 1624 | continue; 1625 | 1626 | filelist[j].idx = i; 1627 | filelist[j].name = zip_get_name(za, i, 0); 1628 | j++; 1629 | } 1630 | if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) 1631 | qsort(filelist, survivors, sizeof(filelist[0]), 1632 | _zip_torrentzip_cmp); 1633 | 1634 | new_torrentzip = (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 1 1635 | && zip_get_archive_flag(za, ZIP_AFL_TORRENT, 1636 | ZIP_FL_UNCHANGED) == 0); 1637 | error = 0; 1638 | for (j=0; jentry+i) || new_torrentzip) { 1643 | _zip_dirent_init(&de); 1644 | 1645 | if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) 1646 | _zip_dirent_torrent_normalize(&de); 1647 | 1648 | /* use it as central directory entry */ 1649 | memcpy(cd->entry+j, &de, sizeof(cd->entry[j])); 1650 | 1651 | /* set/update file name */ 1652 | if (za->entry[i].ch_filename == NULL) { 1653 | if (za->entry[i].state == ZIP_ST_ADDED) { 1654 | de.filename = strdup("-"); 1655 | de.filename_len = 1; 1656 | cd->entry[j].filename = "-"; 1657 | } 1658 | else { 1659 | de.filename = strdup(za->cdir->entry[i].filename); 1660 | de.filename_len = strlen(de.filename); 1661 | cd->entry[j].filename = za->cdir->entry[i].filename; 1662 | cd->entry[j].filename_len = de.filename_len; 1663 | } 1664 | } 1665 | } 1666 | else { 1667 | /* copy existing directory entries */ 1668 | if (fseeko(za->zp, za->cdir->entry[i].offset, SEEK_SET) != 0) { 1669 | _zip_error_set(&za->error, ZIP_ER_SEEK, errno); 1670 | error = 1; 1671 | break; 1672 | } 1673 | if (_zip_dirent_read(&de, za->zp, NULL, 0, 1, &za->error) != 0) { 1674 | error = 1; 1675 | break; 1676 | } 1677 | if (de.bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { 1678 | de.crc = za->cdir->entry[i].crc; 1679 | de.comp_size = za->cdir->entry[i].comp_size; 1680 | de.uncomp_size = za->cdir->entry[i].uncomp_size; 1681 | de.bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR; 1682 | } 1683 | memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[j])); 1684 | } 1685 | 1686 | if (za->entry[i].ch_filename) { 1687 | free(de.filename); 1688 | if ((de.filename=strdup(za->entry[i].ch_filename)) == NULL) { 1689 | error = 1; 1690 | break; 1691 | } 1692 | de.filename_len = strlen(de.filename); 1693 | cd->entry[j].filename = za->entry[i].ch_filename; 1694 | cd->entry[j].filename_len = de.filename_len; 1695 | } 1696 | 1697 | if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0 1698 | && za->entry[i].ch_comment_len != -1) { 1699 | /* as the rest of cd entries, its malloc/free is done by za */ 1700 | cd->entry[j].comment = za->entry[i].ch_comment; 1701 | cd->entry[j].comment_len = za->entry[i].ch_comment_len; 1702 | } 1703 | 1704 | cd->entry[j].offset = ftello(out); 1705 | 1706 | if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) { 1707 | struct zip_source *zs; 1708 | 1709 | zs = NULL; 1710 | if (!ZIP_ENTRY_DATA_CHANGED(za->entry+i)) { 1711 | if ((zs=zip_source_zip(za, za, i, ZIP_FL_RECOMPRESS, 0, -1)) 1712 | == NULL) { 1713 | error = 1; 1714 | break; 1715 | } 1716 | } 1717 | 1718 | if (add_data(za, zs ? zs : za->entry[i].source, &de, out) < 0) { 1719 | error = 1; 1720 | break; 1721 | } 1722 | cd->entry[j].last_mod = de.last_mod; 1723 | cd->entry[j].comp_method = de.comp_method; 1724 | cd->entry[j].comp_size = de.comp_size; 1725 | cd->entry[j].uncomp_size = de.uncomp_size; 1726 | cd->entry[j].crc = de.crc; 1727 | } 1728 | else { 1729 | if (_zip_dirent_write(&de, out, 1, &za->error) < 0) { 1730 | error = 1; 1731 | break; 1732 | } 1733 | /* we just read the local dirent, file is at correct position */ 1734 | if (copy_data(za->zp, cd->entry[j].comp_size, out, 1735 | &za->error) < 0) { 1736 | error = 1; 1737 | break; 1738 | } 1739 | } 1740 | 1741 | _zip_dirent_finalize(&de); 1742 | } 1743 | 1744 | if (!error) { 1745 | if (write_cdir(za, cd, out) < 0) 1746 | error = 1; 1747 | } 1748 | 1749 | /* pointers in cd entries are owned by za */ 1750 | cd->nentry = 0; 1751 | _zip_cdir_free(cd); 1752 | 1753 | if (error) { 1754 | _zip_dirent_finalize(&de); 1755 | fclose(out); 1756 | remove(temp); 1757 | free(temp); 1758 | return -1; 1759 | } 1760 | 1761 | if (fclose(out) != 0) { 1762 | _zip_error_set(&za->error, ZIP_ER_CLOSE, errno); 1763 | remove(temp); 1764 | free(temp); 1765 | return -1; 1766 | } 1767 | 1768 | if (za->zp) { 1769 | fclose(za->zp); 1770 | za->zp = NULL; 1771 | reopen_on_error = 1; 1772 | } 1773 | if (_zip_rename(temp, za->zn) != 0) { 1774 | _zip_error_set(&za->error, ZIP_ER_RENAME, errno); 1775 | remove(temp); 1776 | free(temp); 1777 | if (reopen_on_error) { 1778 | /* ignore errors, since we're already in an error case */ 1779 | za->zp = fopen(za->zn, "rb"); 1780 | } 1781 | return -1; 1782 | } 1783 | mask = umask(0); 1784 | umask(mask); 1785 | chmod(za->zn, 0666&~mask); 1786 | 1787 | _zip_free(za); 1788 | free(temp); 1789 | 1790 | return 0; 1791 | } 1792 | 1793 | 1794 | 1795 | static int 1796 | add_data(struct zip *za, struct zip_source *zs, struct zip_dirent *de, FILE *ft) 1797 | { 1798 | myoff_t offstart, offend; 1799 | zip_source_callback cb; 1800 | void *ud; 1801 | struct zip_stat st; 1802 | 1803 | cb = zs->f; 1804 | ud = zs->ud; 1805 | 1806 | if (cb(ud, &st, sizeof(st), ZIP_SOURCE_STAT) < (ssize_t)sizeof(st)) { 1807 | ch_set_error(&za->error, cb, ud); 1808 | return -1; 1809 | } 1810 | 1811 | if (cb(ud, NULL, 0, ZIP_SOURCE_OPEN) < 0) { 1812 | ch_set_error(&za->error, cb, ud); 1813 | return -1; 1814 | } 1815 | 1816 | offstart = ftello(ft); 1817 | 1818 | if (_zip_dirent_write(de, ft, 1, &za->error) < 0) 1819 | return -1; 1820 | 1821 | if (st.comp_method != ZIP_CM_STORE) { 1822 | if (add_data_comp(cb, ud, &st, ft, &za->error) < 0) 1823 | return -1; 1824 | } 1825 | else { 1826 | if (add_data_uncomp(za, cb, ud, &st, ft) < 0) 1827 | return -1; 1828 | } 1829 | 1830 | if (cb(ud, NULL, 0, ZIP_SOURCE_CLOSE) < 0) { 1831 | ch_set_error(&za->error, cb, ud); 1832 | return -1; 1833 | } 1834 | 1835 | offend = ftello(ft); 1836 | 1837 | if (fseeko(ft, offstart, SEEK_SET) < 0) { 1838 | _zip_error_set(&za->error, ZIP_ER_SEEK, errno); 1839 | return -1; 1840 | } 1841 | 1842 | 1843 | de->last_mod = st.mtime; 1844 | de->comp_method = st.comp_method; 1845 | de->crc = st.crc; 1846 | de->uncomp_size = st.size; 1847 | de->comp_size = st.comp_size; 1848 | 1849 | if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) 1850 | _zip_dirent_torrent_normalize(de); 1851 | 1852 | if (_zip_dirent_write(de, ft, 1, &za->error) < 0) 1853 | return -1; 1854 | 1855 | if (fseeko(ft, offend, SEEK_SET) < 0) { 1856 | _zip_error_set(&za->error, ZIP_ER_SEEK, errno); 1857 | return -1; 1858 | } 1859 | 1860 | return 0; 1861 | } 1862 | 1863 | 1864 | 1865 | static int 1866 | add_data_comp(zip_source_callback cb, void *ud, struct zip_stat *st,FILE *ft, 1867 | struct zip_error *error) 1868 | { 1869 | char buf[BUFSIZE]; 1870 | ssize_t n; 1871 | 1872 | st->comp_size = 0; 1873 | while ((n=cb(ud, buf, sizeof(buf), ZIP_SOURCE_READ)) > 0) { 1874 | if (fwrite(buf, 1, n, ft) != (size_t)n) { 1875 | _zip_error_set(error, ZIP_ER_WRITE, errno); 1876 | return -1; 1877 | } 1878 | 1879 | st->comp_size += n; 1880 | } 1881 | if (n < 0) { 1882 | ch_set_error(error, cb, ud); 1883 | return -1; 1884 | } 1885 | 1886 | return 0; 1887 | } 1888 | 1889 | 1890 | 1891 | static int 1892 | add_data_uncomp(struct zip *za, zip_source_callback cb, void *ud, 1893 | struct zip_stat *st, FILE *ft) 1894 | { 1895 | char b1[BUFSIZE], b2[BUFSIZE]; 1896 | int end, flush, ret; 1897 | ssize_t n; 1898 | size_t n2; 1899 | z_stream zstr; 1900 | int mem_level; 1901 | 1902 | st->comp_method = ZIP_CM_DEFLATE; 1903 | st->comp_size = st->size = 0; 1904 | st->crc = crc32(0, NULL, 0); 1905 | 1906 | zstr.zalloc = Z_NULL; 1907 | zstr.zfree = Z_NULL; 1908 | zstr.opaque = NULL; 1909 | zstr.avail_in = 0; 1910 | zstr.avail_out = 0; 1911 | 1912 | if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) 1913 | mem_level = TORRENT_MEM_LEVEL; 1914 | else 1915 | mem_level = MAX_MEM_LEVEL; 1916 | 1917 | /* -MAX_WBITS: undocumented feature of zlib to _not_ write a zlib header */ 1918 | deflateInit2(&zstr, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, mem_level, 1919 | Z_DEFAULT_STRATEGY); 1920 | 1921 | zstr.next_out = (Bytef *)b2; 1922 | zstr.avail_out = sizeof(b2); 1923 | zstr.avail_in = 0; 1924 | 1925 | flush = 0; 1926 | end = 0; 1927 | while (!end) { 1928 | if (zstr.avail_in == 0 && !flush) { 1929 | if ((n=cb(ud, b1, sizeof(b1), ZIP_SOURCE_READ)) < 0) { 1930 | ch_set_error(&za->error, cb, ud); 1931 | deflateEnd(&zstr); 1932 | return -1; 1933 | } 1934 | if (n > 0) { 1935 | zstr.avail_in = n; 1936 | zstr.next_in = (Bytef *)b1; 1937 | st->size += n; 1938 | st->crc = crc32(st->crc, (Bytef *)b1, n); 1939 | } 1940 | else 1941 | flush = Z_FINISH; 1942 | } 1943 | 1944 | ret = deflate(&zstr, flush); 1945 | if (ret != Z_OK && ret != Z_STREAM_END) { 1946 | _zip_error_set(&za->error, ZIP_ER_ZLIB, ret); 1947 | return -1; 1948 | } 1949 | 1950 | if (zstr.avail_out != sizeof(b2)) { 1951 | n2 = sizeof(b2) - zstr.avail_out; 1952 | 1953 | if (fwrite(b2, 1, n2, ft) != n2) { 1954 | _zip_error_set(&za->error, ZIP_ER_WRITE, errno); 1955 | return -1; 1956 | } 1957 | 1958 | zstr.next_out = (Bytef *)b2; 1959 | zstr.avail_out = sizeof(b2); 1960 | st->comp_size += n2; 1961 | } 1962 | 1963 | if (ret == Z_STREAM_END) { 1964 | deflateEnd(&zstr); 1965 | end = 1; 1966 | } 1967 | } 1968 | 1969 | return 0; 1970 | } 1971 | 1972 | 1973 | 1974 | static void 1975 | ch_set_error(struct zip_error *error, zip_source_callback cb, void *ud) 1976 | { 1977 | int e[2]; 1978 | 1979 | if ((cb(ud, e, sizeof(e), ZIP_SOURCE_ERROR)) < (ssize_t)sizeof(e)) { 1980 | error->zip_err = ZIP_ER_INTERNAL; 1981 | error->sys_err = 0; 1982 | } 1983 | else { 1984 | error->zip_err = e[0]; 1985 | error->sys_err = e[1]; 1986 | } 1987 | } 1988 | 1989 | 1990 | 1991 | static int 1992 | copy_data(FILE *fs, myoff_t len, FILE *ft, struct zip_error *error) 1993 | { 1994 | char buf[BUFSIZE]; 1995 | int n, nn; 1996 | 1997 | if (len == 0) 1998 | return 0; 1999 | 2000 | while (len > 0) { 2001 | nn = len > sizeof(buf) ? sizeof(buf) : len; 2002 | if ((n=fread(buf, 1, nn, fs)) < 0) { 2003 | _zip_error_set(error, ZIP_ER_READ, errno); 2004 | return -1; 2005 | } 2006 | else if (n == 0) { 2007 | _zip_error_set(error, ZIP_ER_EOF, 0); 2008 | return -1; 2009 | } 2010 | 2011 | if (fwrite(buf, 1, n, ft) != (size_t)n) { 2012 | _zip_error_set(error, ZIP_ER_WRITE, errno); 2013 | return -1; 2014 | } 2015 | 2016 | len -= n; 2017 | } 2018 | 2019 | return 0; 2020 | } 2021 | 2022 | 2023 | 2024 | static int 2025 | write_cdir(struct zip *za, struct zip_cdir *cd, FILE *out) 2026 | { 2027 | myoff_t offset; 2028 | uLong crc; 2029 | char buf[TORRENT_CRC_LEN+1]; 2030 | 2031 | if (_zip_cdir_write(cd, out, &za->error) < 0) 2032 | return -1; 2033 | 2034 | if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0) 2035 | return 0; 2036 | 2037 | 2038 | /* fix up torrentzip comment */ 2039 | 2040 | offset = ftello(out); 2041 | 2042 | if (_zip_filerange_crc(out, cd->offset, cd->size, &crc, &za->error) < 0) 2043 | return -1; 2044 | 2045 | snprintf(buf, sizeof(buf), "%08lX", (long)crc); 2046 | 2047 | if (fseeko(out, offset-TORRENT_CRC_LEN, SEEK_SET) < 0) { 2048 | _zip_error_set(&za->error, ZIP_ER_SEEK, errno); 2049 | return -1; 2050 | } 2051 | 2052 | if (fwrite(buf, TORRENT_CRC_LEN, 1, out) != 1) { 2053 | _zip_error_set(&za->error, ZIP_ER_WRITE, errno); 2054 | return -1; 2055 | } 2056 | 2057 | return 0; 2058 | } 2059 | 2060 | 2061 | 2062 | static int 2063 | _zip_cdir_set_comment(struct zip_cdir *dest, struct zip *src) 2064 | { 2065 | if (src->ch_comment_len != -1) { 2066 | dest->comment = _zip_memdup(src->ch_comment, 2067 | src->ch_comment_len, &src->error); 2068 | if (dest->comment == NULL) 2069 | return -1; 2070 | dest->comment_len = src->ch_comment_len; 2071 | } else { 2072 | if (src->cdir && src->cdir->comment) { 2073 | dest->comment = _zip_memdup(src->cdir->comment, 2074 | src->cdir->comment_len, &src->error); 2075 | if (dest->comment == NULL) 2076 | return -1; 2077 | dest->comment_len = src->cdir->comment_len; 2078 | } 2079 | } 2080 | 2081 | return 0; 2082 | } 2083 | 2084 | 2085 | 2086 | static int 2087 | _zip_changed(struct zip *za, int *survivorsp) 2088 | { 2089 | int changed, i, survivors; 2090 | 2091 | changed = survivors = 0; 2092 | 2093 | if (za->ch_comment_len != -1 2094 | || za->ch_flags != za->flags) 2095 | changed = 1; 2096 | 2097 | for (i=0; inentry; i++) { 2098 | if ((za->entry[i].state != ZIP_ST_UNCHANGED) 2099 | || (za->entry[i].ch_comment_len != -1)) 2100 | changed = 1; 2101 | if (za->entry[i].state != ZIP_ST_DELETED) 2102 | survivors++; 2103 | } 2104 | 2105 | *survivorsp = survivors; 2106 | 2107 | return changed; 2108 | } 2109 | 2110 | 2111 | 2112 | static char * 2113 | _zip_create_temp_output(struct zip *za, FILE **outp) 2114 | { 2115 | char *temp; 2116 | int tfd; 2117 | FILE *tfp; 2118 | 2119 | if ((temp=(char *)malloc(strlen(za->zn)+8)) == NULL) { 2120 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 2121 | return NULL; 2122 | } 2123 | 2124 | sprintf(temp, "%s.XXXXXX", za->zn); 2125 | 2126 | if ((tfd=mkstemp(temp)) == -1) { 2127 | _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno); 2128 | free(temp); 2129 | return NULL; 2130 | } 2131 | 2132 | if ((tfp=fdopen(tfd, "r+b")) == NULL) { 2133 | _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno); 2134 | close(tfd); 2135 | remove(temp); 2136 | free(temp); 2137 | return NULL; 2138 | } 2139 | 2140 | *outp = tfp; 2141 | return temp; 2142 | } 2143 | 2144 | 2145 | 2146 | static int 2147 | _zip_torrentzip_cmp(const void *a, const void *b) 2148 | { 2149 | return strcasecmp(((const struct filelist *)a)->name, 2150 | ((const struct filelist *)b)->name); 2151 | } 2152 | 2153 | 2154 | 2155 | ZIP_EXTERN int 2156 | zip_add_dir(struct zip *za, const char *name) 2157 | { 2158 | int len, ret; 2159 | char *s; 2160 | struct zip_source *source; 2161 | 2162 | if (name == NULL) { 2163 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 2164 | return -1; 2165 | } 2166 | 2167 | s = NULL; 2168 | len = strlen(name); 2169 | 2170 | if (name[len-1] != '/') { 2171 | if ((s=(char *)malloc(len+2)) == NULL) { 2172 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 2173 | return -1; 2174 | } 2175 | strcpy(s, name); 2176 | s[len] = '/'; 2177 | s[len+1] = '\0'; 2178 | } 2179 | 2180 | if ((source=zip_source_buffer(za, NULL, 0, 0)) == NULL) { 2181 | free(s); 2182 | return -1; 2183 | } 2184 | 2185 | ret = _zip_replace(za, -1, s ? s : name, source); 2186 | 2187 | free(s); 2188 | if (ret < 0) 2189 | zip_source_free(source); 2190 | 2191 | return ret; 2192 | } 2193 | 2194 | 2195 | ZIP_EXTERN int 2196 | zip_error_to_str(char *buf, size_t len, int ze, int se) 2197 | { 2198 | const char *zs, *ss; 2199 | 2200 | if (ze < 0 || ze >= _zip_nerr_str) 2201 | return snprintf(buf, len, "Unknown error %d", ze); 2202 | 2203 | zs = _zip_err_str[ze]; 2204 | 2205 | switch (_zip_err_type[ze]) { 2206 | case ZIP_ET_SYS: 2207 | ss = strerror(se); 2208 | break; 2209 | 2210 | case ZIP_ET_ZLIB: 2211 | ss = zError(se); 2212 | break; 2213 | 2214 | default: 2215 | ss = NULL; 2216 | } 2217 | 2218 | return snprintf(buf, len, "%s%s%s", 2219 | zs, (ss ? ": " : ""), (ss ? ss : "")); 2220 | } 2221 | 2222 | 2223 | ZIP_EXTERN void 2224 | zip_file_error_clear(struct zip_file *zf) 2225 | { 2226 | _zip_error_clear(&zf->error); 2227 | } 2228 | 2229 | 2230 | ZIP_EXTERN int 2231 | zip_fclose(struct zip_file *zf) 2232 | { 2233 | int i, ret; 2234 | 2235 | if (zf->zstr) 2236 | inflateEnd(zf->zstr); 2237 | free(zf->buffer); 2238 | free(zf->zstr); 2239 | 2240 | for (i=0; iza->nfile; i++) { 2241 | if (zf->za->file[i] == zf) { 2242 | zf->za->file[i] = zf->za->file[zf->za->nfile-1]; 2243 | zf->za->nfile--; 2244 | break; 2245 | } 2246 | } 2247 | 2248 | ret = 0; 2249 | if (zf->error.zip_err) 2250 | ret = zf->error.zip_err; 2251 | else if ((zf->flags & ZIP_ZF_CRC) && (zf->flags & ZIP_ZF_EOF)) { 2252 | /* if EOF, compare CRC */ 2253 | if (zf->crc_orig != zf->crc) 2254 | ret = ZIP_ER_CRC; 2255 | } 2256 | 2257 | free(zf); 2258 | return ret; 2259 | } 2260 | 2261 | 2262 | int 2263 | _zip_filerange_crc(FILE *fp, myoff_t start, myoff_t len, uLong *crcp, 2264 | struct zip_error *errp) 2265 | { 2266 | Bytef buf[BUFSIZE]; 2267 | size_t n; 2268 | 2269 | *crcp = crc32(0L, Z_NULL, 0); 2270 | 2271 | if (fseeko(fp, start, SEEK_SET) != 0) { 2272 | _zip_error_set(errp, ZIP_ER_SEEK, errno); 2273 | return -1; 2274 | } 2275 | 2276 | while (len > 0) { 2277 | n = len > BUFSIZE ? BUFSIZE : len; 2278 | if ((n=fread(buf, 1, n, fp)) <= 0) { 2279 | _zip_error_set(errp, ZIP_ER_READ, errno); 2280 | return -1; 2281 | } 2282 | 2283 | *crcp = crc32(*crcp, buf, n); 2284 | 2285 | len-= n; 2286 | } 2287 | 2288 | return 0; 2289 | } 2290 | 2291 | 2292 | ZIP_EXTERN const char * 2293 | zip_file_strerror(struct zip_file *zf) 2294 | { 2295 | return _zip_error_strerror(&zf->error); 2296 | } 2297 | 2298 | 2299 | /* _zip_file_get_offset(za, ze): 2300 | Returns the offset of the file data for entry ze. 2301 | 2302 | On error, fills in za->error and returns 0. 2303 | */ 2304 | 2305 | unsigned int 2306 | _zip_file_get_offset(struct zip *za, int idx) 2307 | { 2308 | struct zip_dirent de; 2309 | unsigned int offset; 2310 | 2311 | offset = za->cdir->entry[idx].offset; 2312 | 2313 | if (fseeko(za->zp, offset, SEEK_SET) != 0) { 2314 | _zip_error_set(&za->error, ZIP_ER_SEEK, errno); 2315 | return 0; 2316 | } 2317 | 2318 | if (_zip_dirent_read(&de, za->zp, NULL, 0, 1, &za->error) != 0) 2319 | return 0; 2320 | 2321 | offset += LENTRYSIZE + de.filename_len + de.extrafield_len; 2322 | 2323 | _zip_dirent_finalize(&de); 2324 | 2325 | return offset; 2326 | } 2327 | 2328 | 2329 | ZIP_EXTERN void 2330 | zip_file_error_get(struct zip_file *zf, int *zep, int *sep) 2331 | { 2332 | _zip_error_get(&zf->error, zep, sep); 2333 | } 2334 | 2335 | 2336 | static struct zip_file *_zip_file_new(struct zip *za); 2337 | 2338 | 2339 | 2340 | ZIP_EXTERN struct zip_file * 2341 | zip_fopen_index(struct zip *za, int fileno, int flags) 2342 | { 2343 | int len, ret; 2344 | int zfflags; 2345 | struct zip_file *zf; 2346 | 2347 | if ((fileno < 0) || (fileno >= za->nentry)) { 2348 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 2349 | return NULL; 2350 | } 2351 | 2352 | if ((flags & ZIP_FL_UNCHANGED) == 0 2353 | && ZIP_ENTRY_DATA_CHANGED(za->entry+fileno)) { 2354 | _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); 2355 | return NULL; 2356 | } 2357 | 2358 | if (fileno >= za->cdir->nentry) { 2359 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 2360 | return NULL; 2361 | } 2362 | 2363 | zfflags = 0; 2364 | switch (za->cdir->entry[fileno].comp_method) { 2365 | case ZIP_CM_STORE: 2366 | zfflags |= ZIP_ZF_CRC; 2367 | break; 2368 | 2369 | case ZIP_CM_DEFLATE: 2370 | if ((flags & ZIP_FL_COMPRESSED) == 0) 2371 | zfflags |= ZIP_ZF_CRC | ZIP_ZF_DECOMP; 2372 | break; 2373 | default: 2374 | if ((flags & ZIP_FL_COMPRESSED) == 0) { 2375 | _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); 2376 | return NULL; 2377 | } 2378 | break; 2379 | } 2380 | 2381 | zf = _zip_file_new(za); 2382 | 2383 | zf->flags = zfflags; 2384 | /* zf->name = za->cdir->entry[fileno].filename; */ 2385 | zf->method = za->cdir->entry[fileno].comp_method; 2386 | zf->bytes_left = za->cdir->entry[fileno].uncomp_size; 2387 | zf->cbytes_left = za->cdir->entry[fileno].comp_size; 2388 | zf->crc_orig = za->cdir->entry[fileno].crc; 2389 | 2390 | if ((zf->fpos=_zip_file_get_offset(za, fileno)) == 0) { 2391 | zip_fclose(zf); 2392 | return NULL; 2393 | } 2394 | 2395 | if ((zf->flags & ZIP_ZF_DECOMP) == 0) 2396 | zf->bytes_left = zf->cbytes_left; 2397 | else { 2398 | if ((zf->buffer=(char *)malloc(BUFSIZE)) == NULL) { 2399 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 2400 | zip_fclose(zf); 2401 | return NULL; 2402 | } 2403 | 2404 | len = _zip_file_fillbuf(zf->buffer, BUFSIZE, zf); 2405 | if (len <= 0) { 2406 | _zip_error_copy(&za->error, &zf->error); 2407 | zip_fclose(zf); 2408 | return NULL; 2409 | } 2410 | 2411 | if ((zf->zstr = (z_stream *)malloc(sizeof(z_stream))) == NULL) { 2412 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 2413 | zip_fclose(zf); 2414 | return NULL; 2415 | } 2416 | zf->zstr->zalloc = Z_NULL; 2417 | zf->zstr->zfree = Z_NULL; 2418 | zf->zstr->opaque = NULL; 2419 | zf->zstr->next_in = (Bytef *)zf->buffer; 2420 | zf->zstr->avail_in = len; 2421 | 2422 | /* negative value to tell zlib that there is no header */ 2423 | if ((ret=inflateInit2(zf->zstr, -MAX_WBITS)) != Z_OK) { 2424 | _zip_error_set(&za->error, ZIP_ER_ZLIB, ret); 2425 | zip_fclose(zf); 2426 | return NULL; 2427 | } 2428 | } 2429 | 2430 | return zf; 2431 | } 2432 | 2433 | 2434 | 2435 | int 2436 | _zip_file_fillbuf(void *buf, size_t buflen, struct zip_file *zf) 2437 | { 2438 | int i, j; 2439 | 2440 | if (zf->error.zip_err != ZIP_ER_OK) 2441 | return -1; 2442 | 2443 | if ((zf->flags & ZIP_ZF_EOF) || zf->cbytes_left <= 0 || buflen <= 0) 2444 | return 0; 2445 | 2446 | if (fseeko(zf->za->zp, zf->fpos, SEEK_SET) < 0) { 2447 | _zip_error_set(&zf->error, ZIP_ER_SEEK, errno); 2448 | return -1; 2449 | } 2450 | if (buflen < zf->cbytes_left) 2451 | i = buflen; 2452 | else 2453 | i = zf->cbytes_left; 2454 | 2455 | j = fread(buf, 1, i, zf->za->zp); 2456 | if (j == 0) { 2457 | _zip_error_set(&zf->error, ZIP_ER_EOF, 0); 2458 | j = -1; 2459 | } 2460 | else if (j < 0) 2461 | _zip_error_set(&zf->error, ZIP_ER_READ, errno); 2462 | else { 2463 | zf->fpos += j; 2464 | zf->cbytes_left -= j; 2465 | } 2466 | 2467 | return j; 2468 | } 2469 | 2470 | 2471 | 2472 | static struct zip_file * 2473 | _zip_file_new(struct zip *za) 2474 | { 2475 | struct zip_file *zf, **file; 2476 | int n; 2477 | 2478 | if ((zf=(struct zip_file *)malloc(sizeof(struct zip_file))) == NULL) { 2479 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 2480 | return NULL; 2481 | } 2482 | 2483 | if (za->nfile >= za->nfile_alloc-1) { 2484 | n = za->nfile_alloc + 10; 2485 | file = (struct zip_file **)realloc(za->file, 2486 | n*sizeof(struct zip_file *)); 2487 | if (file == NULL) { 2488 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 2489 | free(zf); 2490 | return NULL; 2491 | } 2492 | za->nfile_alloc = n; 2493 | za->file = file; 2494 | } 2495 | 2496 | za->file[za->nfile++] = zf; 2497 | 2498 | zf->za = za; 2499 | _zip_error_init(&zf->error); 2500 | zf->flags = 0; 2501 | zf->crc = crc32(0L, Z_NULL, 0); 2502 | zf->crc_orig = 0; 2503 | zf->method = -1; 2504 | zf->bytes_left = zf->cbytes_left = 0; 2505 | zf->fpos = 0; 2506 | zf->buffer = NULL; 2507 | zf->zstr = NULL; 2508 | 2509 | return zf; 2510 | } 2511 | 2512 | 2513 | ZIP_EXTERN struct zip_file * 2514 | zip_fopen(struct zip *za, const char *fname, int flags) 2515 | { 2516 | int idx; 2517 | 2518 | if ((idx=zip_name_locate(za, fname, flags)) < 0) 2519 | return NULL; 2520 | 2521 | return zip_fopen_index(za, idx, flags); 2522 | } 2523 | 2524 | 2525 | ZIP_EXTERN int 2526 | zip_set_file_comment(struct zip *za, int idx, const char *comment, int len) 2527 | { 2528 | char *tmpcom; 2529 | 2530 | if (idx < 0 || idx >= za->nentry 2531 | || len < 0 || len > MAXCOMLEN 2532 | || (len > 0 && comment == NULL)) { 2533 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 2534 | return -1; 2535 | } 2536 | 2537 | if (len > 0) { 2538 | if ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL) 2539 | return -1; 2540 | } 2541 | else 2542 | tmpcom = NULL; 2543 | 2544 | free(za->entry[idx].ch_comment); 2545 | za->entry[idx].ch_comment = tmpcom; 2546 | za->entry[idx].ch_comment_len = len; 2547 | 2548 | return 0; 2549 | } 2550 | 2551 | 2552 | ZIP_EXTERN struct zip_source * 2553 | zip_source_file(struct zip *za, const char *fname, myoff_t start, myoff_t len) 2554 | { 2555 | if (za == NULL) 2556 | return NULL; 2557 | 2558 | if (fname == NULL || start < 0 || len < -1) { 2559 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 2560 | return NULL; 2561 | } 2562 | 2563 | return _zip_source_file_or_p(za, fname, NULL, start, len); 2564 | } 2565 | 2566 | 2567 | struct read_data { 2568 | const char *buf, *data, *end; 2569 | time_t mtime; 2570 | int freep; 2571 | }; 2572 | 2573 | static ssize_t read_data(void *state, void *data, size_t len, 2574 | enum zip_source_cmd cmd); 2575 | 2576 | 2577 | 2578 | ZIP_EXTERN struct zip_source * 2579 | zip_source_buffer(struct zip *za, const void *data, myoff_t len, int freep) 2580 | { 2581 | struct read_data *f; 2582 | struct zip_source *zs; 2583 | 2584 | if (za == NULL) 2585 | return NULL; 2586 | 2587 | if (len < 0 || (data == NULL && len > 0)) { 2588 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 2589 | return NULL; 2590 | } 2591 | 2592 | if ((f=(struct read_data *)malloc(sizeof(*f))) == NULL) { 2593 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 2594 | return NULL; 2595 | } 2596 | 2597 | f->data = (const char *)data; 2598 | f->end = ((const char *)data)+len; 2599 | f->freep = freep; 2600 | f->mtime = time(NULL); 2601 | 2602 | if ((zs=zip_source_function(za, read_data, f)) == NULL) { 2603 | free(f); 2604 | return NULL; 2605 | } 2606 | 2607 | return zs; 2608 | } 2609 | 2610 | 2611 | 2612 | static ssize_t 2613 | read_data(void *state, void *data, size_t len, enum zip_source_cmd cmd) 2614 | { 2615 | struct read_data *z; 2616 | char *buf; 2617 | size_t n; 2618 | 2619 | z = (struct read_data *)state; 2620 | buf = (char *)data; 2621 | 2622 | switch (cmd) { 2623 | case ZIP_SOURCE_OPEN: 2624 | z->buf = z->data; 2625 | return 0; 2626 | 2627 | case ZIP_SOURCE_READ: 2628 | n = z->end - z->buf; 2629 | if (n > len) 2630 | n = len; 2631 | 2632 | if (n) { 2633 | memcpy(buf, z->buf, n); 2634 | z->buf += n; 2635 | } 2636 | 2637 | return n; 2638 | 2639 | case ZIP_SOURCE_CLOSE: 2640 | return 0; 2641 | 2642 | case ZIP_SOURCE_STAT: 2643 | { 2644 | struct zip_stat *st; 2645 | 2646 | if (len < sizeof(*st)) 2647 | return -1; 2648 | 2649 | st = (struct zip_stat *)data; 2650 | 2651 | zip_stat_init(st); 2652 | st->mtime = z->mtime; 2653 | st->size = z->end - z->data; 2654 | 2655 | return sizeof(*st); 2656 | } 2657 | 2658 | case ZIP_SOURCE_ERROR: 2659 | { 2660 | int *e; 2661 | 2662 | if (len < sizeof(int)*2) 2663 | return -1; 2664 | 2665 | e = (int *)data; 2666 | e[0] = e[1] = 0; 2667 | } 2668 | return sizeof(int)*2; 2669 | 2670 | case ZIP_SOURCE_FREE: 2671 | if (z->freep) { 2672 | free((void *)z->data); 2673 | z->data = NULL; 2674 | } 2675 | free(z); 2676 | return 0; 2677 | 2678 | default: 2679 | ; 2680 | } 2681 | 2682 | return -1; 2683 | } 2684 | 2685 | 2686 | int 2687 | _zip_set_name(struct zip *za, int idx, const char *name) 2688 | { 2689 | char *s; 2690 | int i; 2691 | 2692 | if (idx < 0 || idx >= za->nentry || name == NULL) { 2693 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 2694 | return -1; 2695 | } 2696 | 2697 | if ((i=_zip_name_locate(za, name, 0, NULL)) != -1 && i != idx) { 2698 | _zip_error_set(&za->error, ZIP_ER_EXISTS, 0); 2699 | return -1; 2700 | } 2701 | 2702 | /* no effective name change */ 2703 | if (i == idx) 2704 | return 0; 2705 | 2706 | if ((s=strdup(name)) == NULL) { 2707 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 2708 | return -1; 2709 | } 2710 | 2711 | if (za->entry[idx].state == ZIP_ST_UNCHANGED) 2712 | za->entry[idx].state = ZIP_ST_RENAMED; 2713 | 2714 | free(za->entry[idx].ch_filename); 2715 | za->entry[idx].ch_filename = s; 2716 | 2717 | return 0; 2718 | } 2719 | 2720 | 2721 | ZIP_EXTERN int 2722 | zip_set_archive_flag(struct zip *za, int flag, int value) 2723 | { 2724 | if (value) 2725 | za->ch_flags |= flag; 2726 | else 2727 | za->ch_flags &= ~flag; 2728 | 2729 | return 0; 2730 | } 2731 | 2732 | 2733 | void 2734 | _zip_unchange_data(struct zip_entry *ze) 2735 | { 2736 | if (ze->source) { 2737 | (void)ze->source->f(ze->source->ud, NULL, 0, ZIP_SOURCE_FREE); 2738 | free(ze->source); 2739 | ze->source = NULL; 2740 | } 2741 | 2742 | ze->state = ze->ch_filename ? ZIP_ST_RENAMED : ZIP_ST_UNCHANGED; 2743 | } 2744 | 2745 | 2746 | ZIP_EXTERN int 2747 | zip_unchange_archive(struct zip *za) 2748 | { 2749 | free(za->ch_comment); 2750 | za->ch_comment = NULL; 2751 | za->ch_comment_len = -1; 2752 | 2753 | za->ch_flags = za->flags; 2754 | 2755 | return 0; 2756 | } 2757 | 2758 | ZIP_EXTERN int 2759 | zip_unchange(struct zip *za, int idx) 2760 | { 2761 | return _zip_unchange(za, idx, 0); 2762 | } 2763 | 2764 | 2765 | 2766 | int 2767 | _zip_unchange(struct zip *za, int idx, int allow_duplicates) 2768 | { 2769 | int i; 2770 | 2771 | if (idx < 0 || idx >= za->nentry) { 2772 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 2773 | return -1; 2774 | } 2775 | 2776 | if (za->entry[idx].ch_filename) { 2777 | if (!allow_duplicates) { 2778 | i = _zip_name_locate(za, 2779 | _zip_get_name(za, idx, ZIP_FL_UNCHANGED, NULL), 2780 | 0, NULL); 2781 | if (i != -1 && i != idx) { 2782 | _zip_error_set(&za->error, ZIP_ER_EXISTS, 0); 2783 | return -1; 2784 | } 2785 | } 2786 | 2787 | free(za->entry[idx].ch_filename); 2788 | za->entry[idx].ch_filename = NULL; 2789 | } 2790 | 2791 | free(za->entry[idx].ch_comment); 2792 | za->entry[idx].ch_comment = NULL; 2793 | za->entry[idx].ch_comment_len = -1; 2794 | 2795 | _zip_unchange_data(za->entry+idx); 2796 | 2797 | return 0; 2798 | } 2799 | 2800 | ZIP_EXTERN int 2801 | zip_unchange_all(struct zip *za) 2802 | { 2803 | int ret, i; 2804 | 2805 | ret = 0; 2806 | for (i=0; inentry; i++) 2807 | ret |= _zip_unchange(za, i, 1); 2808 | 2809 | ret |= zip_unchange_archive(za); 2810 | 2811 | return ret; 2812 | } 2813 | 2814 | 2815 | ZIP_EXTERN int 2816 | zip_set_archive_comment(struct zip *za, const char *comment, int len) 2817 | { 2818 | char *tmpcom; 2819 | 2820 | if (len < 0 || len > MAXCOMLEN 2821 | || (len > 0 && comment == NULL)) { 2822 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 2823 | return -1; 2824 | } 2825 | 2826 | if (len > 0) { 2827 | if ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL) 2828 | return -1; 2829 | } 2830 | else 2831 | tmpcom = NULL; 2832 | 2833 | free(za->ch_comment); 2834 | za->ch_comment = tmpcom; 2835 | za->ch_comment_len = len; 2836 | 2837 | return 0; 2838 | } 2839 | 2840 | 2841 | ZIP_EXTERN int 2842 | zip_replace(struct zip *za, int idx, struct zip_source *source) 2843 | { 2844 | if (idx < 0 || idx >= za->nentry || source == NULL) { 2845 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 2846 | return -1; 2847 | } 2848 | 2849 | if (_zip_replace(za, idx, NULL, source) == -1) 2850 | return -1; 2851 | 2852 | return 0; 2853 | } 2854 | 2855 | 2856 | 2857 | 2858 | int 2859 | _zip_replace(struct zip *za, int idx, const char *name, 2860 | struct zip_source *source) 2861 | { 2862 | if (idx == -1) { 2863 | if (_zip_entry_new(za) == NULL) 2864 | return -1; 2865 | 2866 | idx = za->nentry - 1; 2867 | } 2868 | 2869 | _zip_unchange_data(za->entry+idx); 2870 | 2871 | if (name && _zip_set_name(za, idx, name) != 0) 2872 | return -1; 2873 | 2874 | za->entry[idx].state = ((za->cdir == NULL || idx >= za->cdir->nentry) 2875 | ? ZIP_ST_ADDED : ZIP_ST_REPLACED); 2876 | za->entry[idx].source = source; 2877 | 2878 | return idx; 2879 | } 2880 | 2881 | 2882 | ZIP_EXTERN int 2883 | zip_rename(struct zip *za, int idx, const char *name) 2884 | { 2885 | const char *old_name; 2886 | int old_is_dir, new_is_dir; 2887 | 2888 | if (idx >= za->nentry || idx < 0 || name[0] == '\0') { 2889 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 2890 | return -1; 2891 | } 2892 | 2893 | if ((old_name=zip_get_name(za, idx, 0)) == NULL) 2894 | return -1; 2895 | 2896 | new_is_dir = (name[strlen(name)-1] == '/'); 2897 | old_is_dir = (old_name[strlen(old_name)-1] == '/'); 2898 | 2899 | if (new_is_dir != old_is_dir) { 2900 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 2901 | return -1; 2902 | } 2903 | 2904 | return _zip_set_name(za, idx, name); 2905 | } 2906 | 2907 | #include 2908 | #include 2909 | #include 2910 | #include 2911 | #include 2912 | #include 2913 | 2914 | static void set_error(int *, struct zip_error *, int); 2915 | static struct zip *_zip_allocate_new(const char *, int *); 2916 | static int _zip_checkcons(FILE *, struct zip_cdir *, struct zip_error *); 2917 | static void _zip_check_torrentzip(struct zip *); 2918 | static struct zip_cdir *_zip_find_central_dir(FILE *, int, int *, myoff_t); 2919 | static int _zip_file_exists(const char *, int, int *); 2920 | static int _zip_headercomp(struct zip_dirent *, int, 2921 | struct zip_dirent *, int); 2922 | static unsigned char *_zip_memmem(const unsigned char *, int, 2923 | const unsigned char *, int); 2924 | static struct zip_cdir *_zip_readcdir(FILE *, unsigned char *, unsigned char *, 2925 | int, int, struct zip_error *); 2926 | 2927 | 2928 | 2929 | ZIP_EXTERN struct zip * 2930 | zip_open(const char *fn, int flags, int *zep) 2931 | { 2932 | FILE *fp; 2933 | struct zip *za; 2934 | struct zip_cdir *cdir; 2935 | int i; 2936 | myoff_t len; 2937 | 2938 | switch (_zip_file_exists(fn, flags, zep)) { 2939 | case -1: 2940 | return NULL; 2941 | case 0: 2942 | return _zip_allocate_new(fn, zep); 2943 | default: 2944 | break; 2945 | } 2946 | 2947 | if ((fp=fopen(fn, "rb")) == NULL) { 2948 | set_error(zep, NULL, ZIP_ER_OPEN); 2949 | return NULL; 2950 | } 2951 | 2952 | fseeko(fp, 0, SEEK_END); 2953 | len = ftello(fp); 2954 | 2955 | /* treat empty files as empty archives */ 2956 | if (len == 0) { 2957 | if ((za=_zip_allocate_new(fn, zep)) == NULL) 2958 | fclose(fp); 2959 | else 2960 | za->zp = fp; 2961 | return za; 2962 | } 2963 | 2964 | cdir = _zip_find_central_dir(fp, flags, zep, len); 2965 | if (cdir == NULL) { 2966 | fclose(fp); 2967 | return NULL; 2968 | } 2969 | 2970 | if ((za=_zip_allocate_new(fn, zep)) == NULL) { 2971 | _zip_cdir_free(cdir); 2972 | fclose(fp); 2973 | return NULL; 2974 | } 2975 | 2976 | za->cdir = cdir; 2977 | za->zp = fp; 2978 | 2979 | if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry)) 2980 | * cdir->nentry)) == NULL) { 2981 | set_error(zep, NULL, ZIP_ER_MEMORY); 2982 | _zip_free(za); 2983 | return NULL; 2984 | } 2985 | for (i=0; inentry; i++) 2986 | _zip_entry_new(za); 2987 | 2988 | _zip_check_torrentzip(za); 2989 | za->ch_flags = za->flags; 2990 | 2991 | return za; 2992 | } 2993 | 2994 | 2995 | 2996 | static void 2997 | set_error(int *zep, struct zip_error *err, int ze) 2998 | { 2999 | int se; 3000 | 3001 | if (err) { 3002 | _zip_error_get(err, &ze, &se); 3003 | if (zip_error_get_sys_type(ze) == ZIP_ET_SYS) 3004 | errno = se; 3005 | } 3006 | 3007 | if (zep) 3008 | *zep = ze; 3009 | } 3010 | 3011 | 3012 | 3013 | /* _zip_readcdir: 3014 | tries to find a valid end-of-central-directory at the beginning of 3015 | buf, and then the corresponding central directory entries. 3016 | Returns a struct zip_cdir which contains the central directory 3017 | entries, or NULL if unsuccessful. */ 3018 | 3019 | static struct zip_cdir * 3020 | _zip_readcdir(FILE *fp, unsigned char *buf, unsigned char *eocd, int buflen, 3021 | int flags, struct zip_error *error) 3022 | { 3023 | struct zip_cdir *cd; 3024 | unsigned char *cdp, **bufp; 3025 | int i, comlen, nentry; 3026 | 3027 | comlen = buf + buflen - eocd - EOCDLEN; 3028 | if (comlen < 0) { 3029 | /* not enough bytes left for comment */ 3030 | _zip_error_set(error, ZIP_ER_NOZIP, 0); 3031 | return NULL; 3032 | } 3033 | 3034 | /* check for end-of-central-dir magic */ 3035 | if (memcmp(eocd, EOCD_MAGIC, 4) != 0) { 3036 | _zip_error_set(error, ZIP_ER_NOZIP, 0); 3037 | return NULL; 3038 | } 3039 | 3040 | if (memcmp(eocd+4, "\0\0\0\0", 4) != 0) { 3041 | _zip_error_set(error, ZIP_ER_MULTIDISK, 0); 3042 | return NULL; 3043 | } 3044 | 3045 | cdp = eocd + 8; 3046 | /* number of cdir-entries on this disk */ 3047 | i = _zip_read2(&cdp); 3048 | /* number of cdir-entries */ 3049 | nentry = _zip_read2(&cdp); 3050 | 3051 | if ((cd=_zip_cdir_new(nentry, error)) == NULL) 3052 | return NULL; 3053 | 3054 | cd->size = _zip_read4(&cdp); 3055 | cd->offset = _zip_read4(&cdp); 3056 | cd->comment = NULL; 3057 | cd->comment_len = _zip_read2(&cdp); 3058 | 3059 | if ((comlen < cd->comment_len) || (cd->nentry != i)) { 3060 | _zip_error_set(error, ZIP_ER_NOZIP, 0); 3061 | free(cd); 3062 | return NULL; 3063 | } 3064 | if ((flags & ZIP_CHECKCONS) && comlen != cd->comment_len) { 3065 | _zip_error_set(error, ZIP_ER_INCONS, 0); 3066 | free(cd); 3067 | return NULL; 3068 | } 3069 | 3070 | if (cd->comment_len) { 3071 | if ((cd->comment=(char *)_zip_memdup(eocd+EOCDLEN, 3072 | cd->comment_len, error)) 3073 | == NULL) { 3074 | free(cd); 3075 | return NULL; 3076 | } 3077 | } 3078 | 3079 | cdp = eocd; 3080 | if (cd->size < (unsigned int)(eocd-buf)) { 3081 | /* if buffer already read in, use it */ 3082 | cdp = eocd - cd->size; 3083 | bufp = &cdp; 3084 | } 3085 | else { 3086 | /* go to start of cdir and read it entry by entry */ 3087 | bufp = NULL; 3088 | clearerr(fp); 3089 | fseeko(fp, cd->offset, SEEK_SET); 3090 | /* possible consistency check: cd->offset = 3091 | len-(cd->size+cd->comment_len+EOCDLEN) ? */ 3092 | if (ferror(fp) || ((unsigned long)ftello(fp) != cd->offset)) { 3093 | /* seek error or offset of cdir wrong */ 3094 | if (ferror(fp)) 3095 | _zip_error_set(error, ZIP_ER_SEEK, errno); 3096 | else 3097 | _zip_error_set(error, ZIP_ER_NOZIP, 0); 3098 | free(cd); 3099 | return NULL; 3100 | } 3101 | } 3102 | 3103 | for (i=0; inentry; i++) { 3104 | if ((_zip_dirent_read(cd->entry+i, fp, bufp, eocd-cdp, 0, 3105 | error)) < 0) { 3106 | cd->nentry = i; 3107 | _zip_cdir_free(cd); 3108 | return NULL; 3109 | } 3110 | } 3111 | 3112 | return cd; 3113 | } 3114 | 3115 | 3116 | 3117 | /* _zip_checkcons: 3118 | Checks the consistency of the central directory by comparing central 3119 | directory entries with local headers and checking for plausible 3120 | file and header offsets. Returns -1 if not plausible, else the 3121 | difference between the lowest and the highest fileposition reached */ 3122 | 3123 | static int 3124 | _zip_checkcons(FILE *fp, struct zip_cdir *cd, struct zip_error *error) 3125 | { 3126 | int i; 3127 | unsigned int min, max, j; 3128 | struct zip_dirent temp; 3129 | 3130 | if (cd->nentry) { 3131 | max = cd->entry[0].offset; 3132 | min = cd->entry[0].offset; 3133 | } 3134 | else 3135 | min = max = 0; 3136 | 3137 | for (i=0; inentry; i++) { 3138 | if (cd->entry[i].offset < min) 3139 | min = cd->entry[i].offset; 3140 | if (min > cd->offset) { 3141 | _zip_error_set(error, ZIP_ER_NOZIP, 0); 3142 | return -1; 3143 | } 3144 | 3145 | j = cd->entry[i].offset + cd->entry[i].comp_size 3146 | + cd->entry[i].filename_len + LENTRYSIZE; 3147 | if (j > max) 3148 | max = j; 3149 | if (max > cd->offset) { 3150 | _zip_error_set(error, ZIP_ER_NOZIP, 0); 3151 | return -1; 3152 | } 3153 | 3154 | if (fseeko(fp, cd->entry[i].offset, SEEK_SET) != 0) { 3155 | _zip_error_set(error, ZIP_ER_SEEK, 0); 3156 | return -1; 3157 | } 3158 | 3159 | if (_zip_dirent_read(&temp, fp, NULL, 0, 1, error) == -1) 3160 | return -1; 3161 | 3162 | if (_zip_headercomp(cd->entry+i, 0, &temp, 1) != 0) { 3163 | _zip_error_set(error, ZIP_ER_INCONS, 0); 3164 | _zip_dirent_finalize(&temp); 3165 | return -1; 3166 | } 3167 | _zip_dirent_finalize(&temp); 3168 | } 3169 | 3170 | return max - min; 3171 | } 3172 | 3173 | 3174 | 3175 | /* _zip_check_torrentzip: 3176 | check wether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */ 3177 | 3178 | static void 3179 | _zip_check_torrentzip(struct zip *za) 3180 | { 3181 | uLong crc_got, crc_should; 3182 | char buf[8+1]; 3183 | char *end; 3184 | 3185 | if (za->zp == NULL || za->cdir == NULL) 3186 | return; 3187 | 3188 | if (za->cdir->comment_len != TORRENT_SIG_LEN+8 3189 | || strncmp(za->cdir->comment, TORRENT_SIG, TORRENT_SIG_LEN) != 0) 3190 | return; 3191 | 3192 | memcpy(buf, za->cdir->comment+TORRENT_SIG_LEN, 8); 3193 | buf[8] = '\0'; 3194 | errno = 0; 3195 | crc_should = strtoul(buf, &end, 16); 3196 | if ((crc_should == UINT_MAX && errno != 0) || (end && *end)) 3197 | return; 3198 | 3199 | if (_zip_filerange_crc(za->zp, za->cdir->offset, za->cdir->size, 3200 | &crc_got, NULL) < 0) 3201 | return; 3202 | 3203 | if (crc_got == crc_should) 3204 | za->flags |= ZIP_AFL_TORRENT; 3205 | } 3206 | 3207 | 3208 | 3209 | 3210 | /* _zip_headercomp: 3211 | compares two headers h1 and h2; if they are local headers, set 3212 | local1p or local2p respectively to 1, else 0. Return 0 if they 3213 | are identical, -1 if not. */ 3214 | 3215 | static int 3216 | _zip_headercomp(struct zip_dirent *h1, int local1p, struct zip_dirent *h2, 3217 | int local2p) 3218 | { 3219 | if ((h1->version_needed != h2->version_needed) 3220 | #if 0 3221 | /* some zip-files have different values in local 3222 | and global headers for the bitflags */ 3223 | || (h1->bitflags != h2->bitflags) 3224 | #endif 3225 | || (h1->comp_method != h2->comp_method) 3226 | || (h1->last_mod != h2->last_mod) 3227 | || (h1->filename_len != h2->filename_len) 3228 | || !h1->filename || !h2->filename 3229 | || strcmp(h1->filename, h2->filename)) 3230 | return -1; 3231 | 3232 | /* check that CRC and sizes are zero if data descriptor is used */ 3233 | if ((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local1p 3234 | && (h1->crc != 0 3235 | || h1->comp_size != 0 3236 | || h1->uncomp_size != 0)) 3237 | return -1; 3238 | if ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local2p 3239 | && (h2->crc != 0 3240 | || h2->comp_size != 0 3241 | || h2->uncomp_size != 0)) 3242 | return -1; 3243 | 3244 | /* check that CRC and sizes are equal if no data descriptor is used */ 3245 | if (((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local1p == 0) 3246 | && ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local2p == 0)) { 3247 | if ((h1->crc != h2->crc) 3248 | || (h1->comp_size != h2->comp_size) 3249 | || (h1->uncomp_size != h2->uncomp_size)) 3250 | return -1; 3251 | } 3252 | 3253 | if ((local1p == local2p) 3254 | && ((h1->extrafield_len != h2->extrafield_len) 3255 | || (h1->extrafield_len && h2->extrafield 3256 | && memcmp(h1->extrafield, h2->extrafield, 3257 | h1->extrafield_len)))) 3258 | return -1; 3259 | 3260 | /* if either is local, nothing more to check */ 3261 | if (local1p || local2p) 3262 | return 0; 3263 | 3264 | if ((h1->version_madeby != h2->version_madeby) 3265 | || (h1->disk_number != h2->disk_number) 3266 | || (h1->int_attrib != h2->int_attrib) 3267 | || (h1->ext_attrib != h2->ext_attrib) 3268 | || (h1->offset != h2->offset) 3269 | || (h1->comment_len != h2->comment_len) 3270 | || (h1->comment_len && h2->comment 3271 | && memcmp(h1->comment, h2->comment, h1->comment_len))) 3272 | return -1; 3273 | 3274 | return 0; 3275 | } 3276 | 3277 | 3278 | 3279 | static struct zip * 3280 | _zip_allocate_new(const char *fn, int *zep) 3281 | { 3282 | struct zip *za; 3283 | struct zip_error error; 3284 | 3285 | if ((za=_zip_new(&error)) == NULL) { 3286 | set_error(zep, &error, 0); 3287 | return NULL; 3288 | } 3289 | 3290 | za->zn = strdup(fn); 3291 | if (!za->zn) { 3292 | _zip_free(za); 3293 | set_error(zep, NULL, ZIP_ER_MEMORY); 3294 | return NULL; 3295 | } 3296 | return za; 3297 | } 3298 | 3299 | 3300 | 3301 | static int 3302 | _zip_file_exists(const char *fn, int flags, int *zep) 3303 | { 3304 | struct stat st; 3305 | 3306 | if (fn == NULL) { 3307 | set_error(zep, NULL, ZIP_ER_INVAL); 3308 | return -1; 3309 | } 3310 | 3311 | if (stat(fn, &st) != 0) { 3312 | if (flags & ZIP_CREATE) 3313 | return 0; 3314 | else { 3315 | set_error(zep, NULL, ZIP_ER_OPEN); 3316 | return -1; 3317 | } 3318 | } 3319 | else if ((flags & ZIP_EXCL)) { 3320 | set_error(zep, NULL, ZIP_ER_EXISTS); 3321 | return -1; 3322 | } 3323 | /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, 3324 | just like open() */ 3325 | 3326 | return 1; 3327 | } 3328 | 3329 | 3330 | 3331 | static struct zip_cdir * 3332 | _zip_find_central_dir(FILE *fp, int flags, int *zep, myoff_t len) 3333 | { 3334 | struct zip_cdir *cdir, *cdirnew; 3335 | unsigned char *buf, *match; 3336 | int a, best, buflen, i; 3337 | struct zip_error zerr; 3338 | 3339 | i = fseeko(fp, -(len < CDBUFSIZE ? len : CDBUFSIZE), SEEK_END); 3340 | if (i == -1 && errno != EFBIG) { 3341 | /* seek before start of file on my machine */ 3342 | set_error(zep, NULL, ZIP_ER_SEEK); 3343 | return NULL; 3344 | } 3345 | 3346 | /* 64k is too much for stack */ 3347 | if ((buf=(unsigned char *)malloc(CDBUFSIZE)) == NULL) { 3348 | set_error(zep, NULL, ZIP_ER_MEMORY); 3349 | return NULL; 3350 | } 3351 | 3352 | clearerr(fp); 3353 | buflen = fread(buf, 1, CDBUFSIZE, fp); 3354 | 3355 | if (ferror(fp)) { 3356 | set_error(zep, NULL, ZIP_ER_READ); 3357 | free(buf); 3358 | return NULL; 3359 | } 3360 | 3361 | best = -1; 3362 | cdir = NULL; 3363 | match = buf; 3364 | _zip_error_set(&zerr, ZIP_ER_NOZIP, 0); 3365 | 3366 | while ((match=_zip_memmem(match, buflen-(match-buf)-18, 3367 | (const unsigned char *)EOCD_MAGIC, 4))!=NULL) { 3368 | /* found match -- check, if good */ 3369 | /* to avoid finding the same match all over again */ 3370 | match++; 3371 | if ((cdirnew=_zip_readcdir(fp, buf, match-1, buflen, flags, 3372 | &zerr)) == NULL) 3373 | continue; 3374 | 3375 | if (cdir) { 3376 | if (best <= 0) 3377 | best = _zip_checkcons(fp, cdir, &zerr); 3378 | a = _zip_checkcons(fp, cdirnew, &zerr); 3379 | if (best < a) { 3380 | _zip_cdir_free(cdir); 3381 | cdir = cdirnew; 3382 | best = a; 3383 | } 3384 | else 3385 | _zip_cdir_free(cdirnew); 3386 | } 3387 | else { 3388 | cdir = cdirnew; 3389 | if (flags & ZIP_CHECKCONS) 3390 | best = _zip_checkcons(fp, cdir, &zerr); 3391 | else 3392 | best = 0; 3393 | } 3394 | cdirnew = NULL; 3395 | } 3396 | 3397 | free(buf); 3398 | 3399 | if (best < 0) { 3400 | set_error(zep, &zerr, 0); 3401 | _zip_cdir_free(cdir); 3402 | return NULL; 3403 | } 3404 | 3405 | return cdir; 3406 | } 3407 | 3408 | 3409 | 3410 | static unsigned char * 3411 | _zip_memmem(const unsigned char *big, int biglen, const unsigned char *little, 3412 | int littlelen) 3413 | { 3414 | const unsigned char *p; 3415 | 3416 | if ((biglen < littlelen) || (littlelen == 0)) 3417 | return NULL; 3418 | p = big-1; 3419 | while ((p=(const unsigned char *) 3420 | memchr(p+1, little[0], (size_t)(big-(p+1)+biglen-littlelen+1))) 3421 | != NULL) { 3422 | if (memcmp(p+1, little+1, littlelen-1)==0) 3423 | return (unsigned char *)p; 3424 | } 3425 | 3426 | return NULL; 3427 | } 3428 | 3429 | 3430 | /* _zip_new: 3431 | creates a new zipfile struct, and sets the contents to zero; returns 3432 | the new struct. */ 3433 | 3434 | struct zip * 3435 | _zip_new(struct zip_error *error) 3436 | { 3437 | struct zip *za; 3438 | 3439 | za = (struct zip *)malloc(sizeof(struct zip)); 3440 | if (!za) { 3441 | _zip_error_set(error, ZIP_ER_MEMORY, 0); 3442 | return NULL; 3443 | } 3444 | 3445 | za->zn = NULL; 3446 | za->zp = NULL; 3447 | _zip_error_init(&za->error); 3448 | za->cdir = NULL; 3449 | za->ch_comment = NULL; 3450 | za->ch_comment_len = -1; 3451 | za->nentry = za->nentry_alloc = 0; 3452 | za->entry = NULL; 3453 | za->nfile = za->nfile_alloc = 0; 3454 | za->file = NULL; 3455 | za->flags = za->ch_flags = 0; 3456 | 3457 | return za; 3458 | } 3459 | 3460 | 3461 | void * 3462 | _zip_memdup(const void *mem, size_t len, struct zip_error *error) 3463 | { 3464 | void *ret; 3465 | 3466 | ret = malloc(len); 3467 | if (!ret) { 3468 | _zip_error_set(error, ZIP_ER_MEMORY, 0); 3469 | return NULL; 3470 | } 3471 | 3472 | memcpy(ret, mem, len); 3473 | 3474 | return ret; 3475 | } 3476 | 3477 | 3478 | ZIP_EXTERN int 3479 | zip_get_num_files(struct zip *za) 3480 | { 3481 | if (za == NULL) 3482 | return -1; 3483 | 3484 | return za->nentry; 3485 | } 3486 | 3487 | ZIP_EXTERN const char * 3488 | zip_get_name(struct zip *za, int idx, int flags) 3489 | { 3490 | return _zip_get_name(za, idx, flags, &za->error); 3491 | } 3492 | 3493 | 3494 | 3495 | const char * 3496 | _zip_get_name(struct zip *za, int idx, int flags, struct zip_error *error) 3497 | { 3498 | if (idx < 0 || idx >= za->nentry) { 3499 | _zip_error_set(error, ZIP_ER_INVAL, 0); 3500 | return NULL; 3501 | } 3502 | 3503 | if ((flags & ZIP_FL_UNCHANGED) == 0) { 3504 | if (za->entry[idx].state == ZIP_ST_DELETED) { 3505 | _zip_error_set(error, ZIP_ER_DELETED, 0); 3506 | return NULL; 3507 | } 3508 | if (za->entry[idx].ch_filename) 3509 | return za->entry[idx].ch_filename; 3510 | } 3511 | 3512 | if (za->cdir == NULL || idx >= za->cdir->nentry) { 3513 | _zip_error_set(error, ZIP_ER_INVAL, 0); 3514 | return NULL; 3515 | } 3516 | 3517 | return za->cdir->entry[idx].filename; 3518 | } 3519 | 3520 | 3521 | ZIP_EXTERN const char * 3522 | zip_get_file_comment(struct zip *za, int idx, int *lenp, int flags) 3523 | { 3524 | if (idx < 0 || idx >= za->nentry) { 3525 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 3526 | return NULL; 3527 | } 3528 | 3529 | if ((flags & ZIP_FL_UNCHANGED) 3530 | || (za->entry[idx].ch_comment_len == -1)) { 3531 | if (lenp != NULL) 3532 | *lenp = za->cdir->entry[idx].comment_len; 3533 | return za->cdir->entry[idx].comment; 3534 | } 3535 | 3536 | if (lenp != NULL) 3537 | *lenp = za->entry[idx].ch_comment_len; 3538 | return za->entry[idx].ch_comment; 3539 | } 3540 | 3541 | 3542 | ZIP_EXTERN int 3543 | zip_get_archive_flag(struct zip *za, int flag, int flags) 3544 | { 3545 | int fl; 3546 | 3547 | fl = (flags & ZIP_FL_UNCHANGED) ? za->flags : za->ch_flags; 3548 | 3549 | return (fl & flag) ? 1 : 0; 3550 | } 3551 | 3552 | 3553 | ZIP_EXTERN const char * 3554 | zip_get_archive_comment(struct zip *za, int *lenp, int flags) 3555 | { 3556 | if ((flags & ZIP_FL_UNCHANGED) 3557 | || (za->ch_comment_len == -1)) { 3558 | if (za->cdir) { 3559 | if (lenp != NULL) 3560 | *lenp = za->cdir->comment_len; 3561 | return za->cdir->comment; 3562 | } 3563 | else { 3564 | if (lenp != NULL) 3565 | *lenp = -1; 3566 | return NULL; 3567 | } 3568 | } 3569 | 3570 | if (lenp != NULL) 3571 | *lenp = za->ch_comment_len; 3572 | return za->ch_comment; 3573 | } 3574 | 3575 | 3576 | /* _zip_free: 3577 | frees the space allocated to a zipfile struct, and closes the 3578 | corresponding file. */ 3579 | 3580 | void 3581 | _zip_free(struct zip *za) 3582 | { 3583 | int i; 3584 | 3585 | if (za == NULL) 3586 | return; 3587 | 3588 | if (za->zn) 3589 | free(za->zn); 3590 | 3591 | if (za->zp) 3592 | fclose(za->zp); 3593 | 3594 | _zip_cdir_free(za->cdir); 3595 | 3596 | if (za->entry) { 3597 | for (i=0; inentry; i++) { 3598 | _zip_entry_free(za->entry+i); 3599 | } 3600 | free(za->entry); 3601 | } 3602 | 3603 | for (i=0; infile; i++) { 3604 | if (za->file[i]->error.zip_err == ZIP_ER_OK) { 3605 | _zip_error_set(&za->file[i]->error, ZIP_ER_ZIPCLOSED, 0); 3606 | za->file[i]->za = NULL; 3607 | } 3608 | } 3609 | 3610 | free(za->file); 3611 | 3612 | free(za); 3613 | 3614 | return; 3615 | } 3616 | 3617 | 3618 | ZIP_EXTERN ssize_t 3619 | zip_fread(struct zip_file *zf, void *outbuf, size_t toread) 3620 | { 3621 | int ret; 3622 | size_t out_before, len; 3623 | int i; 3624 | 3625 | if (!zf) 3626 | return -1; 3627 | 3628 | if (zf->error.zip_err != 0) 3629 | return -1; 3630 | 3631 | if ((zf->flags & ZIP_ZF_EOF) || (toread == 0)) 3632 | return 0; 3633 | 3634 | if (zf->bytes_left == 0) { 3635 | zf->flags |= ZIP_ZF_EOF; 3636 | if (zf->flags & ZIP_ZF_CRC) { 3637 | if (zf->crc != zf->crc_orig) { 3638 | _zip_error_set(&zf->error, ZIP_ER_CRC, 0); 3639 | return -1; 3640 | } 3641 | } 3642 | return 0; 3643 | } 3644 | 3645 | if ((zf->flags & ZIP_ZF_DECOMP) == 0) { 3646 | ret = _zip_file_fillbuf(outbuf, toread, zf); 3647 | if (ret > 0) { 3648 | if (zf->flags & ZIP_ZF_CRC) 3649 | zf->crc = crc32(zf->crc, (Bytef *)outbuf, ret); 3650 | zf->bytes_left -= ret; 3651 | } 3652 | return ret; 3653 | } 3654 | 3655 | zf->zstr->next_out = (Bytef *)outbuf; 3656 | zf->zstr->avail_out = toread; 3657 | out_before = zf->zstr->total_out; 3658 | 3659 | /* endless loop until something has been accomplished */ 3660 | for (;;) { 3661 | ret = inflate(zf->zstr, Z_SYNC_FLUSH); 3662 | 3663 | switch (ret) { 3664 | case Z_OK: 3665 | case Z_STREAM_END: 3666 | /* all ok */ 3667 | /* Z_STREAM_END probably won't happen, since we didn't 3668 | have a header */ 3669 | len = zf->zstr->total_out - out_before; 3670 | if (len >= zf->bytes_left || len >= toread) { 3671 | if (zf->flags & ZIP_ZF_CRC) 3672 | zf->crc = crc32(zf->crc, (Bytef *)outbuf, len); 3673 | zf->bytes_left -= len; 3674 | return len; 3675 | } 3676 | break; 3677 | 3678 | case Z_BUF_ERROR: 3679 | if (zf->zstr->avail_in == 0) { 3680 | i = _zip_file_fillbuf(zf->buffer, BUFSIZE, zf); 3681 | if (i == 0) { 3682 | _zip_error_set(&zf->error, ZIP_ER_INCONS, 0); 3683 | return -1; 3684 | } 3685 | else if (i < 0) 3686 | return -1; 3687 | zf->zstr->next_in = (Bytef *)zf->buffer; 3688 | zf->zstr->avail_in = i; 3689 | continue; 3690 | } 3691 | /* fallthrough */ 3692 | case Z_NEED_DICT: 3693 | case Z_DATA_ERROR: 3694 | case Z_STREAM_ERROR: 3695 | case Z_MEM_ERROR: 3696 | _zip_error_set(&zf->error, ZIP_ER_ZLIB, ret); 3697 | return -1; 3698 | } 3699 | } 3700 | } 3701 | 3702 | 3703 | ZIP_EXTERN const char * 3704 | zip_strerror(struct zip *za) 3705 | { 3706 | return _zip_error_strerror(&za->error); 3707 | } 3708 | 3709 | 3710 | ZIP_EXTERN void 3711 | zip_stat_init(struct zip_stat *st) 3712 | { 3713 | st->name = NULL; 3714 | st->index = -1; 3715 | st->crc = 0; 3716 | st->mtime = (time_t)-1; 3717 | st->size = -1; 3718 | st->comp_size = -1; 3719 | st->comp_method = ZIP_CM_STORE; 3720 | st->encryption_method = ZIP_EM_NONE; 3721 | } 3722 | 3723 | 3724 | ZIP_EXTERN int 3725 | zip_stat_index(struct zip *za, int index, int flags, struct zip_stat *st) 3726 | { 3727 | const char *name; 3728 | 3729 | if (index < 0 || index >= za->nentry) { 3730 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 3731 | return -1; 3732 | } 3733 | 3734 | if ((name=zip_get_name(za, index, flags)) == NULL) 3735 | return -1; 3736 | 3737 | 3738 | if ((flags & ZIP_FL_UNCHANGED) == 0 3739 | && ZIP_ENTRY_DATA_CHANGED(za->entry+index)) { 3740 | if (za->entry[index].source->f(za->entry[index].source->ud, 3741 | st, sizeof(*st), ZIP_SOURCE_STAT) < 0) { 3742 | _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); 3743 | return -1; 3744 | } 3745 | } 3746 | else { 3747 | if (za->cdir == NULL || index >= za->cdir->nentry) { 3748 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 3749 | return -1; 3750 | } 3751 | 3752 | st->crc = za->cdir->entry[index].crc; 3753 | st->size = za->cdir->entry[index].uncomp_size; 3754 | st->mtime = za->cdir->entry[index].last_mod; 3755 | st->comp_size = za->cdir->entry[index].comp_size; 3756 | st->comp_method = za->cdir->entry[index].comp_method; 3757 | if (za->cdir->entry[index].bitflags & ZIP_GPBF_ENCRYPTED) { 3758 | if (za->cdir->entry[index].bitflags & ZIP_GPBF_STRONG_ENCRYPTION) { 3759 | /* XXX */ 3760 | st->encryption_method = ZIP_EM_UNKNOWN; 3761 | } 3762 | else 3763 | st->encryption_method = ZIP_EM_TRAD_PKWARE; 3764 | } 3765 | else 3766 | st->encryption_method = ZIP_EM_NONE; 3767 | /* st->bitflags = za->cdir->entry[index].bitflags; */ 3768 | } 3769 | 3770 | st->index = index; 3771 | st->name = name; 3772 | 3773 | return 0; 3774 | } 3775 | 3776 | 3777 | ZIP_EXTERN int 3778 | zip_stat(struct zip *za, const char *fname, int flags, struct zip_stat *st) 3779 | { 3780 | int idx; 3781 | 3782 | if ((idx=zip_name_locate(za, fname, flags)) < 0) 3783 | return -1; 3784 | 3785 | return zip_stat_index(za, idx, flags, st); 3786 | } 3787 | 3788 | 3789 | struct read_zip { 3790 | struct zip_file *zf; 3791 | struct zip_stat st; 3792 | myoff_t off, len; 3793 | }; 3794 | 3795 | static ssize_t read_zip(void *st, void *data, size_t len, 3796 | enum zip_source_cmd cmd); 3797 | 3798 | 3799 | 3800 | ZIP_EXTERN struct zip_source * 3801 | zip_source_zip(struct zip *za, struct zip *srcza, int srcidx, int flags, 3802 | myoff_t start, myoff_t len) 3803 | { 3804 | struct zip_error error; 3805 | struct zip_source *zs; 3806 | struct read_zip *p; 3807 | 3808 | /* XXX: ZIP_FL_RECOMPRESS */ 3809 | 3810 | if (za == NULL) 3811 | return NULL; 3812 | 3813 | if (srcza == NULL || start < 0 || len < -1 || srcidx < 0 || srcidx >= srcza->nentry) { 3814 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 3815 | return NULL; 3816 | } 3817 | 3818 | if ((flags & ZIP_FL_UNCHANGED) == 0 3819 | && ZIP_ENTRY_DATA_CHANGED(srcza->entry+srcidx)) { 3820 | _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); 3821 | return NULL; 3822 | } 3823 | 3824 | if (len == 0) 3825 | len = -1; 3826 | 3827 | if (start == 0 && len == -1 && (flags & ZIP_FL_RECOMPRESS) == 0) 3828 | flags |= ZIP_FL_COMPRESSED; 3829 | else 3830 | flags &= ~ZIP_FL_COMPRESSED; 3831 | 3832 | if ((p=(struct read_zip *)malloc(sizeof(*p))) == NULL) { 3833 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 3834 | return NULL; 3835 | } 3836 | 3837 | _zip_error_copy(&error, &srcza->error); 3838 | 3839 | if (zip_stat_index(srcza, srcidx, flags, &p->st) < 0 3840 | || (p->zf=zip_fopen_index(srcza, srcidx, flags)) == NULL) { 3841 | free(p); 3842 | _zip_error_copy(&za->error, &srcza->error); 3843 | _zip_error_copy(&srcza->error, &error); 3844 | 3845 | return NULL; 3846 | } 3847 | p->off = start; 3848 | p->len = len; 3849 | 3850 | if ((flags & ZIP_FL_COMPRESSED) == 0) { 3851 | p->st.size = p->st.comp_size = len; 3852 | p->st.comp_method = ZIP_CM_STORE; 3853 | p->st.crc = 0; 3854 | } 3855 | 3856 | if ((zs=zip_source_function(za, read_zip, p)) == NULL) { 3857 | free(p); 3858 | return NULL; 3859 | } 3860 | 3861 | return zs; 3862 | } 3863 | 3864 | 3865 | 3866 | static ssize_t 3867 | read_zip(void *state, void *data, size_t len, enum zip_source_cmd cmd) 3868 | { 3869 | struct read_zip *z; 3870 | char b[8192], *buf; 3871 | int i, n; 3872 | 3873 | z = (struct read_zip *)state; 3874 | buf = (char *)data; 3875 | 3876 | switch (cmd) { 3877 | case ZIP_SOURCE_OPEN: 3878 | for (n=0; noff; n+= i) { 3879 | i = (z->off-n > sizeof(b) ? sizeof(b) : z->off-n); 3880 | if ((i=zip_fread(z->zf, b, i)) < 0) { 3881 | zip_fclose(z->zf); 3882 | z->zf = NULL; 3883 | return -1; 3884 | } 3885 | } 3886 | return 0; 3887 | 3888 | case ZIP_SOURCE_READ: 3889 | if (z->len != -1) 3890 | n = len > z->len ? z->len : len; 3891 | else 3892 | n = len; 3893 | 3894 | 3895 | if ((i=zip_fread(z->zf, buf, n)) < 0) 3896 | return -1; 3897 | 3898 | if (z->len != -1) 3899 | z->len -= i; 3900 | 3901 | return i; 3902 | 3903 | case ZIP_SOURCE_CLOSE: 3904 | return 0; 3905 | 3906 | case ZIP_SOURCE_STAT: 3907 | if (len < sizeof(z->st)) 3908 | return -1; 3909 | len = sizeof(z->st); 3910 | 3911 | memcpy(data, &z->st, len); 3912 | return len; 3913 | 3914 | case ZIP_SOURCE_ERROR: 3915 | { 3916 | int *e; 3917 | 3918 | if (len < sizeof(int)*2) 3919 | return -1; 3920 | 3921 | e = (int *)data; 3922 | zip_file_error_get(z->zf, e, e+1); 3923 | } 3924 | return sizeof(int)*2; 3925 | 3926 | case ZIP_SOURCE_FREE: 3927 | zip_fclose(z->zf); 3928 | free(z); 3929 | return 0; 3930 | 3931 | default: 3932 | ; 3933 | } 3934 | 3935 | return -1; 3936 | } 3937 | 3938 | 3939 | ZIP_EXTERN struct zip_source * 3940 | zip_source_function(struct zip *za, zip_source_callback zcb, void *ud) 3941 | { 3942 | struct zip_source *zs; 3943 | 3944 | if (za == NULL) 3945 | return NULL; 3946 | 3947 | if ((zs=(struct zip_source *)malloc(sizeof(*zs))) == NULL) { 3948 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 3949 | return NULL; 3950 | } 3951 | 3952 | zs->f = zcb; 3953 | zs->ud = ud; 3954 | 3955 | return zs; 3956 | } 3957 | 3958 | 3959 | ZIP_EXTERN void 3960 | zip_source_free(struct zip_source *source) 3961 | { 3962 | if (source == NULL) 3963 | return; 3964 | 3965 | (void)source->f(source->ud, NULL, 0, ZIP_SOURCE_FREE); 3966 | 3967 | free(source); 3968 | } 3969 | 3970 | 3971 | struct read_file { 3972 | char *fname; /* name of file to copy from */ 3973 | FILE *f; /* file to copy from */ 3974 | myoff_t off; /* start offset of */ 3975 | myoff_t len; /* lengt of data to copy */ 3976 | myoff_t remain; /* bytes remaining to be copied */ 3977 | int e[2]; /* error codes */ 3978 | }; 3979 | 3980 | static ssize_t read_file(void *state, void *data, size_t len, 3981 | enum zip_source_cmd cmd); 3982 | 3983 | 3984 | 3985 | ZIP_EXTERN struct zip_source * 3986 | zip_source_filep(struct zip *za, FILE *file, myoff_t start, myoff_t len) 3987 | { 3988 | if (za == NULL) 3989 | return NULL; 3990 | 3991 | if (file == NULL || start < 0 || len < -1) { 3992 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 3993 | return NULL; 3994 | } 3995 | 3996 | return _zip_source_file_or_p(za, NULL, file, start, len); 3997 | } 3998 | 3999 | 4000 | 4001 | struct zip_source * 4002 | _zip_source_file_or_p(struct zip *za, const char *fname, FILE *file, 4003 | myoff_t start, myoff_t len) 4004 | { 4005 | struct read_file *f; 4006 | struct zip_source *zs; 4007 | 4008 | if (file == NULL && fname == NULL) { 4009 | _zip_error_set(&za->error, ZIP_ER_INVAL, 0); 4010 | return NULL; 4011 | } 4012 | 4013 | if ((f=(struct read_file *)malloc(sizeof(struct read_file))) == NULL) { 4014 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 4015 | return NULL; 4016 | } 4017 | 4018 | f->fname = NULL; 4019 | if (fname) { 4020 | if ((f->fname=strdup(fname)) == NULL) { 4021 | _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); 4022 | free(f); 4023 | return NULL; 4024 | } 4025 | } 4026 | f->f = file; 4027 | f->off = start; 4028 | f->len = (len ? len : -1); 4029 | 4030 | if ((zs=zip_source_function(za, read_file, f)) == NULL) { 4031 | free(f); 4032 | return NULL; 4033 | } 4034 | 4035 | return zs; 4036 | } 4037 | 4038 | 4039 | 4040 | static ssize_t 4041 | read_file(void *state, void *data, size_t len, enum zip_source_cmd cmd) 4042 | { 4043 | struct read_file *z; 4044 | char *buf; 4045 | int i, n; 4046 | 4047 | z = (struct read_file *)state; 4048 | buf = (char *)data; 4049 | 4050 | switch (cmd) { 4051 | case ZIP_SOURCE_OPEN: 4052 | if (z->fname) { 4053 | if ((z->f=fopen(z->fname, "rb")) == NULL) { 4054 | z->e[0] = ZIP_ER_OPEN; 4055 | z->e[1] = errno; 4056 | return -1; 4057 | } 4058 | } 4059 | 4060 | if (fseeko(z->f, z->off, SEEK_SET) < 0) { 4061 | z->e[0] = ZIP_ER_SEEK; 4062 | z->e[1] = errno; 4063 | return -1; 4064 | } 4065 | z->remain = z->len; 4066 | return 0; 4067 | 4068 | case ZIP_SOURCE_READ: 4069 | if (z->remain != -1) 4070 | n = len > z->remain ? z->remain : len; 4071 | else 4072 | n = len; 4073 | 4074 | if ((i=fread(buf, 1, n, z->f)) < 0) { 4075 | z->e[0] = ZIP_ER_READ; 4076 | z->e[1] = errno; 4077 | return -1; 4078 | } 4079 | 4080 | if (z->remain != -1) 4081 | z->remain -= i; 4082 | 4083 | return i; 4084 | 4085 | case ZIP_SOURCE_CLOSE: 4086 | if (z->fname) { 4087 | fclose(z->f); 4088 | z->f = NULL; 4089 | } 4090 | return 0; 4091 | 4092 | case ZIP_SOURCE_STAT: 4093 | { 4094 | struct zip_stat *st; 4095 | struct stat fst; 4096 | int err; 4097 | 4098 | if (len < sizeof(*st)) 4099 | return -1; 4100 | 4101 | if (z->f) 4102 | err = fstat(fileno(z->f), &fst); 4103 | else 4104 | err = stat(z->fname, &fst); 4105 | 4106 | if (err != 0) { 4107 | z->e[0] = ZIP_ER_READ; /* best match */ 4108 | z->e[1] = errno; 4109 | return -1; 4110 | } 4111 | 4112 | st = (struct zip_stat *)data; 4113 | 4114 | zip_stat_init(st); 4115 | st->mtime = fst.st_mtime; 4116 | if (z->len != -1) 4117 | st->size = z->len; 4118 | else if ((fst.st_mode&S_IFMT) == S_IFREG) 4119 | st->size = fst.st_size; 4120 | 4121 | return sizeof(*st); 4122 | } 4123 | 4124 | case ZIP_SOURCE_ERROR: 4125 | if (len < sizeof(int)*2) 4126 | return -1; 4127 | 4128 | memcpy(data, z->e, sizeof(int)*2); 4129 | return sizeof(int)*2; 4130 | 4131 | case ZIP_SOURCE_FREE: 4132 | free(z->fname); 4133 | if (z->f) 4134 | fclose(z->f); 4135 | free(z); 4136 | return 0; 4137 | 4138 | default: 4139 | ; 4140 | } 4141 | 4142 | return -1; 4143 | } 4144 | 4145 | 4146 | ZIP_EXTERN int 4147 | zip_name_locate(struct zip *za, const char *fname, int flags) 4148 | { 4149 | return _zip_name_locate(za, fname, flags, &za->error); 4150 | } 4151 | 4152 | 4153 | 4154 | int 4155 | _zip_name_locate(struct zip *za, const char *fname, int flags, 4156 | struct zip_error *error) 4157 | { 4158 | int (*cmp)(const char *, const char *); 4159 | const char *fn, *p; 4160 | int i, n; 4161 | 4162 | if (fname == NULL) { 4163 | _zip_error_set(error, ZIP_ER_INVAL, 0); 4164 | return -1; 4165 | } 4166 | 4167 | cmp = (flags & ZIP_FL_NOCASE) ? strcasecmp : strcmp; 4168 | 4169 | n = (flags & ZIP_FL_UNCHANGED) ? za->cdir->nentry : za->nentry; 4170 | for (i=0; icdir->entry[i].filename; 4173 | else 4174 | fn = _zip_get_name(za, i, flags, error); 4175 | 4176 | /* newly added (partially filled) entry */ 4177 | if (fn == NULL) 4178 | continue; 4179 | 4180 | if (flags & ZIP_FL_NODIR) { 4181 | p = strrchr(fn, '/'); 4182 | if (p) 4183 | fn = p+1; 4184 | } 4185 | 4186 | if (cmp(fname, fn) == 0) 4187 | return i; 4188 | } 4189 | 4190 | _zip_error_set(error, ZIP_ER_NOENT, 0); 4191 | return -1; 4192 | } 4193 | 4194 | --------------------------------------------------------------------------------