1# Copyright 2019 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import struct 6import sys 7import zipfile 8 9from util import build_utils 10 11_FIXED_ZIP_HEADER_LEN = 30 12 13 14def _PatchedDecodeExtra(self): 15 # Try to decode the extra field. 16 extra = self.extra 17 unpack = struct.unpack 18 while len(extra) >= 4: 19 tp, ln = unpack('<HH', extra[:4]) 20 if tp == 1: 21 if ln >= 24: 22 counts = unpack('<QQQ', extra[4:28]) 23 elif ln == 16: 24 counts = unpack('<QQ', extra[4:20]) 25 elif ln == 8: 26 counts = unpack('<Q', extra[4:12]) 27 elif ln == 0: 28 counts = () 29 else: 30 raise RuntimeError, "Corrupt extra field %s" % (ln, ) 31 32 idx = 0 33 34 # ZIP64 extension (large files and/or large archives) 35 if self.file_size in (0xffffffffffffffffL, 0xffffffffL): 36 self.file_size = counts[idx] 37 idx += 1 38 39 if self.compress_size == 0xFFFFFFFFL: 40 self.compress_size = counts[idx] 41 idx += 1 42 43 if self.header_offset == 0xffffffffL: 44 self.header_offset = counts[idx] 45 idx += 1 46 47 extra = extra[ln + 4:] 48 49 50def ApplyZipFileZipAlignFix(): 51 """Fix zipfile.ZipFile() to be able to open zipaligned .zip files. 52 53 Android's zip alignment uses not-quite-valid zip headers to perform alignment. 54 Python < 3.4 crashes when trying to load them. 55 https://bugs.python.org/issue14315 56 """ 57 if sys.version_info < (3, 4): 58 zipfile.ZipInfo._decodeExtra = ( # pylint: disable=protected-access 59 _PatchedDecodeExtra) 60 61 62def _SetAlignment(zip_obj, zip_info, alignment): 63 """Sets a ZipInfo's extra field such that the file will be aligned. 64 65 Args: 66 zip_obj: The ZipFile object that is being written. 67 zip_info: The ZipInfo object about to be written. 68 alignment: The amount of alignment (e.g. 4, or 4*1024). 69 """ 70 cur_offset = zip_obj.fp.tell() 71 header_size = _FIXED_ZIP_HEADER_LEN + len(zip_info.filename) 72 padding_needed = (alignment - ( 73 (cur_offset + header_size) % alignment)) % alignment 74 75 76 # Python writes |extra| to both the local file header and the central 77 # directory's file header. Android's zipalign tool writes only to the 78 # local file header, so there is more overhead in using python to align. 79 zip_info.extra = b'\0' * padding_needed 80 81 82def AddToZipHermetic(zip_file, 83 zip_path, 84 src_path=None, 85 data=None, 86 compress=None, 87 alignment=None): 88 """Same as build_utils.AddToZipHermetic(), but with alignment. 89 90 Args: 91 alignment: If set, align the data of the entry to this many bytes. 92 """ 93 zipinfo = build_utils.HermeticZipInfo(filename=zip_path) 94 if alignment: 95 _SetAlignment(zip_file, zipinfo, alignment) 96 build_utils.AddToZipHermetic( 97 zip_file, zipinfo, src_path=src_path, data=data, compress=compress) 98