diff --git a/_data/other_repo_list.csv b/_data/other_repo_list.csv
index 4503052..4c35840 100644
--- a/_data/other_repo_list.csv
+++ b/_data/other_repo_list.csv
@@ -27,7 +27,6 @@ https://git.Apture.io/mayx/blog
http://219.157.255.213:25311/mayx/blog
http://116.236.50.103:8789/mayx/blog
https://repo.gusdya.net/mayx/blog
-https://gitea.synapsetec.cn/mayx/blog
http://gitea.yunshanghub.com:8081/mayx/blog
http://152.69.204.151:3000/mayx/blog
http://187.216.152.151:9999/mayx/blog
@@ -68,7 +67,6 @@ http://39.101.74.135:5000/mayx/blog_cn
http://123.57.130.140:3000/mayx/blog_cn
http://118.24.46.223:3000/mayx/blog_cn
http://s3.v100.vip:31057/mayx/blog_cn
-http://101.33.225.95:3000/mayx/blog_cn
http://45.55.138.82:3000/mayx/blog_cn
http://118.24.129.148:3000/mayx/blog_cn
http://120.48.141.82:3000/mayx/blog_cn
@@ -119,9 +117,7 @@ http://tian-you.top:7020/mayx/blog
http://34.17.182.140/mayx-gogs/blog
https://mcgit.place/mayx/blog
http://git.instal.org.cn/mayx/blog
-https://git.smart-family.net/mayx/blog
https://git.chiasson.cloud/mayx/blog
-https://git.everestlinux.org/mayx/blog
https://repo.qruize.com/mayx/blog
https://git.xneon.org/mayx/blog
https://lab.dutt.ch/mayx/blog
@@ -132,11 +128,8 @@ https://gitea.deliverables.io/mayx/blog
http://23.182.16.150:3000/mayx/blog
https://git.ritonquilol.fr/mayx/blog
https://bis127.vse.cz/mayx/blog
-https://app.gitpasha.com/mayx/blog
https://git.jhammah.com/mayx/blog
-https://git.kemomimi.site/mayx/blog
https://gitea.kolesarhome.com/mayx/blog
-https://gitbucket.aint-no.info/mayx/blog
https://git.wikeo.ovh/mayx/blog
https://devcraft-dot.tech/mayx/blog
https://a-t-g.ru/mayx/blog
@@ -176,11 +169,9 @@ https://git.uj-s.com/mayx/blog
https://git.albiobola.nl/mayx/blog
https://git.83channel.net/mayx/blog
https://repo.paperless.rs/mayx/blog
-https://bolha.dev/mayx/blog
https://git.checkerwars.com/mayx/blog
https://git.broderlands.com/mayx/blog
https://gitea.schwegmann.tech/mayx/blog
-https://veretium.com/mayx/blog
https://gitea.kcm-nixi.cn:32443/mayx/blog
https://git.riskreduction.net/mayx/blog
https://git.twitchmagic.pro/mayx/blog
@@ -189,11 +180,19 @@ https://git.imagitech.mx/mayx/blog
https://github.jogjacloud.com/mayx/blog
https://git.stormofgalaxy.com/mayx/blog
https://git.jibai.dev/mayx/blog
-https://git.danfis.cz/mayx/blog
https://dev.rasadyar.com/mayx/blog
https://git.dew.vn/mayx/blog
https://git.recstar.club/mayx/blog
-http://www.1flow1.net/mayx/blog
https://git.ric-rac.org/mayx/blog
https://git.yan.best/mayx/blog
https://forgejo.cgr-international.com/mayx/blog
+https://yang-gitea.umersoft.com/mayx/blog
+https://synthesist.d4d.host/mayx/blog
+https://git.takits.me/mayx/blog
+https://gitea.zazlab.freeddns.org/mayx/blog
+https://gitweb.cn/mayx/blog
+https://forge.harusato.com/mayx/blog
+https://forgejo.siriusdevops.com/mayx/blog
+https://git.tessdev.fr/mayx/blog
+https://gitlab.navy.mi.th/mayx/blog
+https://forgejo.quantum-forge.io/mayx/blog
diff --git a/_posts/2026-11-01-compress.md b/_posts/2026-11-01-compress.md
new file mode 100644
index 0000000..a06ba85
--- /dev/null
+++ b/_posts/2026-11-01-compress.md
@@ -0,0 +1,1428 @@
+---
+layout: post
+title: 关于压缩的各种探索
+tags: [压缩, 探索, Quine, zstd]
+---
+
+ 压缩……在消除冗余的同时,又创造了新的混乱?
+
+# 对压缩比的追求
+ 上次我在做[博客的离线模式](/2026/10/01/quine.html)时,为了降低带宽的消耗,我把我的博客压缩包又用7-Zip额外压缩了一遍,从大约16MiB压缩到了4MiB,效果感觉挺不错。另外我又试了试几个常见的压缩算法,比如Zip、zstd、BZip2等,全部使用最高等级压缩,但压缩效果都不如使用LZMA2的7-Zip好,速度甚至还比7-Zip慢,看来LZMA2还是相当强啊。
+ 所以我在想,LZMA2是不是最强的压缩算法呢?虽然不同压缩算法可能对不同类型的数据效果不一样,但目前来看对我的数据来说,LZMA2看起来是最强的啊……不过这些只是常见算法,如果是用那些因为压缩速度慢而不太常见的算法,会不会比LZMA2更强呢?
+## ZPAQ
+ 我搜了一下,PAQ系列算法似乎是公认最强的,通过类似机器学习的算法花大量的时间达到更高的压缩比。其中比较知名的就是[ZPAQ](https://github.com/zpaq/zpaq),这个程序已经有10年不更新了,当然对于算法来说这点倒也不是什么问题,毕竟LZMA2也是十几年前的算法。最终我试着用它压缩我的博客压缩包,用了一分钟左右的时间,压缩到了3.5MiB,比7-Zip压缩的少了大约10%,感觉效果还不错。
+## PAQ8PX
+ 当然ZPAQ只是PAQ系列中的其中一个算法,有些人为了追求更高的压缩比,依然在对其进行改进,据我所知,目前仍在更新、压缩效果也非常出色的应该是[PAQ8PX](https://github.com/hxim/paq8px),我试着用v217版本压缩了一下,最终把压缩包压到了3.1MiB,真的是非常强。而代价也是极其高,首先压缩花了一个半小时,而且在这个过程中需要占用30GiB内存,更关键的问题是在解压时同样需要消耗这么多时间和资源,所以说这个算法真的是只能追求压缩比,基本上没办法正常使用……
+## NNCP
+ 除了PAQ系列之外,FFMPEG的作者[Fabrice Bellard](https://bellard.org)也做过一个使用机器学习的压缩算法,叫做[NNCP](https://bellard.org/nncp/),使用了和现代LLM同款的Transformer模型。于是我编译了一下,试着在RTX4090上压缩我的压缩包,也差不多用了一个半小时,结果压缩比还没LZMA2高😂,给我压到了4.1MiB,也许是因为我的博客里有些图片,而NNCP貌似是专攻英文文本的,所以效果差了不少……又一次证明了LZMA2真的很强啊~
+## cmix
+ 后来我又听说还有一个叫做[cmix](https://github.com/byronknoll/cmix)的压缩算法,一样是基于机器学习,据说效果好像还不错,只不过在我实际用v21版本测试的时候不知道为什么总是压到后面的时候就会崩溃……这个项目也有2年没更新了,可能是代码有什么BUG。而且和PAQ8PX一样内存占用很高,用时非常长,但就从崩溃的位置来看,它压缩一半的结果还是比PAQ8PX更大,看来这个压缩算法的地位有点尴尬啊……不知道它是不是又是针对文本特化过的算法,但目前的结果来看感觉不如PAQ8PX。
+## 总结
+ 最后PAQ8PX在这次测试中获得了最终的冠军🏆,我的博客压缩包里面包含的数据分布也算是有一定代表性吧,有一定的图片,大量的纯文本网页,和不少网站的结构应该很相似,所以这个压缩结果可能对不少数据都有一定的参考性。不过无论是PAQ8PX、NNCP还是cmix,它们压缩和解压需要的资源实在是太多了,不太适合一般情况下使用,至于ZPAQ虽然也是那种压缩和解压消耗相同的资源的算法,但作为十年前的东西来说,它在现在的速度还算是能在接受范围内,所以说如果想把不算太大的文件压到尽可能小,用ZPAQ看起来是最合适的选择,至于绝大多数的文件,还是用使用LZMA2算法的7-Zip吧~
+
+# 关于自包含压缩包的继续研究
+## zstd Quine
+ 在上次我做博客压缩包的时候,AI告诉我LZMA2和zstd都可以做能包含大文件的Quine,但我当时却以“zstd感觉不是很知名”的理由选择了LZMA2。然而实际上zstd甚至都有专门的[RFC 8878](https://datatracker.ietf.org/doc/html/rfc8878),甚至有不少网站都已经选择了zstd作为传输的压缩算法……既然如此,那我就让AI再简单研究一下zstd Quine吧,搜了一下以前也从来没人做过。
+ AI看了一眼规范之后,说这个比7z Quine制作起来在结构上会更简单,但在计算校验值上会更困难,简单是因为zstd支持一种叫做“可跳过帧”的东西,有这个东西就能在构建的时候有更多的自由度,不过zstd用的是一种叫做“有限状态熵”的编码方式,这个要重新研究一下。至于困难是因为zstd默认使用XXH64来校验,相比于7z格式默认使用的CRC32来说,它是非线性的,因此很难像CRC32那样靠几个公式轻松计算出来。不过有一点好处是XXH64的计算速度比CRC32快不少,而且zstd只校验XXH64结果的低32位,因此即使是通过爆破方式,也用不了多长时间就能计算出来。当然这个值和7-Zip一样都是可选的,其实不算也不影响什么,但既然能算的话就算一下呗~
+ 然后AI就开始想办法生成了,用了一个小时就做出来了,最开始它是直接做的`.zst`格式,但libarchive又开始出幺蛾子,显示`Input requires too many filters for decoding`错误,我试了一下[Gzip Quine](http://swtch.com/r.gz)用libarchive也有相同的问题……实在是令人难受,所以我又要求它改成`.tar.zst`格式,这样直接用Windows资源管理器也能直接打开,还增加了和我之前7z Quine一样的文件夹打包功能,说不定以后会用得上呢。
+ 顺便一说,XXH64虽然说是非线性的,但作为非密码学哈希,倒也可以在不爆破的情况下构造值,于是以下就是最终的生成代码:
+
+
+Show Code
+
+
+```python
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""Pack files/directories and a byte-identical copy of this .tar.zst archive.
+
+Example: python3 blogquine_tarzstd.py ./site ./site.tar.zst
+One directory packs its contents; multiple inputs retain their basenames.
+"""
+from __future__ import annotations
+
+import argparse
+import hashlib
+import os
+from pathlib import Path, PurePosixPath
+import stat
+import sys
+import tempfile
+import ctypes
+import ctypes.util
+import io
+import shutil
+import subprocess
+import tarfile
+from dataclasses import dataclass
+from functools import lru_cache
+
+BLOCK = 65536
+MASK = (1 << 64) - 1
+P1, P2 = 0x9E3779B185EBCA87, 0xC2B2AE3D27D4EB4F
+P3, P4 = 0x165667B19E3779F9, 0x85EBCA77C2B2AE63
+I1, I2 = pow(P1, -1, 1 << 64), pow(P2, -1, 1 << 64)
+LL_BASE = tuple(range(16)) + (16,18,20,22,24,28,32,40,48,64,128,256,512,1024,2048,4096,8192,16384,32768,65536)
+LL_BITS = (0,)*16 + (1,1,1,1,2,2,3,3,4,6,7,8,9,10,11,12,13,14,15,16)
+ML_BASE = tuple(range(3,35)) + (35,37,39,41,43,47,51,59,67,83,99,131,259,515,1027,2051,4099,8195,16387,32771,65539)
+ML_BITS = (0,)*32 + (1,1,1,1,2,2,3,3,4,4,5,7,8,9,10,11,12,13,14,15,16)
+
+
+def _rol(x: int, n: int) -> int:
+ return ((x << n) | (x >> (64 - n))) & MASK
+
+
+def _ror(x: int, n: int) -> int:
+ return ((x >> n) | (x << (64 - n))) & MASK
+
+
+def _round(v: int, w: int) -> int:
+ return _rol((v + w * P2) & MASK, 31) * P1 & MASK
+
+
+def checksum_for_size(size: int) -> int:
+ """XXH64 digest when all four terminal accumulators are zero."""
+ if size < 32 or size % 32:
+ raise ValueError("decoded size must be a positive multiple of 32")
+ h = 0
+ for _ in range(4):
+ h = (h * P1 + P4) & MASK
+ h = (h + size) & MASK
+ h ^= h >> 33
+ h = h * P2 & MASK
+ h ^= h >> 29
+ h = h * P3 & MASK
+ return h ^ (h >> 32)
+
+
+def force_words(data: bytes | bytearray, offset: int) -> bytes:
+ """Force the four final lanes to zero using four unique aligned words."""
+ if len(data) % 32 or offset % 8 or not 0 <= offset <= len(data)-32:
+ raise ValueError("invalid checksum patch position")
+ before = [(P1+P2)&MASK, P2, 0, (-P1)&MASK]
+ after = [0, 0, 0, 0]
+ view = memoryview(data)
+ for p in range(0, offset, 8):
+ lane = (p//8) % 4
+ before[lane] = _round(before[lane], int.from_bytes(view[p:p+8], "little"))
+ for p in range(len(data)-8, offset+31, -8):
+ lane = (p//8) % 4
+ w = int.from_bytes(view[p:p+8], "little")
+ after[lane] = (_ror(after[lane]*I1 & MASK, 31) - w*P2) & MASK
+ result = bytearray()
+ for p in range(offset, offset+32, 8):
+ lane = (p//8) % 4
+ w = ((_ror(after[lane]*I1 & MASK, 31) - before[lane])*I2) & MASK
+ result += w.to_bytes(8, "little")
+ return bytes(result)
+
+
+def _length_code(value, bases, widths):
+ for symbol, (base, width) in enumerate(zip(bases, widths)):
+ if base <= value < base + (1 << width):
+ return symbol, value-base, width
+ raise ValueError(f"unencodable Zstd length {value}")
+
+
+def _literal_header(n):
+ if n < 32:
+ return bytes((n << 3,))
+ if n < 4096:
+ return ((n << 4)|4).to_bytes(2,"little")
+ return ((n << 4)|12).to_bytes(3,"little")
+
+
+def _sequence(ll, ml, distance):
+ if distance < 1:
+ raise ValueError("back reference must be positive")
+ lc, lv, ln = _length_code(ll, LL_BASE, LL_BITS)
+ mc, mv, mn = _length_code(ml, ML_BASE, ML_BITS)
+ oc = (distance+3).bit_length()-1
+ if oc > 31:
+ raise ValueError("input needs a Zstd history window larger than 2 GiB")
+ ov = distance+3-(1 << oc)
+ bits = lv | (mv << ln) | (ov << (ln+mn)) | (1 << (ln+mn+oc))
+ stream = bits.to_bytes((ln+mn+oc+8)//8, "little")
+ return bytes((1, 0x54, lc, oc, mc)) + stream
+
+
+def _copy_block(literals, length, distance):
+ if len(literals)+length > 131072:
+ raise ValueError("Zstd decoded block exceeds 128 KiB")
+ seq = _sequence(len(literals), length, distance)
+ body = _literal_header(len(literals)) + literals + seq
+ return ((len(body)<<3)|4).to_bytes(3,"little") + body, seq
+
+
+def _raw_header(size):
+ return (size << 3).to_bytes(3, "little")
+
+
+def _parts(total):
+ """Nonempty pieces with length >=3 and bounded decoded block size."""
+ out = []
+ while total > BLOCK:
+ n = BLOCK
+ if total-n < 3:
+ n -= 3-(total-n)
+ out.append(n)
+ total -= n
+ if total:
+ if total < 3:
+ raise ValueError("internal block split too short")
+ out.append(total)
+ return out
+
+
+def _header(name, size, mtime):
+ info = tarfile.TarInfo(name)
+ info.size, info.mode, info.mtime = size, 0o644, mtime
+ info.uid = info.gid = 0
+ return info.tobuf(format=tarfile.PAX_FORMAT, encoding="utf-8", errors="surrogateescape")
+
+
+def _window_descriptor(required):
+ if required > (1 << 31):
+ raise ValueError("input needs a history window larger than the supported 2 GiB")
+ for wd in range(256):
+ base = 1 << (10 + (wd >> 3))
+ size = base + (base >> 3)*(wd & 7)
+ if size >= required:
+ return wd, size
+ raise ValueError("input exceeds the Zstandard frame window format")
+
+
+@lru_cache(maxsize=1)
+def _libzstd():
+ path = ctypes.util.find_library("zstd")
+ if not path:
+ raise RuntimeError("libzstd is required (install the Zstandard library)")
+ lib = ctypes.CDLL(path)
+ lib.ZSTD_decompress.argtypes = [ctypes.c_void_p,ctypes.c_size_t,ctypes.c_void_p,ctypes.c_size_t]
+ lib.ZSTD_decompress.restype = ctypes.c_size_t
+ lib.ZSTD_isError.argtypes = [ctypes.c_size_t]
+ lib.ZSTD_isError.restype = ctypes.c_uint
+ lib.ZSTD_getErrorName.argtypes = [ctypes.c_size_t]
+ lib.ZSTD_getErrorName.restype = ctypes.c_char_p
+ lib.ZSTD_compressBound.argtypes = [ctypes.c_size_t]
+ lib.ZSTD_compressBound.restype = ctypes.c_size_t
+ lib.ZSTD_compress.argtypes = [ctypes.c_void_p,ctypes.c_size_t,ctypes.c_void_p,ctypes.c_size_t,ctypes.c_int]
+ lib.ZSTD_compress.restype = ctypes.c_size_t
+ return lib
+
+
+def decompress(data: bytes, decoded_size: int) -> bytes:
+ """Decode and verify the one frame through the system reference library."""
+ try:
+ lib = _libzstd()
+ except RuntimeError:
+ try:
+ import zstandard
+ except ImportError:
+ command = shutil.which("zstd")
+ if not command:
+ raise RuntimeError("verification needs libzstd, Python zstandard, or the zstd executable") from None
+ result = subprocess.run([command,"-q","-d","-c","--long=31"],input=data,capture_output=True)
+ if result.returncode:
+ raise RuntimeError("Zstandard verification: "+result.stderr.decode(errors="replace").strip())
+ raw = result.stdout
+ else:
+ decoder = zstandard.ZstdDecompressor(max_window_size=1 << 31)
+ with decoder.stream_reader(io.BytesIO(data),read_across_frames=True) as reader:
+ raw = reader.read(decoded_size+1)
+ if reader.read(1):
+ raise RuntimeError("decoded data exceeds the declared size")
+ if len(raw) != decoded_size:
+ raise RuntimeError(f"decoded size mismatch: {len(raw)} != {decoded_size}")
+ return raw
+ dest = ctypes.create_string_buffer(decoded_size)
+ n = lib.ZSTD_decompress(dest, decoded_size, data, len(data))
+ if lib.ZSTD_isError(n):
+ raise RuntimeError("Zstandard verification: " + lib.ZSTD_getErrorName(n).decode())
+ if n != decoded_size:
+ raise RuntimeError(f"decoded size mismatch: {n} != {decoded_size}")
+ return dest.raw
+
+
+@dataclass
+class _Chunk:
+ kind: str
+ f: int
+ size: int
+ decoded: int
+ content: bytes = b""
+ source: int = 0
+
+
+def _build_quine(prefix_tar: bytes, quine_name: str, *, mtime=0, compressed=None):
+ """Return (archive, info, decoded TAR), adding only a self member.
+
+ The leading skippable frame is the quotation template. No seed TAR member
+ is created. The baseline stores source payloads once as raw Zstd literals.
+ """
+ template_size = 512
+ self_header = _header(quine_name, 1, mtime)
+ q = len(prefix_tar)+len(self_header)
+ chunks = []
+ f, o = template_size+6, 0
+ # Native prefix blocks may use a wider history than the quotation replay.
+ # Also, a block may regenerate at most min(window_size, 128 KiB).
+ max_distance = max(1,len(prefix_tar) if compressed is not None else 1)
+ raw_start = len(prefix_tar) if compressed is not None else 0
+ prefix_pieces = _parts(q-raw_start)
+ if compressed is not None:
+ chunks.append(_Chunk("code",f,len(compressed),len(prefix_tar),compressed))
+ f += len(compressed)
+ o += len(prefix_tar)
+ template_pieces = _parts(template_size)
+ # First output the actual TAR prefix, then the complete skippable template
+ # as the beginning of the embedded archive itself.
+ for size in prefix_pieces:
+ chunks.append(_Chunk("initial", f, 3+size, size, source=o))
+ f += 3+size
+ o += size
+ source = 0
+ for size in template_pieces:
+ chunks.append(_Chunk("template",f,3+size,size,source=source))
+ f += 3+size
+ o += size
+ source += size
+ # Emit the physical frame header, then quote every preceding RAW block.
+ # The tiny header literals are fixed structural bytes, not new payload copies.
+ chunks.append(_Chunk("framecopy",f,9,6))
+ f += 9
+ o += 6
+ if compressed is not None:
+ at = 0
+ while at < len(compressed):
+ literal = compressed[at:at+BLOCK]
+ code = _raw_header(len(literal))+literal
+ chunks.append(_Chunk("code",f,len(code),len(literal),code))
+ f += len(code)
+ o += len(literal)
+ at += len(literal)
+ for source_start,pieces in ((raw_start,prefix_pieces),(q,template_pieces)):
+ source = source_start
+ for size in pieces:
+ literal = _raw_header(size)
+ distance = o+3-source
+ code,_ = _copy_block(literal,size,distance)
+ chunks.append(_Chunk("code",f,len(code),3+size,code))
+ f += len(code)
+ o += 3+size
+ source += size
+ max_distance = max(max_distance,distance)
+ # A quote/replay gear may itself use multiple RAW chunks. Its quoted source
+ # ends just before the FIRST new RAW payload, so no circular data is read.
+ for _ in range(64):
+ gap = f-(o-q)
+ if gap <= 0:
+ raise RuntimeError("invalid forward quotation gap")
+ start_o = o
+ group = _parts(gap+3)
+ source = 0
+ for size in group:
+ chunks.append(_Chunk("gear",f,3+size,size,source=o-q))
+ f += 3+size
+ o += size
+ for index,size in enumerate(group):
+ literal = _raw_header(size) if index else b""
+ distance = o+len(literal)-(start_o+source)
+ code,_ = _copy_block(literal,size,distance)
+ chunks.append(_Chunk("code",f,len(code),len(literal)+size,code))
+ f += len(code)
+ o += len(literal)+size
+ source += size
+ max_distance = max(max_distance,distance)
+ if f-(o-q) <= 24:
+ break
+ else:
+ raise RuntimeError("quotation gear normalization did not converge")
+ plant_pos,tail_pos = q+32,q+256
+ choice = None
+ for empty in range(32):
+ jf = f+3*empty
+ gap = jf-(o-q)
+ distance = o-plant_pos
+ for length in range(max(3,gap+5),min(220,gap+40)):
+ jump,_ = _copy_block(b"",length,distance)
+ if length != gap+len(jump)+5:
+ continue
+ patch_f = jf+len(jump)+5
+ if patch_f % 8:
+ continue
+ xo = o+length
+ match = 15
+ for _ in range(10):
+ xcode,sx = _copy_block(bytes(32),match,xo+32-tail_pos)
+ new_match = len(sx)+8
+ if new_match == match:
+ break
+ match = new_match
+ else:
+ continue
+ total = jf+len(jump)+len(xcode)+8
+ choice = (total,empty,length,jump,xcode,sx,patch_f,xo)
+ break
+ if choice:
+ break
+ if choice is None:
+ raise RuntimeError("no aligned terminal block layout")
+ total,empty,length,jump,xcode,sx,patch_f,xo = choice
+ for _ in range(empty):
+ chunks.append(_Chunk("code",f,3,0,bytes(3)))
+ f += 3
+ jump_output = o
+ chunks.append(_Chunk("code",f,len(jump),length,jump))
+ f += len(jump)
+ o += length
+ chunks.append(_Chunk("code",f,len(xcode),32+len(sx)+8,xcode))
+ f += len(xcode)
+ o += 32+len(sx)+8
+ padding = (-total)%512+1024
+ decoded_size = q+total+padding
+ if o != q+total or f+8 != total:
+ raise RuntimeError("terminal self-copy equation did not close")
+ checksum = checksum_for_size(decoded_size)
+ checksum_bytes = (checksum & 0xffffffff).to_bytes(4,"little")
+ rle = ((padding << 3)|3).to_bytes(3,"little") + b"\0"
+ max_distance = max(max_distance,jump_output-plant_pos,xo+32-tail_pos)
+ wd,window_size = _window_descriptor(max_distance)
+ frame_header = bytes.fromhex("28b52ffd04") + bytes((wd,))
+ out = bytearray(total)
+ out[:8] = bytes.fromhex("502a4d18")+(template_size-8).to_bytes(4,"little")
+ out[template_size:template_size+6] = frame_header
+ for chunk in chunks:
+ if chunk.kind == "code":
+ out[chunk.f:chunk.f+chunk.size] = chunk.content
+ elif chunk.kind == "framecopy":
+ out[chunk.f:chunk.f+chunk.size] = _raw_header(6)+frame_header
+ else:
+ out[chunk.f:chunk.f+3] = _raw_header(chunk.decoded)
+ out[-8:-4],out[-4:] = rle,checksum_bytes
+ template = bytearray(out[:template_size])
+ plant = out[jump_output-q:jump_output-q+length]
+ if len(plant) != length or 32+length > 256:
+ raise RuntimeError("skippable jump template overflow")
+ template[32:32+length] = plant
+ tail = sx+rle+checksum_bytes
+ template[256:256+len(tail)] = tail
+ note = b"\nZstandard quine template; checksum solved by lane inversion.\n"
+ template[320:] = (note*5)[:192]
+ out[:template_size] = template
+ self_header = _header(quine_name,total,mtime)
+ if len(prefix_tar)+len(self_header) != q:
+ raise ValueError("self header changed serialized length; input too large for this layout")
+ tar_prefix = prefix_tar+self_header
+ for chunk in chunks:
+ if chunk.kind == "initial":
+ out[chunk.f+3:chunk.f+chunk.size] = tar_prefix[chunk.source:chunk.source+chunk.decoded]
+ elif chunk.kind == "template":
+ out[chunk.f+3:chunk.f+chunk.size] = template[chunk.source:chunk.source+chunk.decoded]
+ elif chunk.kind == "gear":
+ out[chunk.f+3:chunk.f+chunk.size] = out[chunk.source:chunk.source+chunk.decoded]
+ raw = bytearray(decoded_size)
+ raw[:q] = tar_prefix
+ raw[q:q+total] = out
+ patch = force_words(raw,q+patch_f)
+ out[patch_f:patch_f+32] = patch
+ raw[q+patch_f:q+patch_f+32] = patch
+ archive = bytes(out)
+ actual = decompress(archive,decoded_size)
+ if actual != raw:
+ mismatch = next((p for p,(a,b) in enumerate(zip(actual,raw)) if a != b),min(len(actual),len(raw)))
+ raise RuntimeError(f"self reproduction mismatch at decoded offset {mismatch}")
+ info = dict(quine_name=quine_name,decoded_size=decoded_size,quine_offset=q,
+ frame_count=1,skippable_frames=1,compressed_size=total,
+ checksum=f"{checksum & 0xffffffff:08x}",xxh64=f"{checksum:016x}",
+ window_size=window_size,patch_offset=patch_f,block_count=len(chunks)+1,
+ prefix_size=len(prefix_tar),template_size=template_size,
+ payload_mode="compressed" if compressed is not None else "store",
+ compressed_prefix_size=len(compressed) if compressed is not None else None)
+ return archive,info,actual
+
+
+def _compress_blocks(data: bytes, level: int) -> bytes:
+ """Independent source-prefix blocks, ready to execute after our frame header."""
+ try:
+ lib = _libzstd()
+ except RuntimeError:
+ try:
+ import zstandard
+ except ImportError:
+ command = shutil.which("zstd")
+ if not command:
+ raise RuntimeError("compression needs libzstd, Python zstandard, or the zstd executable") from None
+ option = f"--fast={-level}" if level < 0 else f"-{level or 3}"
+ result = subprocess.run([command,"-q","--no-check","--ultra",option,"-c"],input=data,capture_output=True)
+ if result.returncode:
+ raise RuntimeError("Zstandard prefix compression: "+result.stderr.decode(errors="replace").strip())
+ frame = bytearray(result.stdout)
+ else:
+ frame = bytearray(zstandard.ZstdCompressor(level=level,write_checksum=False).compress(data))
+ else:
+ capacity = lib.ZSTD_compressBound(len(data))
+ dest = ctypes.create_string_buffer(capacity)
+ result = lib.ZSTD_compress(dest,capacity,data,len(data),level)
+ if lib.ZSTD_isError(result):
+ raise RuntimeError("Zstandard prefix compression: "+lib.ZSTD_getErrorName(result).decode())
+ frame = bytearray(dest.raw[:result])
+ descriptor = frame[4]
+ single = bool(descriptor & 32)
+ dictionary_size = (0,1,2,4)[descriptor & 3]
+ fcs_flag = descriptor >> 6
+ content_size = (1 if single else 0,2,4,8)[fcs_flag]
+ header_size = 5+(0 if single else 1)+dictionary_size+content_size
+ at = header_size
+ while True:
+ if at+3 > len(frame):
+ raise RuntimeError("truncated native prefix frame")
+ h = int.from_bytes(frame[at:at+3],"little")
+ last,kind,size = h & 1,(h >> 1) & 3,h >> 3
+ if kind == 3:
+ raise RuntimeError("invalid native prefix block")
+ frame[at] &= 254
+ at += 3+(1 if kind == 1 else size)
+ if last:
+ break
+ if at+(4 if descriptor & 4 else 0) != len(frame):
+ raise RuntimeError("unexpected native prefix frame suffix")
+ return bytes(frame[header_size:at])
+
+
+def build_quine(prefix_tar: bytes, quine_name: str, *, mtime=0, level=9,
+ verify_decoded=None):
+ """Build a seedless single-data-frame TAR quine.
+
+ level=None stores the source prefix once verbatim. An integer enables native
+ prefix compression when its three encoded copies plus overhead are smaller
+ than the raw prefix. This avoids expanding incompressible payloads. Both
+ paths use the same algebraic checksum construction and contain no seed file.
+ After standard decoding and self-copy verification, an optional callback
+ receives (archive, decoded_tar) for additional checks without decoding again.
+ """
+ if len(prefix_tar) % 512:
+ raise ValueError("prefix_tar must end on a 512-byte TAR boundary")
+ if not quine_name:
+ raise ValueError("self member name must be nonempty")
+ if level is not None and (not isinstance(level,int) or not -131072 <= level <= 22):
+ raise ValueError("compression level must be between -131072 and 22")
+ compressed = None
+ if level is not None and prefix_tar:
+ candidate = _compress_blocks(prefix_tar,level)
+ if 3*len(candidate)+2048 < len(prefix_tar):
+ compressed = candidate
+ result,info,decoded = _build_quine(prefix_tar,quine_name,mtime=mtime,compressed=compressed)
+ if verify_decoded is not None:
+ verify_decoded(result,decoded)
+ info["compression_level"] = level
+ return result,info
+
+
+@dataclass
+class Entry:
+ name: str
+ kind: str
+ mode: int
+ path: Path | None = None
+ link: str = ""
+ size: int = 0
+ digest: bytes = b""
+
+
+def archive_name(value: str, *, empty: bool = False) -> str:
+ """Validate a relative POSIX member path without silently truncating it."""
+ if "\0" in value or value.startswith("/") or ".." in value.split("/"):
+ raise ValueError(f"unsafe archive path: {value!r}")
+ if len(value) >= 2 and value[1] == ":":
+ raise ValueError(f"archive path must be relative: {value!r}")
+ name = str(PurePosixPath(value))
+ if name == ".":
+ if empty:
+ return ""
+ raise ValueError("archive member name cannot be empty")
+ return name
+
+
+def join_name(prefix: str, name: str) -> str:
+ return archive_name(f"{prefix}/{name}" if prefix else name)
+
+
+def collect_entries(inputs: list[Path], output: Path, prefix: str,
+ reserved: str) -> tuple[list[Entry], bool]:
+ entries: list[Entry] = []
+ names: dict[str, Entry] = {}
+ excluded = False
+ output_absolute = os.path.abspath(output)
+ if any(os.path.abspath(path) == output_absolute for path in inputs):
+ raise ValueError("output cannot also be an explicit input")
+
+ def add(entry: Entry) -> None:
+ entry.name = archive_name(entry.name)
+ old = names.get(entry.name)
+ if old is not None:
+ if old.kind == entry.kind == "directory" and old.path is None:
+ old.path, old.mode = entry.path, entry.mode
+ return
+ raise ValueError(f"duplicate archive path: {entry.name}")
+ names[entry.name] = entry
+ entries.append(entry)
+
+ def parents(name: str) -> None:
+ parts = PurePosixPath(name).parts
+ for end in range(1, len(parts)):
+ parent = "/".join(parts[:end])
+ existing = names.get(parent)
+ if existing is not None:
+ if existing.kind != "directory":
+ raise ValueError(f"archive parent is not a directory: {parent}")
+ else:
+ add(Entry(parent, "directory", 0o755))
+
+ def walk(path: Path, name: str) -> None:
+ nonlocal excluded
+ if os.path.abspath(path) == output_absolute:
+ excluded = True
+ return
+ st = path.lstat()
+ parents(name)
+ mode = stat.S_IMODE(st.st_mode)
+ if stat.S_ISLNK(st.st_mode):
+ add(Entry(name, "symlink", mode, path, os.readlink(path)))
+ elif stat.S_ISDIR(st.st_mode):
+ add(Entry(name, "directory", mode, path))
+ for child in sorted(path.iterdir(), key=lambda p: p.name):
+ walk(child, join_name(name, child.name))
+ elif stat.S_ISREG(st.st_mode):
+ add(Entry(name, "file", mode, path))
+ else:
+ raise ValueError(f"unsupported special file (not read): {path}")
+
+ # Explicit parents also cover empty sources and custom self locations.
+ parents(reserved)
+ if prefix:
+ parents(prefix + "/placeholder")
+ for path in inputs:
+ st = path.lstat() # Fail for nonexistent inputs, including broken parents.
+ if len(inputs) == 1 and stat.S_ISDIR(st.st_mode):
+ for child in sorted(path.iterdir(), key=lambda p: p.name):
+ walk(child, join_name(prefix, child.name))
+ else:
+ walk(path, join_name(prefix, path.name))
+ if reserved in names:
+ raise ValueError(f"source collides with reserved archive member: {reserved}")
+ for name in names:
+ if name.startswith(reserved + "/"):
+ raise ValueError(f"reserved file would replace a directory: {reserved}")
+ return entries, excluded
+
+
+def encode_entries(entries: list[Entry], mtime: int) -> bytes:
+ out = bytearray()
+ for entry in entries:
+ member = tarfile.TarInfo(entry.name)
+ member.mode, member.mtime = entry.mode, mtime
+ data = b""
+ if entry.kind == "directory":
+ member.type = tarfile.DIRTYPE
+ elif entry.kind == "symlink":
+ member.type, member.linkname = tarfile.SYMTYPE, entry.link
+ else:
+ flags = os.O_RDONLY | getattr(os, "O_BINARY", 0) | getattr(os, "O_NOFOLLOW", 0)
+ assert entry.path is not None
+ with os.fdopen(os.open(entry.path, flags), "rb") as source:
+ before = os.fstat(source.fileno())
+ if not stat.S_ISREG(before.st_mode):
+ raise ValueError(f"input is no longer a regular file: {entry.path}")
+ data = source.read()
+ after = os.fstat(source.fileno())
+ if (len(data) != before.st_size or before.st_size != after.st_size or
+ before.st_mtime_ns != after.st_mtime_ns):
+ raise ValueError(f"input changed while reading: {entry.path}")
+ entry.size, entry.digest = len(data), hashlib.sha256(data).digest()
+ member.size = entry.size
+ out.extend(member.tobuf(format=tarfile.PAX_FORMAT, encoding="utf-8",
+ errors="surrogateescape"))
+ out.extend(data)
+ out.extend(bytes((-len(data)) % 512))
+ return bytes(out)
+
+
+def verify_archive(archive: bytes, raw: bytes, entries: list[Entry],
+ quine_name: str) -> None:
+ """Check members using the core's already checksum-verified decoded bytes."""
+ if len(raw) % 512 or raw[-1024:] != bytes(1024):
+ raise ValueError("TAR is missing its complete zero end records")
+ with tarfile.open(fileobj=io.BytesIO(raw), mode="r:") as tar:
+ members = tar.getmembers()
+ by_name = {member.name.rstrip("/"): member for member in members}
+ if len(by_name) != len(members):
+ raise ValueError("duplicate member in generated TAR")
+ expected = {entry.name for entry in entries} | {quine_name}
+ if set(by_name) != expected:
+ raise ValueError("TAR member list does not match the input snapshot")
+ member = by_name[quine_name]
+ if not member.isfile() or tar.extractfile(member).read() != archive:
+ raise ValueError("Quine member is not byte-identical to the archive")
+ for entry in entries:
+ member = by_name[entry.name]
+ if entry.kind == "directory":
+ ok = member.isdir()
+ elif entry.kind == "symlink":
+ ok = member.issym() and member.linkname == entry.link
+ else:
+ ok = (member.isfile() and member.size == entry.size and
+ hashlib.sha256(tar.extractfile(member).read()).digest() == entry.digest)
+ if not ok or stat.S_IMODE(member.mode) != entry.mode:
+ raise ValueError(f"input entry did not survive packing: {entry.name}")
+
+
+def atomic_write(path: Path, data: bytes, force: bool) -> None:
+ if path.exists() and not force:
+ raise FileExistsError(f"output exists; use --force to replace it: {path}")
+ temporary = None
+ try:
+ with tempfile.NamedTemporaryFile(prefix=".zstd-quine-", dir=path.parent,
+ delete=False) as output:
+ temporary = Path(output.name)
+ output.write(data)
+ output.flush()
+ os.fsync(output.fileno())
+ if force:
+ os.replace(temporary, path)
+ else:
+ # link is atomic and cannot overwrite a file created after the check.
+ os.link(temporary, path)
+ temporary.unlink()
+ temporary = None
+ finally:
+ if temporary is not None:
+ temporary.unlink(missing_ok=True)
+
+
+def main(argv: list[str] | None = None) -> int:
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("inputs", metavar="INPUT", nargs="+", type=Path)
+ parser.add_argument("output", metavar="OUTPUT", type=Path)
+ parser.add_argument("--quine-name", help="self member name (default: output basename)")
+ parser.add_argument("--src-dir", default="", help="archive prefix for source entries")
+ parser.add_argument("--quine-dir", default="", help="archive prefix for the self member")
+ parser.add_argument("--mtime", type=int, default=0, help="fixed TAR timestamp (default: 0)")
+ compression = parser.add_mutually_exclusive_group()
+ compression.add_argument("--level", type=int, default=9,
+ help="Zstd source compression level (default: 9; auto-falls back to storage)")
+ compression.add_argument("--store", dest="level", action="store_const", const=None,
+ help="store the source prefix without trying compression")
+ parser.add_argument("--force", action="store_true", help="replace an existing output after verification")
+ args = parser.parse_args(argv)
+ try:
+ if args.output.is_symlink():
+ raise ValueError("output must not be a symbolic link")
+ if args.output.exists() and not args.output.is_file():
+ raise ValueError("output must be a regular file path")
+ if args.output.exists() and not args.force:
+ raise FileExistsError(f"output exists; use --force to replace it: {args.output}")
+ if not args.output.parent.is_dir():
+ raise ValueError(f"output directory does not exist: {args.output.parent}")
+ prefix = archive_name(args.src_dir, empty=True)
+ quine_dir = archive_name(args.quine_dir, empty=True)
+ quine = join_name(quine_dir, archive_name(args.quine_name or args.output.name))
+ entries, excluded = collect_entries(args.inputs, args.output, prefix, quine)
+ prefix_tar = encode_entries(entries, args.mtime)
+ archive, info = build_quine(
+ prefix_tar, quine, mtime=args.mtime, level=args.level,
+ verify_decoded=lambda data, raw: verify_archive(data, raw, entries, quine),
+ )
+ atomic_write(args.output, archive, args.force)
+ files = sum(entry.kind == "file" for entry in entries)
+ dirs = sum(entry.kind == "directory" for entry in entries)
+ links = sum(entry.kind == "symlink" for entry in entries)
+ print(f"[tar.zst quine] {files} files, {dirs} directories, {links} symlinks")
+ if excluded:
+ print("[tar.zst quine] excluded the output path from source traversal")
+ print(f"[tar.zst quine] wrote {args.output}: {len(archive)} bytes")
+ print(f"[layout] {info['frame_count']} checked data frame; payload mode: {info['payload_mode']}; "
+ f"window: {info['window_size']} bytes; XXH64: {info['checksum']}")
+ print("[verify] standard Zstd checksum, TAR contents and exact self: PASS")
+ print(f"[self] {quine}")
+ return 0
+ except (OSError, ValueError, RuntimeError, tarfile.TarError) as error:
+ print(f"error: {error}", file=sys.stderr)
+ return 1
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
+```
+
+
+ 现在AI写的代码真的是越来越复杂了,真的是根本看不懂啊……但就是这样,很神奇的就把问题解决了。总之,zstd Quine也轻松实现了,也算是给自包含压缩包再提供一种新的格式吧。
+
+## ZIP Quine
+ 后来闲的没事又让AI继续研究有没有可能做出大文件的ZIP Quine,结果它研究了一段时间还真让它研究出来了,当然[Ruben Van Mello](https://github.com/ruvmello)所说的窗口大小的问题依然存在,只不过AI用了某种方式绕过去了,而代价则是会存在成员数据有重叠的部分。比如在Python的标准库zipfile中,在[这里](https://github.com/python/cpython/blob/3fb88e94db547e9dbed97de68da87bcf9335a53a/Lib/zipfile/__init__.py#L2276)有检查自身成员压缩数据是不是越过了后续成员的局部头,导致我这种方法生成的ZIP Quine无法被解压,然而7-Zip和libarchive都能正常解压……总之这种方式生成的有一点点兼容性问题,但问题不是很严重,那么以下就是这种生成器的代码:
+
+
+Show Code
+
+
+```python
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""Pack files/directories plus an exact copy of this ZIP archive.
+
+Example: python zip_quine.py ./site ./site.zip
+One directory packs its contents; multiple inputs retain their basenames.
+Python 3.10+; standard library only. Extract with 7-Zip or libarchive.
+The archive deliberately shares physical bytes between overlapping members.
+"""
+from __future__ import annotations
+import argparse
+import io
+import os
+import stat
+import struct
+import sys
+import tempfile
+import time
+import zipfile
+import zlib
+from pathlib import Path, PurePosixPath
+
+LBASE = list(range(3, 11)) + [11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258]
+LBITS = [0]*8 + [1]*4 + [2]*4 + [3]*4 + [4]*4 + [5]*4 + [0]
+DBASE = [1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577]
+DBITS = [0]*4 + [v for n in range(1,14) for v in [n,n]]
+
+CL_ORDER = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1]
+CL_LEN = {0: 1, 1: 3, 17: 3, 18: 2}
+# CL codes in stream order (MSB of the Huffman code first):
+# 0 -> "0", 18 -> "10", 1 -> "110", 17 -> "111"
+CL_CODE = {0: (0b0, 1), 18: (0b1, 2), 1: (0b011, 3), 17: (0b111, 3)}
+
+# (cell length, zero-length prefix, code lengths per unit copy).
+# Exhaustively found for the fixed distance-8 match used by unit_bytes().
+CONNECTORS = [
+ (576, 9, 129), (639, 9, 129), (927, 33, 118), (32872, 1, 128),
+ (33772, 49, 118), (39936, 17, 120), (39951, 17, 120), (39953, 9, 124),
+ (39999, 17, 120), (40732, 41, 108), (40944, 17, 120), (45559, 33, 124),
+ (45560, 33, 120), (49300, 1, 134), (49934, 57, 107), (50078, 49, 107),
+ (57356, 49, 118), (57373, 1, 129), (57374, 25, 117), (57572, 1, 133),
+ (57599, 41, 118), (57854, 41, 117), (58126, 57, 107), (58319, 49, 107),
+ (59264, 25, 117), (59390, 25, 117), (60536, 41, 120), (60540, 41, 118),
+ (61540, 9, 129), (61903, 49, 107), (63495, 25, 118), (63544, 33, 118),
+ (63608, 33, 117), (63743, 41, 118), (63943, 41, 110), (63984, 25, 118),
+ (64423, 25, 124), (64551, 25, 120), (65048, 49, 117), (65311, 33, 118),
+ (65420, 49, 118), (65436, 25, 120),
+]
+
+
+class Bits:
+ def __init__(self):
+ self.value = 0
+ self.count = 0
+
+ def put(self, value, width):
+ assert 0 <= value < (1 << width), (value, width)
+ self.value |= value << self.count
+ self.count += width
+
+ def align(self):
+ self.put(0, -self.count % 8)
+
+ def bytes(self):
+ return self.value.to_bytes((self.count + 7) // 8, 'little')
+
+
+def reverse(value, width):
+ return int(f'{value:0{width}b}'[::-1], 2)
+
+
+def symbol(bits, s):
+ if s <= 143:
+ code, width = 0x30+s, 8
+ elif s <= 255:
+ code, width = 0x190+s-144, 9
+ elif s <= 279:
+ code, width = s-256, 7
+ else:
+ code, width = 0xc0+s-280, 8
+ bits.put(reverse(code, width), width)
+
+
+def number(value, bases, widths):
+ for i, (base, width) in enumerate(zip(bases, widths)):
+ if base <= value < base + (1 << width):
+ return i, value - base, width
+ raise ValueError(value)
+
+
+def copy_code(length, distance):
+ assert 3 <= length and 1 <= distance <= 32768
+ bits = Bits()
+ bits.put(2, 3)
+ remaining = length
+ while remaining:
+ size = min(258, remaining)
+ if 0 < remaining - size < 3:
+ size -= 3 - (remaining - size)
+ slot, extra, width = number(size, LBASE, LBITS)
+ symbol(bits, 257 + slot)
+ bits.put(extra, width)
+ slot, extra, width = number(distance, DBASE, DBITS)
+ bits.put(reverse(slot, 5), 5)
+ bits.put(extra, width)
+ remaining -= size
+ symbol(bits, 256)
+ bits.put(0, 3)
+ bits.align()
+ bits.put(0, 16)
+ bits.put(0xffff, 16)
+ return bits.bytes()
+
+
+def raw_header(size):
+ assert 0 <= size <= 65535
+ return b'\0' + struct.pack(' 257 literal lengths
+ w.put(29, 5) # HDIST=29 -> 30 distance codes
+ w.put(14, 4) # HCLEN=14 -> 18 CL lengths
+ for s in CL_ORDER:
+ w.put(CL_LEN.get(s, 0), 3)
+ assert w.count == 71
+ w.put(0, m) # m zero lengths (m == 1 mod 8)
+ assert w.count % 8 == 0
+ for b in unit:
+ w.put(b, 8)
+ return w.bytes()
+
+
+def payload_head(m, c1, final):
+ window_end = m + 2 * c1
+ first_free = max(257, window_end)
+ count = 287 - first_free
+ if count < 2:
+ raise ValueError('no free distance codes')
+ w = Bits()
+ for i in range(count):
+ w.put(*(CL_CODE[1] if i < 2 else CL_CODE[0]))
+ w.put(1, 1) # EOB (literal code 1)
+ w.put(1 if final else 0, 3) # stored block header
+ w.align()
+ return w.bytes()
+
+
+def geometry(lc, m, c1):
+ head = payload_head(m, c1, False)
+ return dict(lc=lc, m=m, unit=unit_bytes(lc), p_head=len(head)+4,
+ k=8+(71+m)//8, head=head,
+ head_final=payload_head(m, c1, True))
+
+
+UINT32 = 0xffffffff
+UTF8_FLAG = 0x800
+
+
+def _stamp(epoch):
+ if epoch <= 315532800:
+ return 0, 33
+ t = time.gmtime(min(epoch, 4354819198))
+ return ((t.tm_hour << 11) | (t.tm_min << 5) | (t.tm_sec // 2),
+ ((t.tm_year - 1980) << 9) | (t.tm_mon << 5) | t.tm_mday)
+
+
+def _extra_padding(size):
+ if not size:
+ return b''
+ if size < 4:
+ raise ValueError('extra padding needs at least four bytes')
+ return struct.pack(' 60000:
+ raise ValueError(f'UTF-8 archive path exceeds 60000 bytes: {name!r}')
+ data = bytes(e.get('data', b''))
+ if e['is_dir'] and data:
+ raise ValueError('directory entries cannot have data')
+ e.update(name=name, encoded=encoded, data=data, size=len(data),
+ mtime=e.get('mtime', mtime), crc=crc(data), method=0,
+ mode=e.get('mode', (stat.S_IFDIR | 0o755) if e['is_dir']
+ else (stat.S_IFREG | 0o644)), csize=len(data))
+ if len(data) >= UINT32:
+ raise ValueError('ZIP64 is not implemented: a member is too large')
+ return e
+
+
+def _large_plan(e):
+ best = None
+ base = 30 + len(e['encoded'])
+ for values in CONNECTORS:
+ g = geometry(*values)
+ lc, ph, k = g['lc'], g['p_head'], g['k']
+ first_cap, middle_cap, last_cap = lc - base - 5 - k, lc - ph - k, lc - ph - 8
+ if min(first_cap, middle_cap, last_cap) < 4:
+ continue
+ count = 2 + max(0, (e['size'] - first_cap - last_cap + middle_cap - 1) // middle_cap)
+ left = e['size'] - (count - 2) * middle_cap
+ first = min(first_cap, left - 4)
+ if first < 1:
+ continue
+ extra = first_cap - first
+ if 0 < extra < 4:
+ first -= 4 - extra
+ extra = 4
+ last = left - first
+ if not 1 <= last <= last_cap:
+ continue
+ physical = count * lc + (count - 1) * 8
+ candidate = dict(g, count=count, first=first, middle=middle_cap,
+ last=last, extra=extra, physical=physical,
+ csize=e['size'] + 5 + (count - 1) * (k + 8 + ph))
+ if best is None or physical < best['physical']:
+ best = candidate
+ if best is None:
+ raise ValueError(f'cannot fit payload layout for {e["name"]!r}')
+ return best
+
+
+def _solve_patch(baseline):
+ # The final four bytes are a unique free field in the archive comment.
+ # CRC differences do not depend on the prefix bytes, so this needs only
+ # two full-archive CRC scans and 32 tiny four-byte computations.
+ zero = crc(bytes(4))
+ cols = [crc((1 << i).to_bytes(4, 'little')) ^ zero for i in range(32)]
+ rows = [sum(((value >> bit) & 1) << col for col, value in enumerate(cols))
+ | (((baseline >> bit) & 1) << 32) for bit in range(32)]
+ for col in range(32):
+ pivot = next((r for r in range(col, 32) if rows[r] >> col & 1), None)
+ if pivot is None:
+ raise RuntimeError('CRC patch matrix unexpectedly singular')
+ rows[col], rows[pivot] = rows[pivot], rows[col]
+ for r in range(32):
+ if r != col and rows[r] >> col & 1:
+ rows[r] ^= rows[col]
+ return sum(((rows[i] >> 32) & 1) << i for i in range(32)).to_bytes(4, 'little')
+
+
+def build(entries, self_name, *, mtime=0):
+ """Return ZIP bytes containing the inputs and a byte-identical self member.
+
+ Each entry has name, data, is_dir, mode and optional mtime. Unix type bits
+ in mode are preserved, including symlinks whose data is their target text.
+ """
+ items = [_entry(e, mtime) for e in entries]
+ me = _entry(dict(name=self_name, data=b'', mode=stat.S_IFREG | 0o644), mtime)
+ if len(me['encoded']) > 32000:
+ raise ValueError('self member name is too long for the bootstrap window')
+ names = [me['name'].rstrip('/').casefold()] + [e['name'].rstrip('/').casefold() for e in items]
+ if len(set(names)) != len(names):
+ raise ValueError('duplicate or case-colliding member names')
+ if len(items) + 1 >= 65535:
+ raise ValueError('ZIP64 is not implemented: too many members')
+ me.update(method=8, crc=0, local_offset=0)
+ h = 30 + len(me['encoded']) + 260
+ p0 = h + 5
+ plant_at = 30 + len(me['encoded']) + 12
+ first = copy_code(p0, p0)
+ jump = None
+ for length in range(3, 4096):
+ code = copy_code(length, 2 * p0 - plant_at)
+ if length == len(first) + len(code) + 5:
+ jump = code
+ break
+ if jump is None:
+ raise ValueError('no bootstrap layout for this self name')
+ if len(first) + len(jump) + 5 > 248:
+ raise ValueError('self member name needs a bootstrap template larger than 248 bytes; use a shorter name')
+ prefix_size = h + 5 + p0 + len(first) + len(jump) + 5
+ cells, pending, pending_entries = [], bytearray(), []
+
+ def flush_small():
+ nonlocal pending, pending_entries
+ if pending_entries:
+ for e, relative in pending_entries:
+ e['cell_index'], e['cell_relative'] = len(cells), relative
+ cells.append(bytearray(pending) + bytes(8))
+ pending, pending_entries = bytearray(), []
+
+ for e in items:
+ record_size = 30 + len(e['encoded']) + len(e['data'])
+ if record_size <= 65527:
+ if len(pending) + record_size > 65527:
+ flush_small()
+ pending_entries.append((e, len(pending)))
+ pending += _local(e) + e['data']
+ continue
+ flush_small()
+ g = _large_plan(e)
+ e.update(method=8, csize=g['csize'], cell_index=len(cells), cell_relative=0)
+ tail, at = connector_tail(g['unit'], g['m']), g['first']
+ cell = (_local(e, extra=_extra_padding(g['extra']))
+ + b'\0' + struct.pack(' 65000 and current:
+ batches.append(current)
+ current, size = [], 0
+ current.append(e)
+ size += record_size
+ batches.append(current)
+ cd_start = position if cells else prefix_size
+ cd_size = sum(46 + len(e['encoded']) for e in all_entries) + 20 * (len(batches) - 1)
+ directory_sizes = [sum(46 + len(e['encoded']) for e in batch)
+ + (12 if i < len(batches) - 1 else 26)
+ for i, batch in enumerate(batches)]
+ total = (prefix_size + sum(map(len, cells)) + sum(directory_sizes)
+ + 8 * (len(cells) + len(batches) - 1))
+ if max(total, cd_start, cd_size) >= UINT32:
+ raise ValueError('ZIP64 is not implemented: archive exceeds ZIP32 limits')
+ me.update(size=total, csize=total - h)
+ eocd = struct.pack(' 65535:
+ raise ValueError('UTF-8 archive path exceeds the ZIP filename limit')
+ return name
+
+
+def join_name(prefix, name):
+ return archive_name(f'{prefix}/{name}' if prefix else name)
+
+
+def path_key(path):
+ return os.path.normcase(str(Path(path).resolve()))
+
+
+def read_snapshot(path):
+ flags = os.O_RDONLY | getattr(os, 'O_BINARY', 0) | getattr(os, 'O_NOFOLLOW', 0)
+ with os.fdopen(os.open(path, flags), 'rb') as source:
+ before = os.fstat(source.fileno())
+ if not stat.S_ISREG(before.st_mode):
+ raise ValueError(f'input is no longer a regular file: {path}')
+ if before.st_size >= 0xffffffff:
+ raise ValueError(f'file exceeds this generator\'s ZIP32 size limit: {path}')
+ data = source.read()
+ after = os.fstat(source.fileno())
+ if (len(data) != before.st_size or before.st_size != after.st_size
+ or before.st_mtime_ns != after.st_mtime_ns):
+ raise ValueError(f'input changed while reading: {path}')
+ return data
+
+
+def collect_entries(inputs, output, prefix, reserved, mtime=0):
+ entries, names, case_names = [], {}, {}
+ excluded = False
+ output_key = path_key(output)
+ if any(path_key(path) == output_key for path in inputs):
+ raise ValueError('output cannot also be an explicit input')
+
+ def add(name, kind, mode, path=None):
+ name = archive_name(name)
+ old = names.get(name)
+ if old is not None:
+ if kind == 'directory' and old['is_dir'] and old.get('_path') is None:
+ old['_path'], old['mode'] = path, mode
+ return
+ raise ValueError(f'duplicate archive path: {name}')
+ if name.casefold() in case_names:
+ raise ValueError(f'archive paths collide on case-insensitive systems: {name}')
+ entry = dict(name=name, data=b'', mode=mode, mtime=mtime,
+ is_dir=kind == 'directory', kind=kind, _path=path)
+ entries.append(entry)
+ names[name] = entry
+ case_names[name.casefold()] = name
+
+ def parents(name):
+ parts = PurePosixPath(name).parts
+ for end in range(1, len(parts)):
+ parent = '/'.join(parts[:end])
+ existing = names.get(parent)
+ if existing is not None:
+ if not existing['is_dir']:
+ raise ValueError(f'archive parent is not a directory: {parent}')
+ else:
+ add(parent, 'directory', stat.S_IFDIR | 0o755)
+
+ def walk(path, name):
+ nonlocal excluded
+ if path_key(path) == output_key:
+ excluded = True
+ return
+ st = path.lstat()
+ parents(name)
+ if stat.S_ISLNK(st.st_mode):
+ add(name, 'symlink', stat.S_IFLNK | stat.S_IMODE(st.st_mode), path)
+ elif stat.S_ISDIR(st.st_mode):
+ if getattr(path, 'is_junction', lambda: False)():
+ raise ValueError(f'directory junctions are not followed: {path}')
+ add(name, 'directory', stat.S_IFDIR | stat.S_IMODE(st.st_mode), path)
+ for child in sorted(path.iterdir(), key=lambda p: p.name):
+ walk(child, join_name(name, child.name))
+ elif stat.S_ISREG(st.st_mode):
+ add(name, 'file', stat.S_IFREG | stat.S_IMODE(st.st_mode), path)
+ else:
+ raise ValueError(f'unsupported special file: {path}')
+
+ parents(reserved)
+ if prefix:
+ parents(prefix + '/placeholder')
+ for path in inputs:
+ st = path.lstat()
+ if len(inputs) == 1 and stat.S_ISDIR(st.st_mode):
+ for child in sorted(path.iterdir(), key=lambda p: p.name):
+ walk(child, join_name(prefix, child.name))
+ else:
+ walk(path, join_name(prefix, path.name or path.resolve().name))
+ if reserved.casefold() in case_names:
+ raise ValueError(f'source collides with reserved archive member: {reserved}')
+ if any(name.casefold().startswith(reserved.casefold()+'/') for name in names):
+ raise ValueError(f'reserved self member would replace a directory: {reserved}')
+ for entry in entries:
+ path = entry.pop('_path')
+ if entry['kind'] == 'file':
+ entry['data'] = read_snapshot(path)
+ elif entry['kind'] == 'symlink':
+ entry['data'] = os.readlink(path).encode('utf-8')
+ return entries, excluded
+
+
+def verify_archive(archive, entries, self_name):
+ expected = {entry['name']+('/' if entry['is_dir'] else ''):entry['data'] for entry in entries}
+ expected[self_name] = archive
+ with zipfile.ZipFile(io.BytesIO(archive)) as reader:
+ infos = reader.infolist()
+ if len(infos) != len(expected) or {i.filename for i in infos} != set(expected):
+ raise ValueError('generated member list does not match the input snapshot')
+ for member in infos:
+ local = struct.unpack_from('
+
+## 更多格式——RAR Quine
+ 其实大多数常用的压缩算法都和ZIP差不多,核心思想基本上都是LZ77那套用距离和长度来表示重复内容,然后再用各种熵编码来尽可能用少的比特存储数据……所以说RAR Quine理论上也可以存在,毕竟原理都差不多。同样,我也试着让AI做了一下,依旧轻轻松松就做出来了。不过毕竟RAR不是开源软件,生成的代码我就不放出来了,这里有一份生成后的RAR Quine:[quine.rar](/assets/quine.rar),如果有人有兴趣,也可以研究一下这个档案。
+
+# 感想
+ 我明明对压缩的原理也只是了解点皮毛,但是有了AI之后能做的事情真的是太可怕了,各种只能在想象中的东西都被轻松实现……真的是越来越离不开AI了,再看看最近的AI又发现了大量基础设施的高危漏洞,很明显,人被AI淘汰的时代可能越来越近了,到时候……还有继续记录的意义吗?
\ No newline at end of file
diff --git a/_tools/blogquine.py b/_tools/blogquine.py
index 70636bd..770ac2b 100644
--- a/_tools/blogquine.py
+++ b/_tools/blogquine.py
@@ -1,110 +1,83 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
+"""LZMA2 7z quine 生成器,仅依赖 Python 标准库。
+用法:python blogquine.py 源目录 输出.7z [--quine-name 名称]
+ [--src-dir 前缀目录] [--quine-dir 自身所在目录]
+解压得到源文件及输出归档自身;内容原样存储,辅助信息位于归档内部。
+"""
import argparse
import binascii
+from dataclasses import dataclass
import lzma
import os
+from pathlib import Path
import struct
-import sys
import time
-# ============================================================
-# Part 1: 最小 LZMA1 range coder(只做编码)
-#
-# 设计目标:只实现 quine 构造需要的 token:match / rep0-match,
-# 编码字节与历史内容无关(不维护输出历史),
-# 这是"先算结构、后填数据"两阶段装配的基础。
-# 参考:Igor Pavlov 的 LZMA SDK (LzmaEnc.c / LzmaDec.c)。
-# ============================================================
-
-kNumBitModelTotalBits = 11
-kBitModelTotal = 1 << kNumBitModelTotalBits # 2048
-kNumMoveBits = 5
-kTopValue = 1 << 24 # 0x1000000
-
-kNumStates = 12
-kNumLitStates = 7
-kNumPosBitsMax = 4
-kNumLenToPosStates = 4
-kNumAlignBits = 4
-kEndPosModelIndex = 14
-kNumFullDistances = 1 << (kEndPosModelIndex >> 1) # 128
-kMatchMinLen = 2
-kNumLowLenBits = 3
-kNumMidLenBits = 3
-kNumHighLenBits = 8
-kNumLowLenSymbols = 1 << kNumLowLenBits # 8
-kNumMidLenSymbols = 1 << kNumMidLenBits # 8
-kNumPosSlotBits = 6
-
-PROB_INIT = kBitModelTotal >> 1 # 1024
+SIG = b"7z\xbc\xaf'\x1c"
+VER = b"\x00\x04"
+CHUNK = 1 << 16 # LZMA2 未压缩 chunk 上限
+MAX_CHUNK_OUTPUT = 1 << 21 # LZMA2 压缩 chunk 解压上限
+MAX_MATCH = 273
+PROPS_BYTE = 0x5D # lc=3, lp=0, pb=2
+FILETIME_EPOCH_OFFSET = 116444736000000000
+PROB_INIT = 1024
class RangeEncoder:
- """LZMA 的区间编码器。low 是 64 位(要容纳进位),range 是 32 位。"""
+ """LZMA 区间编码器;所有整数截断与 SDK 的 UInt32 运算一致。"""
def __init__(self):
self.low = 0
self.range = 0xFFFFFFFF
self.cache = 0
- self.cache_size = 1 # 初值 1 -> 第一个输出字节恒为 0x00
+ self.cache_size = 1
self.buf = bytearray()
def _shift_low(self):
- if (self.low & 0xFFFFFFFF) < 0xFF000000 or (self.low >> 32) != 0:
+ carry = self.low >> 32
+ if (self.low & 0xFFFFFFFF) < 0xFF000000 or carry:
temp = self.cache
- while True:
- self.buf.append((temp + (self.low >> 32)) & 0xFF)
+ while self.cache_size:
+ self.buf.append((temp + carry) & 0xFF)
temp = 0xFF
self.cache_size -= 1
- if self.cache_size == 0:
- break
self.cache = (self.low >> 24) & 0xFF
self.cache_size += 1
- # 注意:C 里 `(UInt32)low << 8` 会截断回 32 位,必须照做,
- # 否则 low 的高位会一直累积,进位位 (low>>32) 就不止 0/1 了。
- self.low = ((self.low & 0xFFFFFFFF) << 8) & 0xFFFFFFFF
+ self.low = (self.low << 8) & 0xFFFFFFFF
- def encode_bit(self, probs, idx, bit):
- p = probs[idx]
- bound = (self.range >> kNumBitModelTotalBits) * p
- if bit == 0:
- self.range = bound
- probs[idx] = p + ((kBitModelTotal - p) >> kNumMoveBits)
- else:
- self.low += bound
- self.range -= bound
- probs[idx] = p - (p >> kNumMoveBits)
- while self.range < kTopValue:
+ def _normalize(self):
+ while self.range < 1 << 24:
self.range = (self.range << 8) & 0xFFFFFFFF
self._shift_low()
- def encode_direct_bits(self, value, num_bits):
- for i in range(num_bits - 1, -1, -1):
+ def encode_bit(self, probs, index, bit):
+ probability = probs[index]
+ bound = (self.range >> 11) * probability
+ if bit:
+ self.low += bound
+ self.range -= bound
+ probs[index] -= probability >> 5
+ else:
+ self.range = bound
+ probs[index] += (2048 - probability) >> 5
+ self._normalize()
+
+ def encode_direct_bits(self, value, bits):
+ for shift in range(bits - 1, -1, -1):
self.range >>= 1
- if (value >> i) & 1:
+ if value >> shift & 1:
self.low += self.range
- while self.range < kTopValue:
- self.range = (self.range << 8) & 0xFFFFFFFF
- self._shift_low()
+ self._normalize()
- def bittree_encode(self, probs, off, num_bits, symbol):
- """普通位树:MSB 优先,节点下标从 1 开始。"""
- m = 1
- for i in range(num_bits - 1, -1, -1):
- bit = (symbol >> i) & 1
- self.encode_bit(probs, off + m, bit)
- m = (m << 1) | bit
-
- def bittree_reverse_encode(self, probs, off, num_bits, symbol):
- """反向位树:LSB 优先,用于 SpecPos / Align。"""
- m = 1
- for i in range(num_bits):
- bit = symbol & 1
- symbol >>= 1
- self.encode_bit(probs, off + m, bit)
- m = (m << 1) | bit
+ def bit_tree(self, probs, offset, bits, symbol, reverse=False):
+ node = 1
+ shifts = range(bits) if reverse else range(bits - 1, -1, -1)
+ for shift in shifts:
+ bit = symbol >> shift & 1
+ self.encode_bit(probs, offset + node, bit)
+ node = (node << 1) | bit
def finish(self):
for _ in range(5):
@@ -112,602 +85,487 @@ class RangeEncoder:
return bytes(self.buf)
-def _pos_slot_and_bits(d):
- """把 0 基距离 d (=真实距离-1) 拆成 (posSlot, 低位数, 低位值)。"""
- if d < 4:
- return d, 0, 0
- # posSlot >= 4 时:numDirectBits=(slot>>1)-1, base=(2|(slot&1))<> 1) - 1
- base = (2 | (slot & 1)) << n
- if d < base + (1 << n):
- return slot, n, d - base
- raise ValueError("distance too large: %d" % d)
+class LengthEncoder:
+ """普通 match 和 rep0 使用独立概率,但共享长度编码逻辑。"""
+
+ def __init__(self):
+ self.choice = [PROB_INIT] * 2
+ self.low = [PROB_INIT] * 32
+ self.mid = [PROB_INIT] * 32
+ self.high = [PROB_INIT] * 256
+
+ def encode(self, rc, pos_state, length):
+ value = length - 2
+ rc.encode_bit(self.choice, 0, value >= 8)
+ if value < 8:
+ rc.bit_tree(self.low, pos_state << 3, 3, value)
+ else:
+ rc.encode_bit(self.choice, 1, value >= 16)
+ if value < 16:
+ rc.bit_tree(self.mid, pos_state << 3, 3, value - 8)
+ else:
+ rc.bit_tree(self.high, 0, 8, value - 16)
class LzmaEncoder:
- def __init__(self, pb=2):
- """
- 不维护输出假历史:match 的编码字节只取决于 (dist,len,pos),与历史内容无关,
- 因此 quine 构造(先算结构、后填数据)不需要逐字节复制假历史。
- """
- self.pb = pb
- self.pos_mask = (1 << pb) - 1
+ """只编码 match/rep0,编码结果不依赖历史字节,供布局后填充数据。"""
+
+ def __init__(self, out_pos=0):
self.rc = RangeEncoder()
- self.pos = 0 # 已输出字节数
+ self.pos = out_pos
self.state = 0
- # 概率模型
- n = PROB_INIT
- self.p_is_match = [n] * (kNumStates << kNumPosBitsMax)
- self.p_is_rep = [n] * kNumStates
- self.p_is_rep_g0 = [n] * kNumStates
- self.p_rep0_long = [n] * (kNumStates << kNumPosBitsMax)
- self.p_pos_slot = [n] * (kNumLenToPosStates << kNumPosSlotBits)
- self.p_spec_pos = [n] * (kNumFullDistances - kEndPosModelIndex) # 114
- self.p_align = [n] * (1 << kNumAlignBits)
- self.p_len_choice = [n] * 2
- self.p_len_low = [n] * (16 * kNumLowLenSymbols)
- self.p_len_mid = [n] * (16 * kNumMidLenSymbols)
- self.p_len_high = [n] * (1 << kNumHighLenBits)
- self.p_rep_len_choice = [n] * 2
- self.p_rep_len_low = [n] * (16 * kNumLowLenSymbols)
- self.p_rep_len_mid = [n] * (16 * kNumMidLenSymbols)
- self.p_rep_len_high = [n] * (1 << kNumHighLenBits)
+ self.is_match = [PROB_INIT] * (12 << 4)
+ self.is_rep = [PROB_INIT] * 12
+ self.is_rep_g0 = [PROB_INIT] * 12
+ self.rep0_long = [PROB_INIT] * (12 << 4)
+ self.pos_slot = [PROB_INIT] * (4 << 6)
+ self.spec_pos = [PROB_INIT] * 114
+ self.align = [PROB_INIT] * 16
+ self.match_len = LengthEncoder()
+ self.rep_len = LengthEncoder()
- # ---------- 内部 ----------
- @property
- def pos_state(self):
- return self.pos & self.pos_mask
-
- def _encode_len(self, choice, low, mid, high, length):
- """choice 是 2 元素数组:choice[0]=choice 位,choice[1]=choice2 位。"""
- ps = self.pos_state
- l = length - kMatchMinLen
- if l < kNumLowLenSymbols:
- self.rc.encode_bit(choice, 0, 0)
- self.rc.bittree_encode(low, ps << kNumLowLenBits, kNumLowLenBits, l)
- else:
- self.rc.encode_bit(choice, 0, 1)
- l -= kNumLowLenSymbols
- if l < kNumMidLenSymbols:
- self.rc.encode_bit(choice, 1, 0)
- self.rc.bittree_encode(mid, ps << kNumMidLenBits, kNumMidLenBits, l)
- else:
- self.rc.encode_bit(choice, 1, 1)
- self.rc.bittree_encode(high, 0, kNumHighLenBits, l - kNumMidLenSymbols)
-
- # ---------- 对外 token ----------
- def _write_dist(self, dist, lts):
- d = dist - 1
- slot, n, low_bits = _pos_slot_and_bits(d)
- self.rc.bittree_encode(self.p_pos_slot, lts << kNumPosSlotBits,
- kNumPosSlotBits, slot)
+ def _write_dist(self, dist, length):
+ if not 1 <= dist <= 0xFFFFFFFF:
+ raise ValueError("LZMA distance must be 1..2^32-1")
+ value = dist - 1
+ bits = max(0, value.bit_length() - 2)
+ slot = value if value < 4 else 2 * (bits + 1) + (value >> bits & 1)
+ self.rc.bit_tree(self.pos_slot, min(length - 2, 3) << 6, 6, slot)
if slot >= 4:
- if slot < kEndPosModelIndex:
- base = (2 | (slot & 1)) << n
- off = base - slot - 1
- self.rc.bittree_reverse_encode(self.p_spec_pos, off, n, low_bits)
+ base = (2 | (slot & 1)) << bits
+ extra = value - base
+ if slot < 14:
+ self.rc.bit_tree(self.spec_pos, base - slot - 1, bits, extra, True)
else:
- self.rc.encode_direct_bits(low_bits >> kNumAlignBits, n - kNumAlignBits)
- self.rc.bittree_reverse_encode(self.p_align, 0, kNumAlignBits,
- low_bits & ((1 << kNumAlignBits) - 1))
+ self.rc.encode_direct_bits(extra >> 4, bits - 4)
+ self.rc.bit_tree(self.align, 0, 4, extra & 15, True)
def match(self, dist, length):
- assert kMatchMinLen <= length <= 273, length
- ps = self.pos_state
- self.rc.encode_bit(self.p_is_match, (self.state << kNumPosBitsMax) + ps, 1)
- self.rc.encode_bit(self.p_is_rep, self.state, 0) # 非 rep
- lts = min(length - kMatchMinLen, kNumLenToPosStates - 1)
- self._encode_len(self.p_len_choice,
- self.p_len_low, self.p_len_mid, self.p_len_high, length)
- self._write_dist(dist, lts)
- # 状态更新
- self.state = 7 if self.state < kNumLitStates else 10
+ if not 2 <= length <= MAX_MATCH:
+ raise ValueError("LZMA match length must be 2..273")
+ self.rc.encode_bit(self.is_match, (self.state << 4) + (self.pos & 3), 1)
+ self.rc.encode_bit(self.is_rep, self.state, 0)
+ self.match_len.encode(self.rc, self.pos & 3, length)
+ self._write_dist(dist, length)
+ self.state = 7 if self.state < 7 else 10
self.pos += length
def rep_match(self, length):
- """rep0 匹配:只使用最近一次 match 的距离(quine 构造只需要这种)。"""
- assert kMatchMinLen <= length <= 273, length
- ps = self.pos_state
- self.rc.encode_bit(self.p_is_match, (self.state << kNumPosBitsMax) + ps, 1)
- self.rc.encode_bit(self.p_is_rep, self.state, 1)
- self.rc.encode_bit(self.p_is_rep_g0, self.state, 0)
- self.rc.encode_bit(self.p_rep0_long, (self.state << kNumPosBitsMax) + ps, 1)
- self._encode_len(self.p_rep_len_choice,
- self.p_rep_len_low, self.p_rep_len_mid, self.p_rep_len_high, length)
- self.state = 8 if self.state < kNumLitStates else 11
+ if not 2 <= length <= MAX_MATCH:
+ raise ValueError("LZMA rep0 length must be 2..273")
+ index = (self.state << 4) + (self.pos & 3)
+ self.rc.encode_bit(self.is_match, index, 1)
+ self.rc.encode_bit(self.is_rep, self.state, 1)
+ self.rc.encode_bit(self.is_rep_g0, self.state, 0)
+ self.rc.encode_bit(self.rep0_long, index, 1)
+ self.rep_len.encode(self.rc, self.pos & 3, length)
+ self.state = 8 if self.state < 7 else 11
self.pos += length
def finish(self):
return self.rc.finish()
-# ============================================================
-# Part 2: 7z 格式原语
-# ============================================================
-
-SIG = b"7z\xbc\xaf'\x1c"
-VER = b"\x00\x04"
-MAX_MATCH = 273 # LZMA1 单个 match 长度上限
-# FILETIME 纪元(1601-01-01)与 Unix 纪元(1970-01-01)之差,单位 100ns
-FILETIME_EPOCH_OFFSET = 116444736000000000
+def crc32(data, value=0):
+ return binascii.crc32(data, value) & 0xFFFFFFFF
-def crc32(b, v=0):
- return binascii.crc32(b, v) & 0xFFFFFFFF
-
-
-def varint(v):
- """7z UINT64 变长编码:首字节高位连续 n 个 1 + 值的 (7-n) 个高位,再跟 n 字节 LE。"""
- if v < 0x80:
- return bytes([v])
- for n in range(1, 9):
- if v < (1 << (8 * n + 7 - n)):
- break
- else:
- raise ValueError("varint too big")
- first = ((0xFF << (8 - n)) & 0xFF) | ((v >> (8 * n)) & ((1 << (7 - n)) - 1))
- return bytes([first]) + (v & ((1 << (8 * n)) - 1)).to_bytes(n, "little")
+def varint(value):
+ """7z UINT64:首字节给出后续小端字节数,最多九字节。"""
+ if not 0 <= value < 1 << 64:
+ raise ValueError("7z UINT64 out of range")
+ for size in range(8):
+ if value < 1 << (7 * (size + 1)):
+ first = ((0xFF << (8 - size)) & 0xFF) | (value >> (8 * size))
+ return bytes([first]) + (value & ((1 << (8 * size)) - 1)).to_bytes(size, "little")
+ return b"\xff" + value.to_bytes(8, "little")
def store_hdr(payload_len, first=False):
- """LZMA2 uncompressed chunk 头(3 字节,大端 size-1)。"""
- assert 1 <= payload_len <= 65536
- return bytes([0x01 if first else 0x02]) + (payload_len - 1).to_bytes(2, "big")
+ if not 1 <= payload_len <= CHUNK:
+ raise ValueError("LZMA2 stored chunk must contain 1..65536 bytes")
+ return bytes([1 if first else 2]) + (payload_len - 1).to_bytes(2, "big")
def matches_for(dist, total):
- """dist 固定、总长 total 的 token 序列:首个 match + 后续 rep0。
- 长度按 273 上限切分,并避开"只剩 1 字节"(rep0 最小长度为 2)。"""
- assert total >= 2
- toks = []
- first = min(MAX_MATCH, total)
- if total - first == 1:
- first -= 1
- toks.append(("m", dist, first))
- total -= first
- while total > 0:
- l = min(MAX_MATCH, total)
- if total - l == 1:
- l -= 1
- toks.append(("r0", l))
- total -= l
- return toks
-
-
-# ============================================================
-# Part 3: 多文件 7z quine 构造器
-# ============================================================
-
-PROPS_BYTE = 0x5D # lc=3, lp=0, pb=2
-CHUNK = 65536 # LZMA2 单 chunk 解压上限
-SEED_NOTE = ("\nMayx's Blog!").encode("utf-8")
+ """固定距离的首个 match 加 rep0;分段时不留下单字节。"""
+ if total < 2:
+ raise ValueError("match sequence must output at least two bytes")
+ tokens = []
+ while total:
+ length = min(MAX_MATCH, total)
+ if total - length == 1:
+ length -= 1
+ tokens.append(("r0", length) if tokens else ("m", dist, length))
+ total -= length
+ return tokens
def dict_prop_for(maxdist):
- """选最小的 LZMA2 dict prop 使字典 >= maxdist。"""
- for p in range(41):
- if (2 | (p & 1)) << (p // 2 + 11) >= maxdist:
- return p, (2 | (p & 1)) << (p // 2 + 11)
- raise ValueError("distance too large")
+ for prop in range(41):
+ size = 0xFFFFFFFF if prop == 40 else (2 | (prop & 1)) << (prop // 2 + 11)
+ if size >= maxdist:
+ return prop, size
+ raise ValueError("LZMA2 dictionary distance exceeds 2^32-1")
def lzma_chunk(tokens, out_pos):
- """编一个 LZMA chunk(0xC0: state+props reset,无 dict reset,无 end marker)。
- match token 的编码字节只取决于 (dist,len,pos),与历史内容无关(不维护输出历史)。"""
- enc = LzmaEncoder()
- enc.pos = out_pos
- total = 0
- for t in tokens:
- if t[0] == "m":
- enc.match(t[1], t[2])
- total += t[2]
+ """重置状态和概率,保留字典;21-bit 解压长度,不写结束标记。"""
+ enc = LzmaEncoder(out_pos)
+ for token in tokens:
+ if token[0] == "m":
+ enc.match(token[1], token[2])
+ elif token[0] == "r0":
+ enc.rep_match(token[1])
else:
- enc.rep_match(t[1])
- total += t[1]
+ raise ValueError("unsupported LZMA token: %r" % (token[0],))
data = enc.finish()
- assert total - 1 < 65536 and len(data) - 1 < 65536
- hdr = bytes([0xC0]) + (total - 1).to_bytes(2, "big") + \
- (len(data) - 1).to_bytes(2, "big") + bytes([PROPS_BYTE])
- return hdr + data, total
+ total = enc.pos - out_pos
+ if not 1 <= total <= MAX_CHUNK_OUTPUT or not 1 <= len(data) <= CHUNK:
+ raise ValueError("LZMA2 compressed chunk size out of range")
+ unpacked, packed = total - 1, len(data) - 1
+ header = (bytes([0xC0 | (unpacked >> 16)])
+ + (unpacked & 0xFFFF).to_bytes(2, "big")
+ + packed.to_bytes(2, "big") + bytes([PROPS_BYTE]))
+ return header + data, total
+
+
+@dataclass(frozen=True)
+class Entry:
+ name: str
+ is_dir: bool
+ data: bytes = b""
+
+
+@dataclass(frozen=True)
+class Layout:
+ prefix_size: int
+ chunks: tuple
+ samples: bytes
+ padding: int
+ matches: bytes
+ header: bytes
+ crc_offset: int
+ dict_size: int
+
+ @property
+ def packed_size(self):
+ return sum(self.chunks) + 3 * len(self.chunks) + len(self.matches) + 1
+
+
+class LayoutError(RuntimeError):
+ """当前填充量没有满足布局或 CRC 定点,换一个填充量重试。"""
+
+
+def split_sizes(size, limit):
+ """每片至少两字节,避免 match 无法表达的一字节尾片。"""
+ if size < 2:
+ raise ValueError("分片总长度必须至少为 2")
+ sizes = [limit] * (size // limit)
+ tail = size % limit
+ if tail == 1:
+ sizes[-1] -= 1
+ tail = 2
+ if tail:
+ sizes.append(tail)
+ return tuple(sizes)
+
+
+def bitfield(flags):
+ data = bytearray((len(flags) + 7) // 8)
+ for i, flag in enumerate(flags):
+ if flag:
+ data[i // 8] |= 1 << (7 - i % 8)
+ return bytes(data)
+
+
+def archive_path(value, allow_empty=False):
+ value = value.replace("\\", "/")
+ if not value and allow_empty:
+ return ""
+ parts = value.split("/")
+ if any(part in ("", ".", "..") for part in parts) or any(c in value for c in ("\0", ":")):
+ raise ValueError("归档内路径必须是相对路径,不能包含空段、. 或 ..:%r" % value)
+ return "/".join(parts)
+
+
+def encode_segments(segments, out_pos):
+ """把 (历史起点, 长度) 转成 match 流;跨 chunk 时保留字典。"""
+ result, tokens = bytearray(), []
+ used, max_distance = 0, 0
+ for source, length in segments:
+ for size in split_sizes(length, MAX_CHUNK_OUTPUT):
+ if used + size > MAX_CHUNK_OUTPUT:
+ block, _ = lzma_chunk(tokens, out_pos)
+ result += block
+ out_pos += used
+ tokens, used = [], 0
+ distance = out_pos + used - source
+ if distance <= 0:
+ raise LayoutError("回引源尚未输出")
+ max_distance = max(max_distance, distance)
+ tokens.extend(matches_for(distance, size))
+ used += size
+ source += size
+ if tokens:
+ block, _ = lzma_chunk(tokens, out_pos)
+ result += block
+ return bytes(result), max_distance
+
+
+def solve_fixed_crc(data, groups, targets):
+ """CRC 是 GF(2) 仿射函数;同步所有镜像,解三个 CRC 的 96-bit 定点。"""
+ def vector(values):
+ return sum(value << (32 * i) for i, value in enumerate(values))
+
+ base = vector(targets())
+ columns = []
+ for copies in groups:
+ for bit in range(32):
+ positions = [copy[bit // 8] for copy in copies]
+ for pos in positions:
+ data[pos] ^= 1 << (bit % 8)
+ columns.append(vector(targets()) ^ base)
+ for pos in positions:
+ data[pos] ^= 1 << (bit % 8)
+
+ rows = []
+ for bit in range(96):
+ coeff = 1 << bit
+ for j, column in enumerate(columns):
+ coeff ^= ((column >> bit) & 1) << j
+ rows.append([coeff, (base >> bit) & 1])
+ pivots = []
+ for column in range(96):
+ rank = len(pivots)
+ pivot = next((i for i in range(rank, 96) if rows[i][0] >> column & 1), None)
+ if pivot is None:
+ continue
+ rows[rank], rows[pivot] = rows[pivot], rows[rank]
+ for i in range(96):
+ if i != rank and rows[i][0] >> column & 1:
+ rows[i][0] ^= rows[rank][0]
+ rows[i][1] ^= rows[rank][1]
+ pivots.append(column)
+ if any(not coeff and rhs for coeff, rhs in rows):
+ raise LayoutError("CRC 定点方程无解")
+ solution = sum(rows[i][1] << column for i, column in enumerate(pivots))
+ values = [(solution >> (32 * i)) & 0xFFFFFFFF for i in range(3)]
+ for copies, value in zip(groups, values):
+ packed = struct.pack(" CHUNK:
- Ls.append(CHUNK)
- rem -= CHUNK
- Ls.append(rem)
- assert Ls[-1] >= 2, "末 chunk 载荷 %d 太小,调整 d_seed" % Ls[-1]
- k = len(Ls)
- hdrA = store_hdr(CHUNK, first=False) # 0x02 FF FF
- hdrB = store_hdr(Ls[-1], first=False) # 末 chunk 头(可能与 A 相同)
- self.dict_prop, dict_size = dict_prop_for(maxdist_hint)
- # 子流大小(quine 的 total 在迭代后填):seed, 各文件, quine
- file_sizes = [len(data) for _, data in self.files]
+ def add_parents(name):
+ parts = name.split("/")
+ for i in range(1, len(parts)):
+ add("/".join(parts[:i]), True)
- T, h = 100, 100
- for _ in range(30):
- chunks = []
- o, f = 0, 32
- S = 0
- for j, L in enumerate(Ls): # C1a..C1k
- chunks.append({"kind": "store", "foff": f, "size": 3 + L,
- "ooff": o, "olen": L, "first": j == 0,
- "c1": True, "S": S})
- o += L
- f += 3 + L
- S += L
- assert o == d + 35
- # repro:复现 file[35 : 32+3k+d+35) = pay0 hdr1 pay1 ... hdr(k-1) pay(k-1)
- S = 0
- for j, L in enumerate(Ls):
- if j > 0:
- # chunk j 的 3 字节头:从 seed 开头样本复制
- srcpos = 0 if (j < k - 1 or L == CHUNK) else 3
- dist_h = (d + 35 + S + 3 * (j - 1)) - srcpos
- hb, hu = lzma_chunk([("m", dist_h, 3)], o)
- assert hu == 3
- chunks.append({"kind": "lzma", "foff": f, "size": len(hb),
- "ooff": o, "olen": hu, "bytes": hb})
- o += hu
- f += len(hb)
- # chunk j 的载荷:从 W[S:S+L) 复制
- cb, cu = lzma_chunk(matches_for(d + 35 + 3 * j, L), o)
- assert cu == L
- chunks.append({"kind": "lzma", "foff": f, "size": len(cb),
- "ooff": o, "olen": cu, "bytes": cb})
- o += cu
- f += len(cb)
- S += L
- # gears: store(x)+copy(x) 把 slip 压到 <=16
- while f - (o - d) > 16:
- s = f - (o - d)
- x = min(s + 3, CHUNK)
- chunks.append({"kind": "store", "foff": f, "size": 3 + x,
- "ooff": o, "olen": x})
- o += x
- f += 3 + x
- cb, cu = lzma_chunk(matches_for(x, x), o)
- chunks.append({"kind": "lzma", "foff": f, "size": len(cb),
- "ooff": o, "olen": cu, "bytes": cb})
- o += cu
- f += len(cb)
- # jump: 单 match 从 W[6:6+y)(seed 里的种植串)复制,使 slip = -3
- s = f - (o - d)
- y = s + 17
- for _ in range(10):
- jb, ju = lzma_chunk([("m", o - 6, y)], o)
- y2 = s + 3 + len(jb)
- if y2 == y:
- break
- y = y2
- assert ju == y and y2 == y, "jump 不动点失败"
- assert y + 6 <= d_seed, "种植串 %d+6 超过 seed %d" % (y, d_seed)
- chunks.append({"kind": "lzma", "foff": f, "size": len(jb),
- "ooff": o, "olen": ju, "bytes": jb, "jump": True})
- o += ju
- f += len(jb)
- # gadget: 真空 store(T) + match(T,T) + 结束标记
- assert f == (o - d) - 3, "slip=%d 应为 -3" % (f - (o - d))
- chunks.append({"kind": "store", "foff": f, "size": 3 + T,
- "ooff": o, "olen": T, "vac": True})
- f += 3 + T
- o += T
- gb, gu = lzma_chunk(matches_for(T, T), o)
- assert gu == T
- chunks.append({"kind": "lzma", "foff": f, "size": len(gb),
- "ooff": o, "olen": gu, "bytes": gb, "gmatch": True})
- f += len(gb)
- o += gu
- # LZMA2 流结束标记(0x00):7z t 需要它确认流完整结束
- chunks.append({"kind": "term", "foff": f, "size": 1,
- "ooff": o, "olen": 0, "bytes": b"\x00"})
- f += 1
- n = f - 32
- total = f + h
- sub_sizes = [d_seed] + file_sizes + [total]
- entries = self.entries()
- hdr, crc_base = self.build_header(n, total, d, entries, sub_sizes)
- h_new = len(hdr)
- T_new = len(gb) + 1 + h_new
- if T_new == T and h_new == h:
- assert o == d + f + h, "输出终点 %d != d+total %d" % (o, d + f + h)
- return {"d": d, "d_seed": d_seed, "k": k, "Ls": Ls,
- "chunks": chunks, "header": hdr, "crc_base": crc_base,
- "n": n, "total": f + h, "T": T, "h": h,
- "hdrA": hdrA, "hdrB": hdrB, "jump_y": y,
- "n_sub": len(sub_sizes), "sub_sizes": sub_sizes,
- "entries": entries, "dict_size": dict_size}
- T, h = T_new, h_new
- raise RuntimeError("layout 不收敛")
+ if prefix:
+ add_parents(prefix)
+ add(prefix, True)
- # ---------- 装配 ----------
- def assemble(self, lay):
- F = bytearray(lay["total"])
- d, h = lay["d"], lay["h"]
- d_seed = lay["d_seed"]
- hoff = lay["total"] - h
- # pass A: sig + 所有非 payload 字节
- F[0:6] = SIG
- F[6:8] = VER
- struct.pack_into("> i) & 1:
- coeff |= 1 << j
- coeff ^= 1 << i # 对角元 = 1 ^ A[i][i]
- eqs.append([coeff, (basevec >> i) & 1])
- for j in range(96):
- p = next((i for i in range(j, 96) if (eqs[i][0] >> j) & 1), None)
- if p is None:
- raise RuntimeError("GF(2) 奇异 @bit%d" % j)
- eqs[j], eqs[p] = eqs[p], eqs[j]
- for i in range(96):
- if i != j and ((eqs[i][0] >> j) & 1):
- eqs[i][0] ^= eqs[j][0]
- eqs[i][1] ^= eqs[j][1]
- x = 0
- for i in range(96):
- assert eqs[i][0] == (1 << i)
- if eqs[i][1]:
- x |= 1 << i
- vals = [x & 0xFFFFFFFF, (x >> 32) & 0xFFFFFFFF, (x >> 64) & 0xFFFFFFFF]
- for g in range(3):
- for p in groups[g]:
- F[p:p + 4] = struct.pack("