"""Inventory and CRC-check the original deposit without executing its contents.

Usage: python3 inspect_archive.py /path/to/Sarvestani.zip
Only text/source files are extracted; recordings remain inside the source ZIP.
"""
import collections, hashlib, json, pathlib, sys, zipfile

root = pathlib.Path(__file__).resolve().parent
archive = pathlib.Path(sys.argv[1])
sha, md5 = hashlib.sha256(), hashlib.md5()
with archive.open('rb') as f:
    for chunk in iter(lambda:f.read(1024*1024), b''):
        sha.update(chunk); md5.update(chunk)
assert archive.stat().st_size == 1096230210, 'Archive length differs from Dryad record'
assert md5.hexdigest() == 'e840f971630e0540178b9145f4b1d0b7', 'Archive MD5 differs from Dryad record'
inventory=[]; extracted=[]
with zipfile.ZipFile(archive) as z:
    for entry in z.infolist():
        name = pathlib.PurePosixPath(entry.filename)
        assert not name.is_absolute() and '..' not in name.parts, 'Unsafe member path'
        row={'path':entry.filename,'bytes':entry.file_size,'compressed_bytes':entry.compress_size,'crc32':f'{entry.CRC:08x}','directory':entry.is_dir()}
        inventory.append(row)
        if not entry.is_dir():
            # Reading to EOF also verifies the member CRC through Python zipfile.
            digest=hashlib.sha256()
            with z.open(entry) as source:
                for chunk in iter(lambda:source.read(1024*1024), b''):digest.update(chunk)
            row['sha256']=digest.hexdigest()
        if not entry.is_dir() and name.suffix.lower() in {'.m','.txt','.md','.c','.cpp','.h','.json','.xml','.py'} and entry.file_size < 2_000_000:
            target=root/'dryad-extracted'/name
            target.parent.mkdir(parents=True,exist_ok=True)
            target.write_bytes(z.read(entry))
            extracted.append(str(target.relative_to(root)))
counts=collections.Counter(pathlib.PurePosixPath(e['path']).suffix.lower() or '(no extension)' for e in inventory if not e['directory'])
result={'source_doi':'10.5061/dryad.57pv818','version':1,'archive_bytes':archive.stat().st_size,'archive_md5':md5.hexdigest(),'archive_sha256':sha.hexdigest(),'all_member_crc_checks_passed':True,'members':len(inventory),'files':sum(not e['directory'] for e in inventory),'extension_counts':dict(counts),'extracted_files':extracted,'entries':inventory}
(root/'dryad-inventory.json').write_text(json.dumps(result,indent=2)+'\n')
print(json.dumps({k:v for k,v in result.items() if k not in {'entries','extracted_files'}},indent=2))
print('Extracted text/source files:',len(extracted))
