"""Rewrites Bouncy Castle calls that Android 2.x's Dalvik can't link. Calling an Object method (toString/equals/hashCode/getClass) through an *interface* type compiles to invokeinterface, which Dalvik before 4.0 can't resolve: NoSuchMethodError at runtime. Casting the receiver to Object makes javac emit invokevirtual instead. tools/scan_dalvik.py checks nothing was missed. """ import sys FIXES = [ ("asn1/ASN1InputStream.java", "asn1Obj.getClass()", "((Object) asn1Obj).getClass()"), ("asn1/ConstructedBitStream.java", "asn1Obj.getClass()", "((Object) asn1Obj).getClass()"), ("asn1/ConstructedOctetStream.java", "asn1Obj.getClass()", "((Object) asn1Obj).getClass()"), ("asn1/x509/AlgorithmIdentifier.java", "return pa.equals(pb);", "return ((Object) pa).equals(pb);"), ("asn1/x509/GeneralName.java", "buf.append(obj.toString());", "buf.append(((Object) obj).toString());"), ("crypto/CryptoServicesPermission.java", "return actions.toString();", "return ((Object) actions).toString();"), ("crypto/digests/SHA256Digest.java", "digest.getClass().getName()", "((Object) digest).getClass().getName()"), ("crypto/engines/AESEngine.java", "params.getClass().getName()", "((Object) params).getClass().getName()"), ("crypto/engines/ARIAEngine.java", "params.getClass().getName()", "((Object) params).getClass().getName()"), ("crypto/engines/DESedeEngine.java", "params.getClass().getName()", "((Object) params).getClass().getName()"), ("crypto/engines/SM4Engine.java", "params.getClass().getName()", "((Object) params).getClass().getName()"), ("crypto/modes/CCMBlockCipher.java", "params.getClass().getName()", "((Object) params).getClass().getName()"), ("math/ec/ECCurve.java", "getField().equals(other.getField())", "((Object) getField()).equals(other.getField())"), ("math/ec/ECCurve.java", "return getField().hashCode()", "return ((Object) getField()).hashCode()"), ("math/field/GenericPolynomialExtensionField.java", "return subfield.equals(other.subfield) && minimalPolynomial.equals(other.minimalPolynomial);", "return ((Object) subfield).equals(other.subfield) && ((Object) minimalPolynomial).equals(other.minimalPolynomial);"), ("math/field/GenericPolynomialExtensionField.java", "return subfield.hashCode()", "return ((Object) subfield).hashCode()"), ("math/field/GenericPolynomialExtensionField.java", "rotateLeft(minimalPolynomial.hashCode(), 16)", "rotateLeft(((Object) minimalPolynomial).hashCode(), 16)"), ("tls/crypto/impl/AbstractTlsCrypto.java", "secret.getClass().getName()", "((Object) secret).getClass().getName()"), ("tls/crypto/impl/bc/BcTlsSecret.java", "secret.getClass().getName()", "((Object) secret).getClass().getName()"), ] root = sys.argv[1].rstrip("/") + "/com/minamp/bc/" for rel, old, new in FIXES: p = root + rel s = open(p).read() if new in s: continue if old not in s: raise SystemExit("pattern not found in %s: %s" % (rel, old)) open(p, "w").write(s.replace(old, new)) print("patched %d call sites" % len(FIXES))