Handle zip64 extra fields better

Test: check_target_files_signatures
Bug: 283033491
Change-Id: I7da89f8389c09cc99201cff342483c158bd7e9c1
diff --git a/tools/releasetools/check_target_files_signatures.py b/tools/releasetools/check_target_files_signatures.py
index d935607..a7b3523 100755
--- a/tools/releasetools/check_target_files_signatures.py
+++ b/tools/releasetools/check_target_files_signatures.py
@@ -241,7 +241,8 @@
     # Signer (minSdkVersion=24, maxSdkVersion=32) certificate SHA-1 digest: 19da94896ce4078c38ca695701f1dec741ec6d67
     # ...
     certs_info = {}
-    certificate_regex = re.compile(r"(Signer (?:#[0-9]+|\(.*\))) (certificate .*):(.*)")
+    certificate_regex = re.compile(
+        r"(Signer (?:#[0-9]+|\(.*\))) (certificate .*):(.*)")
     for line in output.splitlines():
       m = certificate_regex.match(line)
       if not m:
@@ -312,7 +313,7 @@
     # This is the list of wildcards of files we extract from |filename|.
     apk_extensions = ['*.apk', '*.apex']
 
-    with zipfile.ZipFile(filename) as input_zip:
+    with zipfile.ZipFile(filename, "r") as input_zip:
       self.certmap, compressed_extension = common.ReadApkCerts(input_zip)
     if compressed_extension:
       apk_extensions.append('*.apk' + compressed_extension)
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index d33397b..f00c1a9 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -2135,9 +2135,23 @@
     # to indicate the actual local header offset.
     # As of python3.11, python does not handle zip64 central directories
     # correctly, so we will manually do the parsing here.
+
+    # ZIP64 central directory extra field has two required fields:
+    # 2 bytes header ID and 2 bytes size field. Thes two require fields have
+    # a total size of 4 bytes. Then it has three other 8 bytes field, followed
+    # by a 4 byte disk number field. The last disk number field is not required
+    # to be present, but if it is present, the total size of extra field will be
+    # divisible by 8(because 2+2+4+8*n is always going to be multiple of 8)
+    # Most extra fields are optional, but when they appear, their must appear
+    # in the order defined by zip64 spec. Since file header offset is the 2nd
+    # to last field in zip64 spec, it will only be at last 8 bytes or last 12-4
+    # bytes, depending on whether disk number is present.
     for entry in entries:
-      if entry.header_offset == 0xFFFFFFFF and len(entry.extra) >= 28:
-        entry.header_offset = int.from_bytes(entry.extra[20:28], "little")
+      if entry.header_offset == 0xFFFFFFFF:
+        if len(entry.extra) % 8 == 0:
+          entry.header_offset = int.from_bytes(entry.extra[-12:-4], "little")
+        else:
+          entry.header_offset = int.from_bytes(entry.extra[-8:], "little")
     if patterns is not None:
       filtered = [info for info in entries if any(
           [fnmatch.fnmatch(info.filename, p) for p in patterns])]
diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py
index 4c0d391..f3e6f1e 100755
--- a/tools/releasetools/ota_from_target_files.py
+++ b/tools/releasetools/ota_from_target_files.py
@@ -633,14 +633,17 @@
         return True
     return False
 
-  postinstall_config = common.ReadFromInputFile(input_file, POSTINSTALL_CONFIG)
-  postinstall_config = [
-      line for line in postinstall_config.splitlines() if IsInPartialList(line)]
-  if postinstall_config:
-    postinstall_config = "\n".join(postinstall_config)
-    common.WriteToInputFile(input_file, POSTINSTALL_CONFIG, postinstall_config)
-  else:
-    os.unlink(os.path.join(input_file, POSTINSTALL_CONFIG))
+  if common.DoesInputFileContain(input_file, POSTINSTALL_CONFIG):
+    postinstall_config = common.ReadFromInputFile(
+        input_file, POSTINSTALL_CONFIG)
+    postinstall_config = [
+        line for line in postinstall_config.splitlines() if IsInPartialList(line)]
+    if postinstall_config:
+      postinstall_config = "\n".join(postinstall_config)
+      common.WriteToInputFile(
+          input_file, POSTINSTALL_CONFIG, postinstall_config)
+    else:
+      os.unlink(os.path.join(input_file, POSTINSTALL_CONFIG))
 
   return input_file