1 #! /usr/bin/env python3
4 from struct
import Struct
5 from streams
import streamcopy
, DelegateWriter
6 from binascii
import crc32
7 from io
import BufferedIOBase
9 FILE_SIG
= b
"PK\x03\x04"
10 FILE_STRUCT
= Struct("< BB H H L LLL HH")
22 if len(sig
) != 4 or not sig
.startswith(b
"PK"):
23 raise ValueError("Invalid Zip record signature")
26 yield read_file_header(zip)
28 def read_file_header(zip):
29 (_
, _
, flags
, method
, _
, crc
, comp
, uncomp
, namelen
, extra
) = (
30 FILE_STRUCT
.unpack(zip.read(FILE_STRUCT
.size
)))
32 name
= zip.read(namelen
)
33 if len(name
) != namelen
:
34 raise EOFError("EOF in file name")
35 encoding
= "utf-8" if flags
>> FLAGS_UTF8
& 1 else "cp437"
36 name
= name
.decode(encoding
)
38 if flags
>> FLAGS_STREAMED
& 1:
39 raise NotImplementedError("Data descriptor")
40 return (flags
, method
, crc
, comp
, uncomp
, name
, extra
)
43 zip = sys
.stdin
.buffer
44 out
= sys
.stdout
.buffer
46 for [flags
, method
, crc
, comp
, uncomp
, name
, extra
] in iter_files(zip):
48 print(name
, file=sys
.stderr
)
50 streamcopy(zip, DelegateWriter(), extra
)
53 if flags
& (1 << FLAGS_ENCRYPTED |
1 << FLAGS_STRONG_ENC
):
54 print("Encrypted file", file=sys
.stderr
)
56 if method
!= METHOD_STORE
:
57 print("Compression method {!r}".format(method
), file=sys
.stderr
)
59 if name
.endswith((".txt", ".URL")):
63 streamcopy(zip, DelegateWriter(), comp
)
65 crcwriter
= Crc32Writer()
66 streamcopy(zip, DelegateWriter(out
, crcwriter
), uncomp
)
67 if crcwriter
.crc
!= crc
:
68 fmt
= "Extracted CRC {:08X} != expected CRC {:08X}"
69 print(fmt
.format(crcwriter
.crc
, crc
), file=sys
.stderr
)
71 streamcopy(zip, DelegateWriter(), comp
- uncomp
)
73 class Crc32Writer(BufferedIOBase
):
77 self
.crc
= crc32(b
, self
.crc
)
79 if __name__
== "__main__":