Skip to content

Commit c2298e9

Browse files
committed
Added genzip1.py helper script for generating uncompressed deflate blocks in a zip file for unzip unit tests.
1 parent 6128da9 commit c2298e9

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

meta/test/unzip/genzip1.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/env python3
2+
3+
import struct
4+
import sys
5+
import zlib
6+
7+
def create_zip():
8+
filename = sys.argv[1].encode() if len(sys.argv) > 1 else b"test.txt"
9+
content = sys.stdin.buffer.read()
10+
if len(content) <= 0:
11+
content = b"Test"
12+
13+
# --- 1. Create the Raw Deflate Stream (Stored Block) ---
14+
# We are faking "compression" by creating a valid Deflate stream
15+
# that just wraps raw bytes.
16+
# Header Byte: 0x01
17+
# Bit 0 = 1 (BFINAL, this is the last block)
18+
# Bits 1-2 = 00 (BTYPE, stored/uncompressed)
19+
# LEN: 2 bytes, Little Endian length of data
20+
# NLEN: 2 bytes, Little Endian one's complement of length
21+
22+
length = len(content)
23+
nlen = (~length) & 0xFFFF
24+
25+
# Construct the payload
26+
# <HH means two unsigned short integers (2 bytes) in Little Endian
27+
deflate_header = b'\x01' + struct.pack('<HH', length, nlen)
28+
compressed_data = deflate_header + content
29+
30+
# Calculate Metadata
31+
crc = zlib.crc32(content)
32+
compressed_size = len(compressed_data)
33+
uncompressed_size = length
34+
35+
# --- 2. Construct ZIP Headers ---
36+
37+
# Common Values
38+
# Version needed: 2.0 (20)
39+
# Flags: 0
40+
# Compression Method: 8 (Deflate)
41+
# Time/Date: 0 (for simplicity)
42+
ver = 20
43+
flags = 0
44+
method = 8
45+
46+
# A. Local File Header
47+
# Signature (4s) = PK\x03\x04
48+
lfh_fmt = '<4sHHHHHIIIHH'
49+
lfh = struct.pack(
50+
lfh_fmt,
51+
b'\x50\x4b\x03\x04', # Signature
52+
ver, flags, method, 0, 0, # Ver, Flags, Method, Time, Date
53+
crc, compressed_size, uncompressed_size, # CRC, Sizes
54+
len(filename), 0 # Filename len, Extra len
55+
)
56+
57+
# B. Central Directory Header
58+
# Signature (4s) = PK\x01\x02
59+
cdh_fmt = '<4sHHHHHHIIIHHHHHII'
60+
cdh = struct.pack(
61+
cdh_fmt,
62+
b'\x50\x4b\x01\x02', # Signature
63+
ver, ver, flags, method, 0, 0, # MadeBy, Needed, Flags, Method, Time, Date
64+
crc, compressed_size, uncompressed_size, # CRC, Sizes
65+
len(filename), 0, 0, # Name len, Extra len, Comment len
66+
0, 0, 0x81a40000, # Disk Start, Int Attr, Ext Attr (Permissions)
67+
0 # Relative Offset of Local Header (0 because it's the first file)
68+
)
69+
70+
# C. End of Central Directory Record
71+
# Signature (4s) = PK\x05\x06
72+
# We need to calculate where the Central Directory starts and how big it is
73+
offset_of_cd = len(lfh) + len(filename) + compressed_size
74+
size_of_cd = len(cdh) + len(filename)
75+
76+
eocd_fmt = '<4sHHHHIIH'
77+
eocd = struct.pack(
78+
eocd_fmt,
79+
b'\x50\x4b\x05\x06', # Signature
80+
0, 0, 1, 1, # Disk nums, Recs on disk, Total recs
81+
size_of_cd, offset_of_cd, 0 # CD Size, CD Offset, Comment len
82+
)
83+
84+
# --- 3. Write the File ---
85+
with sys.stdout.buffer as f:
86+
f.write(lfh)
87+
f.write(filename)
88+
f.write(compressed_data)
89+
f.write(cdh)
90+
f.write(filename)
91+
f.write(eocd)
92+
93+
if __name__ == "__main__":
94+
create_zip()

0 commit comments

Comments
 (0)