"""Supplement Session 37 with legacy-tool, table and archive comparisons.
Usage: python jpeg_followup_checks.py FILES RESULTS LEGACY_OUTGUESS LIBER_PRIMUS_MD
"""
import collections,hashlib,json,subprocess,sys
from pathlib import Path
src,out,exe,archive=map(Path,sys.argv[1:]);d=json.loads((out/'jpeg_file_results.json').read_text())
sha=lambda b:hashlib.sha256(b).hexdigest()
rows=[]
for name in ['control_outguess_default.jpg','control_outguess_keyed.jpg','18.jpg']:
 p=out/name if name.startswith('control') else src/name;dst=out/('legacy_'+name+'.bin');opts=['-k','session37-control'] if 'keyed' in name else []
 r=subprocess.run([str(exe),*opts,'-r',str(p),str(dst)],capture_output=True,timeout=90)
 b=dst.read_bytes() if dst.exists() else b''
 rows.append({'input':name,'returncode':r.returncode,'stderr':r.stderr.decode(),'bytes':len(b),'sha256':sha(b),'exact_control_payload':b==(out/'control_payload.bin').read_bytes() if name.startswith('control') else None})
assert all(x['exact_control_payload'] for x in rows[:2])
(out/'jpeg_legacy_check.json').write_text(json.dumps({'version':'OutGuess 0.2 Ubuntu package 0.2-8','executable_sha256':sha(exe.read_bytes()),'runs':rows},indent=2))
a=archive.read_bytes();hay=' '.join(a.decode().split());matches=[]
for n in ['00','01','02','03','08','10','11','12','13']:
 b=(out/f'{n}_outguess.bin').read_bytes()
 matches.append({'file':n+'.jpg','output_sha256':sha(b),'full_output_matches_archive_after_whitespace_normalization':' '.join(b.decode().split()) in hay})
# Compare luminance table bytes, independently of the extra chroma table.
lum=[]
for row in d['files'][17:]:
 b=(src/row['file']).read_bytes();seg=next(s for s in row['jpeg']['segments'] if s['marker']=='DB');p=seg['offset'];lum.append(sha(b[p+4:p+4+seg['payload_bytes']]))
summary={'archive_comparison':{'source_url':'https://github.com/scream314/cicada3301/blob/10733feb487bb8beb9966d534727ee5897aa54fc/liber_primus.md','source_sha256':sha(a),'matches':matches,'note':'10.jpg has a different border numeral and PGP signature from that archive section; this is recorded as a variant, not an exact match or authenticated new discovery.'},'LP2_first_quantization_table_unique_hashes':sorted(set(lum)), 'counts':{}}
for label,r in [('all',d['files']),('LP1',d['files'][:17]),('LP2',d['files'][17:])]:
 summary['counts'][label]={'files':len(r),'outguess_exit_codes':dict(collections.Counter(str(x['outguess']['returncode']) for x in r)),'steghide_exit_codes':dict(collections.Counter(str(x['steghide']['returncode']) for x in r)),'tails':sum(x['tail_bytes']>0 for x in r),'color_modes':dict(collections.Counter(x['pixel_mode'] for x in r))}
(out/'jpeg_audit_summary.json').write_text(json.dumps(summary,indent=2));print(json.dumps(summary,indent=2))
