#!/usr/bin/env python3 """Convert a raw image to an Android sparse image (libsparse format) without extra tools. `fastboot flash ` fails on this host (fastboot 37 reads the file end to copy an AVB footer and aborts with "Failed reading from " before sending anything); for sparse input it skips that step. All-zero 4096-byte blocks become FILL chunks with value 0 (written as zeros, never DONT_CARE), everything else RAW chunks, so the expanded content equals the input byte for byte. The result is verified by expanding it and comparing SHA-256 with the input. """ import argparse import hashlib from pathlib import Path import struct import sys BLOCK = 4096 MAGIC = 0xED26FF3A RAW, FILL, DONT_CARE, CRC32 = 0xCAC1, 0xCAC2, 0xCAC3, 0xCAC4 MAX_RAW_BLOCKS = 4096 # 16 MiB per RAW chunk ZERO = bytes(BLOCK) def convert(source, target): size = source.stat().st_size if size % BLOCK: raise SystemExit('Input size must be a multiple of 4096') total_blocks = size // BLOCK chunks = 0 with open(source, 'rb') as src, open(target, 'wb') as out: out.write(b'\0' * 28) # header, rewritten at the end pending = bytearray() # blocks of the current RAW run pending_blocks = 0 zero_run = 0 def flush_raw(): nonlocal pending, pending_blocks, chunks if pending_blocks: out.write(struct.pack('