import struct, sys

def read_pool(d, off):
    typ, hsz, sz = struct.unpack_from('<HHI', d, off)
    cnt, scnt, flags, sstart, _ = struct.unpack_from('<IIIII', d, off+8)
    utf8 = bool(flags & 0x100)
    offs = struct.unpack_from('<%dI' % cnt, d, off+28)
    base = off + sstart
    out = []
    for o in offs:
        p = base + o
        if utf8:
            n = d[p]; p += 2 if n & 0x80 else 1
            m = d[p]
            if m & 0x80: m = ((m & 0x7f) << 8) | d[p+1]; p += 2
            else: p += 1
            out.append(d[p:p+m].decode('utf-8', 'replace'))
        else:
            n = struct.unpack_from('<H', d, p)[0]; p += 2
            if n & 0x8000: n = ((n & 0x7fff) << 16) | struct.unpack_from('<H', d, p)[0]; p += 2
            out.append(d[p:p+n*2].decode('utf-16-le', 'replace'))
    return out, sz

def patch(path, out_path, edits):
    d = bytearray(open(path, 'rb').read())
    S, psz = read_pool(d, 8)
    off = 8 + psz
    applied = []
    while off < len(d):
        typ, hsz, sz = struct.unpack_from('<HHI', d, off)
        if sz == 0: break
        if typ == 0x0102:
            elem = S[struct.unpack_from('<I', d, off+20)[0]]
            astart, asize, acount = struct.unpack_from('<HHH', d, off+24)
            for i in range(acount):
                a = off + 16 + astart + i*asize
                ans, anm, araw = struct.unpack_from('<iii', d, a)
                tv = struct.unpack_from('<I', d, a+12)[0]
                dtype = (tv >> 24) & 0xff
                data = struct.unpack_from('<i', d, a+16)[0]
                nm = S[anm] if anm >= 0 else '?'
                key = (elem, nm)
                if key in edits:
                    new = edits[key]
                    if dtype != 0x10:
                        print(f"  !! {elem}/{nm} is type 0x{dtype:02x}, not int — skipped")
                        continue
                    struct.pack_into('<i', d, a+16, new)
                    applied.append((elem, nm, data, new))
        off += sz
    open(out_path, 'wb').write(bytes(d))
    return applied

if __name__ == '__main__':
    edits = {('uses-sdk', 'targetSdkVersion'): 23}
    res = patch('apk/AndroidManifest.xml', 'AndroidManifest.patched.xml', edits)
    for e, n, old, new in res:
        print(f"  patched <{e} android:{n}>  {old} -> {new}")
    if not res:
        sys.exit("no edits applied")
