TechCompressor uses custom binary formats for compressed data and archives. Each format is identified by a unique 4-byte magic header to enable automatic format detection and prevent wrong-algorithm decompression errors.
Structure:
[Magic: 4 bytes] [Dict Size: 2 bytes] [Compressed Data: variable]
Details:
- Magic Header:
TCZ1(0x54 0x43 0x5A 0x31) - Dictionary Size: 2-byte big-endian unsigned integer (typically 4096)
- Compressed Data: Stream of 2-byte big-endian code words
Code Word Format:
- Each code is a 2-byte big-endian unsigned integer
- Range: 0-4095 (for 4096-entry dictionary)
- Codes 0-255 represent literal bytes
- Codes 256+ represent dictionary sequences
Dictionary Behavior:
- Initialized with single-byte values (0-255)
- Grows dynamically up to MAX_DICT_SIZE (4096)
- Automatically resets when full (enables unlimited input size)
Example:
Input: "TOBEORNOTTOBEORTOBEORNOT" (25 bytes)
Output: TCZ1 [10 00] [00 54] [00 4F] [00 42] ... (compressed codes)
Structure:
[Magic: 4 bytes] [Tree Size: 4 bytes] [Tree Data: variable] [Compressed Data: variable]
Details:
- Magic Header:
TCH1(0x54 0x43 0x48 0x31) - Tree Size: 4-byte big-endian unsigned integer (length of serialized tree in bytes)
- Tree Data: Serialized Huffman tree structure (preorder traversal)
- Compressed Data: Bit-packed Huffman codes
Tree Serialization Format:
- Preorder traversal of binary tree
- Internal nodes:
0bit - Leaf nodes:
1bit followed by 8-bit byte value - Example:
1[01000001]= leaf node with byte 'A' (0x41)
Compressed Data:
- Variable-length codes packed into bytes
- Padding bits added to align to byte boundary
- Padding size stored in last byte
Special Case:
- Single unique byte: code = "0", tree stores single leaf
Example:
Input: "AAB" (3 bytes, frequencies: A=2, B=1)
Tree: Internal→(Left=A, Right=B)
Codes: A="0", B="1"
Output: TCH1 [tree_size] [tree_data] [compressed: "001"]
Structure:
[Magic: 4 bytes] [Window Size: 2 bytes] [Compressed Data: variable]
Details:
- Magic Header:
TCD1(0x54 0x43 0x44 0x31) - Window Size: 2-byte big-endian unsigned integer (typically 32768 = 32KB)
- Compressed Data: Two-stage encoded data (LZ77 tokens + Huffman codes)
LZ77 Token Format:
- Literal:
(0, byte_value) - Match:
(distance, length)where distance is offset back in window, length is match size
Encoding Process:
- LZ77 pass: Find matches in sliding window, emit tokens
- Huffman pass: Build frequency table from tokens, encode with Huffman
Window Parameters:
- Window size: 32768 bytes (32KB)
- Max match length: 258 bytes
- Min match length: 3 bytes
Example:
Input: "ABABAB" (6 bytes)
LZ77: [(0, 'A'), (0, 'B'), (2, 4)] # "AB" + match 2 bytes back, length 4
Huffman: Encode tokens with Huffman tree
Output: TCD1 [80 00] [huffman_tree] [encoded_tokens]
Structure:
[Magic: 4 bytes] [Salt: 16 bytes] [Nonce: 12 bytes] [Ciphertext: variable] [Auth Tag: 16 bytes]
Details:
- Magic Header:
TCE1(0x54 0x43 0x45 0x31) - Salt: 16-byte random salt for PBKDF2 key derivation
- Nonce: 12-byte random nonce for AES-GCM (recommended size)
- Ciphertext: AES-256-GCM encrypted data (can be any compressed format)
- Auth Tag: 16-byte GCM authentication tag (integrity verification)
Encryption Process:
- Generate random 16-byte salt
- Derive 256-bit key using PBKDF2-HMAC-SHA256 (100,000 iterations)
- Generate random 12-byte nonce
- Encrypt plaintext with AES-256-GCM
- Append authentication tag
Decryption Process:
- Extract salt from encrypted data
- Derive key from password and salt (same PBKDF2 parameters)
- Extract nonce and authentication tag
- Decrypt and verify authentication tag
- Return plaintext (which may be compressed data with its own magic header)
Example:
Input: Compressed LZW data "TCZ1..."
Encrypt: TCE1 [16B salt] [12B nonce] [AES(TCZ1...)] [16B tag]
Decrypt: Verify tag → AES decrypt → "TCZ1..." (original compressed data)
Structure:
[Magic: 4 bytes] [Version: 1 byte] [Algorithm: 1 byte] [Per-File: 1 byte] [Entry Count: 4 bytes]
Details:
- Magic Header:
TCAF(0x54 0x43 0x41 0x46) - TechCompressor Archive Format - Version: 1 byte (current version = 1)
- Algorithm: 1 byte algorithm ID
1= LZW2= HUFFMAN3= DEFLATE4= ARITHMETIC (reserved)
- Per-File Flag: 1 byte boolean (0 = single-stream, 1 = per-file)
- Entry Count: 4-byte big-endian unsigned integer (number of files/folders)
Entry Metadata:
[Name Length: 4 bytes] [Name: UTF-8] [Is Dir: 1 byte] [Mod Time: 8 bytes] [Original Size: 8 bytes] [Data Length: 8 bytes]
Details:
- Name Length: 4-byte big-endian unsigned integer
- Name: UTF-8 encoded relative path (forward slashes, no leading slash)
- Is Dir: 1 byte boolean (0 = file, 1 = directory)
- Mod Time: 8-byte big-endian integer (Unix timestamp in seconds)
- Original Size: 8-byte big-endian unsigned integer (uncompressed size)
- Data Length: 8-byte big-endian unsigned integer (compressed data size, 0 for directories)
Entry Data:
[Compressed Data: Data Length bytes]
- Per-file mode: Each entry's data is independently compressed (has its own magic header)
- Single-stream mode: Only the first file entry contains compressed data; subsequent files are encoded within that stream
Structure:
TCAF Header
Entry 1 Metadata
Entry 1 Data: [TCZ1/TCH1/TCD1...] (independently compressed)
Entry 2 Metadata
Entry 2 Data: [TCZ1/TCH1/TCD1...] (independently compressed)
...
Advantages:
- Random access to individual files
- Selective extraction (no need to decompress entire archive)
- Better for mixed content types
- Fault tolerance (corruption affects only one file)
Disadvantages:
- Slightly larger archive size (metadata overhead per file)
- No cross-file dictionary sharing
Structure:
TCAF Header
Entry 1 Metadata (file 1)
Entry 2 Metadata (file 2)
...
Entry N Metadata (file N)
Combined Data: [TCZ1/TCH1/TCD1...] (all files compressed together)
Advantages:
- Better compression ratio (shared dictionary across files)
- Smaller archive size (single compression overhead)
- Ideal for similar files (source code, text documents)
Disadvantages:
- Must decompress entire archive to extract any file
- Corruption may affect multiple files
- Sequential access only
Path Sanitization:
- Entry names must be relative paths (no leading
/or drive letters) - No
..components allowed (prevents directory traversal) - No absolute paths
- Symlinks are rejected during archive creation
Validation:
- Entry names validated during creation
- Extraction paths sanitized to prevent traversal attacks
- Symlinks resolved before archiving (prevented by default)
Archives can be encrypted by wrapping the entire TCAF structure:
Structure:
TCE1 [Salt] [Nonce] [Encrypted TCAF Archive] [Auth Tag]
- Password protects the entire archive (metadata and data)
- Authentication tag verifies archive integrity
- Decryption must succeed before archive can be parsed
Example:
Unencrypted: TCAF [version][algo][per_file][count][entries...]
Encrypted: TCE1 [salt][nonce][AES(TCAF...)][tag]
TechCompressor automatically detects formats by reading the 4-byte magic header:
with open(file, 'rb') as f:
magic = f.read(4)
if magic == b'TCZ1':
format = 'LZW'
elif magic == b'TCH1':
format = 'Huffman'
elif magic == b'TCD1':
format = 'DEFLATE'
elif magic == b'TCE1':
format = 'Encrypted'
elif magic == b'TCAF':
format = 'Archive'
else:
raise ValueError(f'Unknown format: {magic}')All multi-byte integers use big-endian (network byte order):
- Dictionary size:
struct.pack(">H", size) - Entry count:
struct.pack(">I", count) - Timestamps:
struct.pack(">Q", timestamp)
Current Version: 1.0.0 (TCAF version 1)
Future Compatibility:
- Magic headers are fixed and will not change
- TCAF version byte allows format evolution
- Future versions will read older archives
- Breaking changes will increment major version
Reserved Magic Headers:
TCA1- Reserved for Arithmetic codingTCB1- Reserved for BWT (Burrows-Wheeler Transform)TCS1- Reserved for Snappy algorithmTCR1- Reserved for custom/research algorithms
Archive Extensions:
- Metadata can be extended with new fields (version byte controls parsing)
- Custom attributes (permissions, extended attributes) can be added
- Compression settings (dictionary size, window size) can be stored
- Use buffered I/O for reading/writing archives
- Chunk size: 16MB for streaming large files
- Memory-map large archives for random access (future)
- Magic header mismatch:
ValueError("Invalid magic header") - Corrupted data:
ValueError("Corrupted {format} data") - Wrong password:
ValueError("Decryption failed - wrong password") - Invalid archive:
ValueError("Invalid TCAF archive")
- Test all magic headers with valid and invalid data
- Test encryption with correct and incorrect passwords
- Test archive modes with various file structures
- Test path traversal prevention (e.g.,
../../etc/passwd)
Hex dump:
54 43 5A 31 10 00 00 54 00 4F 00 42 ...
|T |C |Z |1| 4096 | T | O | B |...
Hex dump:
54 43 45 31 [16 bytes salt] [12 bytes nonce] [ciphertext] [16 bytes tag]
|T |C |E |1| ... ... ... ...
Hex dump:
54 43 41 46 01 03 01 00 00 00 02
|T |C |A |F| v1 |DEFL|pfil| 2 files |
00 00 00 08 66 69 6C 65 2E 74 78 74 00 [timestamp] [size] [data_len]
| name_len | f i l e . t x t | file| ... | ... | ... |
[TCD1...compressed data for file.txt...]
00 00 00 09 66 6F 6C 64 2F 66 32 2E 74 78 00 [timestamp] [size] [data_len]
| name_len | f o l d / f 2 . t x | file| ... | ... | ... |
[TCD1...compressed data for fold/f2.tx...]
TechCompressor's format design prioritizes:
- Simplicity: Easy to parse and implement
- Extensibility: Version bytes and magic headers allow evolution
- Security: Path sanitization, authentication tags, no backdoors
- Performance: Streaming support, chunked I/O, efficient encoding
- Interoperability: Well-documented formats enable third-party tools