1*cda5da8dSAndroid Build Coastguard Worker"""zipimport provides support for importing Python modules from Zip archives. 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard WorkerThis module exports three objects: 4*cda5da8dSAndroid Build Coastguard Worker- zipimporter: a class; its constructor takes a path to a Zip archive. 5*cda5da8dSAndroid Build Coastguard Worker- ZipImportError: exception raised by zipimporter objects. It's a 6*cda5da8dSAndroid Build Coastguard Worker subclass of ImportError, so it can be caught as ImportError, too. 7*cda5da8dSAndroid Build Coastguard Worker- _zip_directory_cache: a dict, mapping archive paths to zip directory 8*cda5da8dSAndroid Build Coastguard Worker info dicts, as used in zipimporter._files. 9*cda5da8dSAndroid Build Coastguard Worker 10*cda5da8dSAndroid Build Coastguard WorkerIt is usually not needed to use the zipimport module explicitly; it is 11*cda5da8dSAndroid Build Coastguard Workerused by the builtin import mechanism for sys.path items that are paths 12*cda5da8dSAndroid Build Coastguard Workerto Zip archives. 13*cda5da8dSAndroid Build Coastguard Worker""" 14*cda5da8dSAndroid Build Coastguard Worker 15*cda5da8dSAndroid Build Coastguard Worker#from importlib import _bootstrap_external 16*cda5da8dSAndroid Build Coastguard Worker#from importlib import _bootstrap # for _verbose_message 17*cda5da8dSAndroid Build Coastguard Workerimport _frozen_importlib_external as _bootstrap_external 18*cda5da8dSAndroid Build Coastguard Workerfrom _frozen_importlib_external import _unpack_uint16, _unpack_uint32 19*cda5da8dSAndroid Build Coastguard Workerimport _frozen_importlib as _bootstrap # for _verbose_message 20*cda5da8dSAndroid Build Coastguard Workerimport _imp # for check_hash_based_pycs 21*cda5da8dSAndroid Build Coastguard Workerimport _io # for open 22*cda5da8dSAndroid Build Coastguard Workerimport marshal # for loads 23*cda5da8dSAndroid Build Coastguard Workerimport sys # for modules 24*cda5da8dSAndroid Build Coastguard Workerimport time # for mktime 25*cda5da8dSAndroid Build Coastguard Workerimport _warnings # For warn() 26*cda5da8dSAndroid Build Coastguard Worker 27*cda5da8dSAndroid Build Coastguard Worker__all__ = ['ZipImportError', 'zipimporter'] 28*cda5da8dSAndroid Build Coastguard Worker 29*cda5da8dSAndroid Build Coastguard Worker 30*cda5da8dSAndroid Build Coastguard Workerpath_sep = _bootstrap_external.path_sep 31*cda5da8dSAndroid Build Coastguard Workeralt_path_sep = _bootstrap_external.path_separators[1:] 32*cda5da8dSAndroid Build Coastguard Worker 33*cda5da8dSAndroid Build Coastguard Worker 34*cda5da8dSAndroid Build Coastguard Workerclass ZipImportError(ImportError): 35*cda5da8dSAndroid Build Coastguard Worker pass 36*cda5da8dSAndroid Build Coastguard Worker 37*cda5da8dSAndroid Build Coastguard Worker# _read_directory() cache 38*cda5da8dSAndroid Build Coastguard Worker_zip_directory_cache = {} 39*cda5da8dSAndroid Build Coastguard Worker 40*cda5da8dSAndroid Build Coastguard Worker_module_type = type(sys) 41*cda5da8dSAndroid Build Coastguard Worker 42*cda5da8dSAndroid Build Coastguard WorkerEND_CENTRAL_DIR_SIZE = 22 43*cda5da8dSAndroid Build Coastguard WorkerSTRING_END_ARCHIVE = b'PK\x05\x06' 44*cda5da8dSAndroid Build Coastguard WorkerMAX_COMMENT_LEN = (1 << 16) - 1 45*cda5da8dSAndroid Build Coastguard Worker 46*cda5da8dSAndroid Build Coastguard Workerclass zipimporter(_bootstrap_external._LoaderBasics): 47*cda5da8dSAndroid Build Coastguard Worker """zipimporter(archivepath) -> zipimporter object 48*cda5da8dSAndroid Build Coastguard Worker 49*cda5da8dSAndroid Build Coastguard Worker Create a new zipimporter instance. 'archivepath' must be a path to 50*cda5da8dSAndroid Build Coastguard Worker a zipfile, or to a specific path inside a zipfile. For example, it can be 51*cda5da8dSAndroid Build Coastguard Worker '/tmp/myimport.zip', or '/tmp/myimport.zip/mydirectory', if mydirectory is a 52*cda5da8dSAndroid Build Coastguard Worker valid directory inside the archive. 53*cda5da8dSAndroid Build Coastguard Worker 54*cda5da8dSAndroid Build Coastguard Worker 'ZipImportError is raised if 'archivepath' doesn't point to a valid Zip 55*cda5da8dSAndroid Build Coastguard Worker archive. 56*cda5da8dSAndroid Build Coastguard Worker 57*cda5da8dSAndroid Build Coastguard Worker The 'archive' attribute of zipimporter objects contains the name of the 58*cda5da8dSAndroid Build Coastguard Worker zipfile targeted. 59*cda5da8dSAndroid Build Coastguard Worker """ 60*cda5da8dSAndroid Build Coastguard Worker 61*cda5da8dSAndroid Build Coastguard Worker # Split the "subdirectory" from the Zip archive path, lookup a matching 62*cda5da8dSAndroid Build Coastguard Worker # entry in sys.path_importer_cache, fetch the file directory from there 63*cda5da8dSAndroid Build Coastguard Worker # if found, or else read it from the archive. 64*cda5da8dSAndroid Build Coastguard Worker def __init__(self, path): 65*cda5da8dSAndroid Build Coastguard Worker if not isinstance(path, str): 66*cda5da8dSAndroid Build Coastguard Worker raise TypeError(f"expected str, not {type(path)!r}") 67*cda5da8dSAndroid Build Coastguard Worker if not path: 68*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError('archive path is empty', path=path) 69*cda5da8dSAndroid Build Coastguard Worker if alt_path_sep: 70*cda5da8dSAndroid Build Coastguard Worker path = path.replace(alt_path_sep, path_sep) 71*cda5da8dSAndroid Build Coastguard Worker 72*cda5da8dSAndroid Build Coastguard Worker prefix = [] 73*cda5da8dSAndroid Build Coastguard Worker while True: 74*cda5da8dSAndroid Build Coastguard Worker try: 75*cda5da8dSAndroid Build Coastguard Worker st = _bootstrap_external._path_stat(path) 76*cda5da8dSAndroid Build Coastguard Worker except (OSError, ValueError): 77*cda5da8dSAndroid Build Coastguard Worker # On Windows a ValueError is raised for too long paths. 78*cda5da8dSAndroid Build Coastguard Worker # Back up one path element. 79*cda5da8dSAndroid Build Coastguard Worker dirname, basename = _bootstrap_external._path_split(path) 80*cda5da8dSAndroid Build Coastguard Worker if dirname == path: 81*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError('not a Zip file', path=path) 82*cda5da8dSAndroid Build Coastguard Worker path = dirname 83*cda5da8dSAndroid Build Coastguard Worker prefix.append(basename) 84*cda5da8dSAndroid Build Coastguard Worker else: 85*cda5da8dSAndroid Build Coastguard Worker # it exists 86*cda5da8dSAndroid Build Coastguard Worker if (st.st_mode & 0o170000) != 0o100000: # stat.S_ISREG 87*cda5da8dSAndroid Build Coastguard Worker # it's a not file 88*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError('not a Zip file', path=path) 89*cda5da8dSAndroid Build Coastguard Worker break 90*cda5da8dSAndroid Build Coastguard Worker 91*cda5da8dSAndroid Build Coastguard Worker try: 92*cda5da8dSAndroid Build Coastguard Worker files = _zip_directory_cache[path] 93*cda5da8dSAndroid Build Coastguard Worker except KeyError: 94*cda5da8dSAndroid Build Coastguard Worker files = _read_directory(path) 95*cda5da8dSAndroid Build Coastguard Worker _zip_directory_cache[path] = files 96*cda5da8dSAndroid Build Coastguard Worker self._files = files 97*cda5da8dSAndroid Build Coastguard Worker self.archive = path 98*cda5da8dSAndroid Build Coastguard Worker # a prefix directory following the ZIP file path. 99*cda5da8dSAndroid Build Coastguard Worker self.prefix = _bootstrap_external._path_join(*prefix[::-1]) 100*cda5da8dSAndroid Build Coastguard Worker if self.prefix: 101*cda5da8dSAndroid Build Coastguard Worker self.prefix += path_sep 102*cda5da8dSAndroid Build Coastguard Worker 103*cda5da8dSAndroid Build Coastguard Worker 104*cda5da8dSAndroid Build Coastguard Worker # Check whether we can satisfy the import of the module named by 105*cda5da8dSAndroid Build Coastguard Worker # 'fullname', or whether it could be a portion of a namespace 106*cda5da8dSAndroid Build Coastguard Worker # package. Return self if we can load it, a string containing the 107*cda5da8dSAndroid Build Coastguard Worker # full path if it's a possible namespace portion, None if we 108*cda5da8dSAndroid Build Coastguard Worker # can't load it. 109*cda5da8dSAndroid Build Coastguard Worker def find_loader(self, fullname, path=None): 110*cda5da8dSAndroid Build Coastguard Worker """find_loader(fullname, path=None) -> self, str or None. 111*cda5da8dSAndroid Build Coastguard Worker 112*cda5da8dSAndroid Build Coastguard Worker Search for a module specified by 'fullname'. 'fullname' must be the 113*cda5da8dSAndroid Build Coastguard Worker fully qualified (dotted) module name. It returns the zipimporter 114*cda5da8dSAndroid Build Coastguard Worker instance itself if the module was found, a string containing the 115*cda5da8dSAndroid Build Coastguard Worker full path name if it's possibly a portion of a namespace package, 116*cda5da8dSAndroid Build Coastguard Worker or None otherwise. The optional 'path' argument is ignored -- it's 117*cda5da8dSAndroid Build Coastguard Worker there for compatibility with the importer protocol. 118*cda5da8dSAndroid Build Coastguard Worker 119*cda5da8dSAndroid Build Coastguard Worker Deprecated since Python 3.10. Use find_spec() instead. 120*cda5da8dSAndroid Build Coastguard Worker """ 121*cda5da8dSAndroid Build Coastguard Worker _warnings.warn("zipimporter.find_loader() is deprecated and slated for " 122*cda5da8dSAndroid Build Coastguard Worker "removal in Python 3.12; use find_spec() instead", 123*cda5da8dSAndroid Build Coastguard Worker DeprecationWarning) 124*cda5da8dSAndroid Build Coastguard Worker mi = _get_module_info(self, fullname) 125*cda5da8dSAndroid Build Coastguard Worker if mi is not None: 126*cda5da8dSAndroid Build Coastguard Worker # This is a module or package. 127*cda5da8dSAndroid Build Coastguard Worker return self, [] 128*cda5da8dSAndroid Build Coastguard Worker 129*cda5da8dSAndroid Build Coastguard Worker # Not a module or regular package. See if this is a directory, and 130*cda5da8dSAndroid Build Coastguard Worker # therefore possibly a portion of a namespace package. 131*cda5da8dSAndroid Build Coastguard Worker 132*cda5da8dSAndroid Build Coastguard Worker # We're only interested in the last path component of fullname 133*cda5da8dSAndroid Build Coastguard Worker # earlier components are recorded in self.prefix. 134*cda5da8dSAndroid Build Coastguard Worker modpath = _get_module_path(self, fullname) 135*cda5da8dSAndroid Build Coastguard Worker if _is_dir(self, modpath): 136*cda5da8dSAndroid Build Coastguard Worker # This is possibly a portion of a namespace 137*cda5da8dSAndroid Build Coastguard Worker # package. Return the string representing its path, 138*cda5da8dSAndroid Build Coastguard Worker # without a trailing separator. 139*cda5da8dSAndroid Build Coastguard Worker return None, [f'{self.archive}{path_sep}{modpath}'] 140*cda5da8dSAndroid Build Coastguard Worker 141*cda5da8dSAndroid Build Coastguard Worker return None, [] 142*cda5da8dSAndroid Build Coastguard Worker 143*cda5da8dSAndroid Build Coastguard Worker 144*cda5da8dSAndroid Build Coastguard Worker # Check whether we can satisfy the import of the module named by 145*cda5da8dSAndroid Build Coastguard Worker # 'fullname'. Return self if we can, None if we can't. 146*cda5da8dSAndroid Build Coastguard Worker def find_module(self, fullname, path=None): 147*cda5da8dSAndroid Build Coastguard Worker """find_module(fullname, path=None) -> self or None. 148*cda5da8dSAndroid Build Coastguard Worker 149*cda5da8dSAndroid Build Coastguard Worker Search for a module specified by 'fullname'. 'fullname' must be the 150*cda5da8dSAndroid Build Coastguard Worker fully qualified (dotted) module name. It returns the zipimporter 151*cda5da8dSAndroid Build Coastguard Worker instance itself if the module was found, or None if it wasn't. 152*cda5da8dSAndroid Build Coastguard Worker The optional 'path' argument is ignored -- it's there for compatibility 153*cda5da8dSAndroid Build Coastguard Worker with the importer protocol. 154*cda5da8dSAndroid Build Coastguard Worker 155*cda5da8dSAndroid Build Coastguard Worker Deprecated since Python 3.10. Use find_spec() instead. 156*cda5da8dSAndroid Build Coastguard Worker """ 157*cda5da8dSAndroid Build Coastguard Worker _warnings.warn("zipimporter.find_module() is deprecated and slated for " 158*cda5da8dSAndroid Build Coastguard Worker "removal in Python 3.12; use find_spec() instead", 159*cda5da8dSAndroid Build Coastguard Worker DeprecationWarning) 160*cda5da8dSAndroid Build Coastguard Worker return self.find_loader(fullname, path)[0] 161*cda5da8dSAndroid Build Coastguard Worker 162*cda5da8dSAndroid Build Coastguard Worker def find_spec(self, fullname, target=None): 163*cda5da8dSAndroid Build Coastguard Worker """Create a ModuleSpec for the specified module. 164*cda5da8dSAndroid Build Coastguard Worker 165*cda5da8dSAndroid Build Coastguard Worker Returns None if the module cannot be found. 166*cda5da8dSAndroid Build Coastguard Worker """ 167*cda5da8dSAndroid Build Coastguard Worker module_info = _get_module_info(self, fullname) 168*cda5da8dSAndroid Build Coastguard Worker if module_info is not None: 169*cda5da8dSAndroid Build Coastguard Worker return _bootstrap.spec_from_loader(fullname, self, is_package=module_info) 170*cda5da8dSAndroid Build Coastguard Worker else: 171*cda5da8dSAndroid Build Coastguard Worker # Not a module or regular package. See if this is a directory, and 172*cda5da8dSAndroid Build Coastguard Worker # therefore possibly a portion of a namespace package. 173*cda5da8dSAndroid Build Coastguard Worker 174*cda5da8dSAndroid Build Coastguard Worker # We're only interested in the last path component of fullname 175*cda5da8dSAndroid Build Coastguard Worker # earlier components are recorded in self.prefix. 176*cda5da8dSAndroid Build Coastguard Worker modpath = _get_module_path(self, fullname) 177*cda5da8dSAndroid Build Coastguard Worker if _is_dir(self, modpath): 178*cda5da8dSAndroid Build Coastguard Worker # This is possibly a portion of a namespace 179*cda5da8dSAndroid Build Coastguard Worker # package. Return the string representing its path, 180*cda5da8dSAndroid Build Coastguard Worker # without a trailing separator. 181*cda5da8dSAndroid Build Coastguard Worker path = f'{self.archive}{path_sep}{modpath}' 182*cda5da8dSAndroid Build Coastguard Worker spec = _bootstrap.ModuleSpec(name=fullname, loader=None, 183*cda5da8dSAndroid Build Coastguard Worker is_package=True) 184*cda5da8dSAndroid Build Coastguard Worker spec.submodule_search_locations.append(path) 185*cda5da8dSAndroid Build Coastguard Worker return spec 186*cda5da8dSAndroid Build Coastguard Worker else: 187*cda5da8dSAndroid Build Coastguard Worker return None 188*cda5da8dSAndroid Build Coastguard Worker 189*cda5da8dSAndroid Build Coastguard Worker def get_code(self, fullname): 190*cda5da8dSAndroid Build Coastguard Worker """get_code(fullname) -> code object. 191*cda5da8dSAndroid Build Coastguard Worker 192*cda5da8dSAndroid Build Coastguard Worker Return the code object for the specified module. Raise ZipImportError 193*cda5da8dSAndroid Build Coastguard Worker if the module couldn't be imported. 194*cda5da8dSAndroid Build Coastguard Worker """ 195*cda5da8dSAndroid Build Coastguard Worker code, ispackage, modpath = _get_module_code(self, fullname) 196*cda5da8dSAndroid Build Coastguard Worker return code 197*cda5da8dSAndroid Build Coastguard Worker 198*cda5da8dSAndroid Build Coastguard Worker 199*cda5da8dSAndroid Build Coastguard Worker def get_data(self, pathname): 200*cda5da8dSAndroid Build Coastguard Worker """get_data(pathname) -> string with file data. 201*cda5da8dSAndroid Build Coastguard Worker 202*cda5da8dSAndroid Build Coastguard Worker Return the data associated with 'pathname'. Raise OSError if 203*cda5da8dSAndroid Build Coastguard Worker the file wasn't found. 204*cda5da8dSAndroid Build Coastguard Worker """ 205*cda5da8dSAndroid Build Coastguard Worker if alt_path_sep: 206*cda5da8dSAndroid Build Coastguard Worker pathname = pathname.replace(alt_path_sep, path_sep) 207*cda5da8dSAndroid Build Coastguard Worker 208*cda5da8dSAndroid Build Coastguard Worker key = pathname 209*cda5da8dSAndroid Build Coastguard Worker if pathname.startswith(self.archive + path_sep): 210*cda5da8dSAndroid Build Coastguard Worker key = pathname[len(self.archive + path_sep):] 211*cda5da8dSAndroid Build Coastguard Worker 212*cda5da8dSAndroid Build Coastguard Worker try: 213*cda5da8dSAndroid Build Coastguard Worker toc_entry = self._files[key] 214*cda5da8dSAndroid Build Coastguard Worker except KeyError: 215*cda5da8dSAndroid Build Coastguard Worker raise OSError(0, '', key) 216*cda5da8dSAndroid Build Coastguard Worker return _get_data(self.archive, toc_entry) 217*cda5da8dSAndroid Build Coastguard Worker 218*cda5da8dSAndroid Build Coastguard Worker 219*cda5da8dSAndroid Build Coastguard Worker # Return a string matching __file__ for the named module 220*cda5da8dSAndroid Build Coastguard Worker def get_filename(self, fullname): 221*cda5da8dSAndroid Build Coastguard Worker """get_filename(fullname) -> filename string. 222*cda5da8dSAndroid Build Coastguard Worker 223*cda5da8dSAndroid Build Coastguard Worker Return the filename for the specified module or raise ZipImportError 224*cda5da8dSAndroid Build Coastguard Worker if it couldn't be imported. 225*cda5da8dSAndroid Build Coastguard Worker """ 226*cda5da8dSAndroid Build Coastguard Worker # Deciding the filename requires working out where the code 227*cda5da8dSAndroid Build Coastguard Worker # would come from if the module was actually loaded 228*cda5da8dSAndroid Build Coastguard Worker code, ispackage, modpath = _get_module_code(self, fullname) 229*cda5da8dSAndroid Build Coastguard Worker return modpath 230*cda5da8dSAndroid Build Coastguard Worker 231*cda5da8dSAndroid Build Coastguard Worker 232*cda5da8dSAndroid Build Coastguard Worker def get_source(self, fullname): 233*cda5da8dSAndroid Build Coastguard Worker """get_source(fullname) -> source string. 234*cda5da8dSAndroid Build Coastguard Worker 235*cda5da8dSAndroid Build Coastguard Worker Return the source code for the specified module. Raise ZipImportError 236*cda5da8dSAndroid Build Coastguard Worker if the module couldn't be found, return None if the archive does 237*cda5da8dSAndroid Build Coastguard Worker contain the module, but has no source for it. 238*cda5da8dSAndroid Build Coastguard Worker """ 239*cda5da8dSAndroid Build Coastguard Worker mi = _get_module_info(self, fullname) 240*cda5da8dSAndroid Build Coastguard Worker if mi is None: 241*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't find module {fullname!r}", name=fullname) 242*cda5da8dSAndroid Build Coastguard Worker 243*cda5da8dSAndroid Build Coastguard Worker path = _get_module_path(self, fullname) 244*cda5da8dSAndroid Build Coastguard Worker if mi: 245*cda5da8dSAndroid Build Coastguard Worker fullpath = _bootstrap_external._path_join(path, '__init__.py') 246*cda5da8dSAndroid Build Coastguard Worker else: 247*cda5da8dSAndroid Build Coastguard Worker fullpath = f'{path}.py' 248*cda5da8dSAndroid Build Coastguard Worker 249*cda5da8dSAndroid Build Coastguard Worker try: 250*cda5da8dSAndroid Build Coastguard Worker toc_entry = self._files[fullpath] 251*cda5da8dSAndroid Build Coastguard Worker except KeyError: 252*cda5da8dSAndroid Build Coastguard Worker # we have the module, but no source 253*cda5da8dSAndroid Build Coastguard Worker return None 254*cda5da8dSAndroid Build Coastguard Worker return _get_data(self.archive, toc_entry).decode() 255*cda5da8dSAndroid Build Coastguard Worker 256*cda5da8dSAndroid Build Coastguard Worker 257*cda5da8dSAndroid Build Coastguard Worker # Return a bool signifying whether the module is a package or not. 258*cda5da8dSAndroid Build Coastguard Worker def is_package(self, fullname): 259*cda5da8dSAndroid Build Coastguard Worker """is_package(fullname) -> bool. 260*cda5da8dSAndroid Build Coastguard Worker 261*cda5da8dSAndroid Build Coastguard Worker Return True if the module specified by fullname is a package. 262*cda5da8dSAndroid Build Coastguard Worker Raise ZipImportError if the module couldn't be found. 263*cda5da8dSAndroid Build Coastguard Worker """ 264*cda5da8dSAndroid Build Coastguard Worker mi = _get_module_info(self, fullname) 265*cda5da8dSAndroid Build Coastguard Worker if mi is None: 266*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't find module {fullname!r}", name=fullname) 267*cda5da8dSAndroid Build Coastguard Worker return mi 268*cda5da8dSAndroid Build Coastguard Worker 269*cda5da8dSAndroid Build Coastguard Worker 270*cda5da8dSAndroid Build Coastguard Worker # Load and return the module named by 'fullname'. 271*cda5da8dSAndroid Build Coastguard Worker def load_module(self, fullname): 272*cda5da8dSAndroid Build Coastguard Worker """load_module(fullname) -> module. 273*cda5da8dSAndroid Build Coastguard Worker 274*cda5da8dSAndroid Build Coastguard Worker Load the module specified by 'fullname'. 'fullname' must be the 275*cda5da8dSAndroid Build Coastguard Worker fully qualified (dotted) module name. It returns the imported 276*cda5da8dSAndroid Build Coastguard Worker module, or raises ZipImportError if it could not be imported. 277*cda5da8dSAndroid Build Coastguard Worker 278*cda5da8dSAndroid Build Coastguard Worker Deprecated since Python 3.10. Use exec_module() instead. 279*cda5da8dSAndroid Build Coastguard Worker """ 280*cda5da8dSAndroid Build Coastguard Worker msg = ("zipimport.zipimporter.load_module() is deprecated and slated for " 281*cda5da8dSAndroid Build Coastguard Worker "removal in Python 3.12; use exec_module() instead") 282*cda5da8dSAndroid Build Coastguard Worker _warnings.warn(msg, DeprecationWarning) 283*cda5da8dSAndroid Build Coastguard Worker code, ispackage, modpath = _get_module_code(self, fullname) 284*cda5da8dSAndroid Build Coastguard Worker mod = sys.modules.get(fullname) 285*cda5da8dSAndroid Build Coastguard Worker if mod is None or not isinstance(mod, _module_type): 286*cda5da8dSAndroid Build Coastguard Worker mod = _module_type(fullname) 287*cda5da8dSAndroid Build Coastguard Worker sys.modules[fullname] = mod 288*cda5da8dSAndroid Build Coastguard Worker mod.__loader__ = self 289*cda5da8dSAndroid Build Coastguard Worker 290*cda5da8dSAndroid Build Coastguard Worker try: 291*cda5da8dSAndroid Build Coastguard Worker if ispackage: 292*cda5da8dSAndroid Build Coastguard Worker # add __path__ to the module *before* the code gets 293*cda5da8dSAndroid Build Coastguard Worker # executed 294*cda5da8dSAndroid Build Coastguard Worker path = _get_module_path(self, fullname) 295*cda5da8dSAndroid Build Coastguard Worker fullpath = _bootstrap_external._path_join(self.archive, path) 296*cda5da8dSAndroid Build Coastguard Worker mod.__path__ = [fullpath] 297*cda5da8dSAndroid Build Coastguard Worker 298*cda5da8dSAndroid Build Coastguard Worker if not hasattr(mod, '__builtins__'): 299*cda5da8dSAndroid Build Coastguard Worker mod.__builtins__ = __builtins__ 300*cda5da8dSAndroid Build Coastguard Worker _bootstrap_external._fix_up_module(mod.__dict__, fullname, modpath) 301*cda5da8dSAndroid Build Coastguard Worker exec(code, mod.__dict__) 302*cda5da8dSAndroid Build Coastguard Worker except: 303*cda5da8dSAndroid Build Coastguard Worker del sys.modules[fullname] 304*cda5da8dSAndroid Build Coastguard Worker raise 305*cda5da8dSAndroid Build Coastguard Worker 306*cda5da8dSAndroid Build Coastguard Worker try: 307*cda5da8dSAndroid Build Coastguard Worker mod = sys.modules[fullname] 308*cda5da8dSAndroid Build Coastguard Worker except KeyError: 309*cda5da8dSAndroid Build Coastguard Worker raise ImportError(f'Loaded module {fullname!r} not found in sys.modules') 310*cda5da8dSAndroid Build Coastguard Worker _bootstrap._verbose_message('import {} # loaded from Zip {}', fullname, modpath) 311*cda5da8dSAndroid Build Coastguard Worker return mod 312*cda5da8dSAndroid Build Coastguard Worker 313*cda5da8dSAndroid Build Coastguard Worker 314*cda5da8dSAndroid Build Coastguard Worker def get_resource_reader(self, fullname): 315*cda5da8dSAndroid Build Coastguard Worker """Return the ResourceReader for a package in a zip file. 316*cda5da8dSAndroid Build Coastguard Worker 317*cda5da8dSAndroid Build Coastguard Worker If 'fullname' is a package within the zip file, return the 318*cda5da8dSAndroid Build Coastguard Worker 'ResourceReader' object for the package. Otherwise return None. 319*cda5da8dSAndroid Build Coastguard Worker """ 320*cda5da8dSAndroid Build Coastguard Worker try: 321*cda5da8dSAndroid Build Coastguard Worker if not self.is_package(fullname): 322*cda5da8dSAndroid Build Coastguard Worker return None 323*cda5da8dSAndroid Build Coastguard Worker except ZipImportError: 324*cda5da8dSAndroid Build Coastguard Worker return None 325*cda5da8dSAndroid Build Coastguard Worker from importlib.readers import ZipReader 326*cda5da8dSAndroid Build Coastguard Worker return ZipReader(self, fullname) 327*cda5da8dSAndroid Build Coastguard Worker 328*cda5da8dSAndroid Build Coastguard Worker 329*cda5da8dSAndroid Build Coastguard Worker def invalidate_caches(self): 330*cda5da8dSAndroid Build Coastguard Worker """Reload the file data of the archive path.""" 331*cda5da8dSAndroid Build Coastguard Worker try: 332*cda5da8dSAndroid Build Coastguard Worker self._files = _read_directory(self.archive) 333*cda5da8dSAndroid Build Coastguard Worker _zip_directory_cache[self.archive] = self._files 334*cda5da8dSAndroid Build Coastguard Worker except ZipImportError: 335*cda5da8dSAndroid Build Coastguard Worker _zip_directory_cache.pop(self.archive, None) 336*cda5da8dSAndroid Build Coastguard Worker self._files = {} 337*cda5da8dSAndroid Build Coastguard Worker 338*cda5da8dSAndroid Build Coastguard Worker 339*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 340*cda5da8dSAndroid Build Coastguard Worker return f'<zipimporter object "{self.archive}{path_sep}{self.prefix}">' 341*cda5da8dSAndroid Build Coastguard Worker 342*cda5da8dSAndroid Build Coastguard Worker 343*cda5da8dSAndroid Build Coastguard Worker# _zip_searchorder defines how we search for a module in the Zip 344*cda5da8dSAndroid Build Coastguard Worker# archive: we first search for a package __init__, then for 345*cda5da8dSAndroid Build Coastguard Worker# non-package .pyc, and .py entries. The .pyc entries 346*cda5da8dSAndroid Build Coastguard Worker# are swapped by initzipimport() if we run in optimized mode. Also, 347*cda5da8dSAndroid Build Coastguard Worker# '/' is replaced by path_sep there. 348*cda5da8dSAndroid Build Coastguard Worker_zip_searchorder = ( 349*cda5da8dSAndroid Build Coastguard Worker (path_sep + '__init__.pyc', True, True), 350*cda5da8dSAndroid Build Coastguard Worker (path_sep + '__init__.py', False, True), 351*cda5da8dSAndroid Build Coastguard Worker ('.pyc', True, False), 352*cda5da8dSAndroid Build Coastguard Worker ('.py', False, False), 353*cda5da8dSAndroid Build Coastguard Worker) 354*cda5da8dSAndroid Build Coastguard Worker 355*cda5da8dSAndroid Build Coastguard Worker# Given a module name, return the potential file path in the 356*cda5da8dSAndroid Build Coastguard Worker# archive (without extension). 357*cda5da8dSAndroid Build Coastguard Workerdef _get_module_path(self, fullname): 358*cda5da8dSAndroid Build Coastguard Worker return self.prefix + fullname.rpartition('.')[2] 359*cda5da8dSAndroid Build Coastguard Worker 360*cda5da8dSAndroid Build Coastguard Worker# Does this path represent a directory? 361*cda5da8dSAndroid Build Coastguard Workerdef _is_dir(self, path): 362*cda5da8dSAndroid Build Coastguard Worker # See if this is a "directory". If so, it's eligible to be part 363*cda5da8dSAndroid Build Coastguard Worker # of a namespace package. We test by seeing if the name, with an 364*cda5da8dSAndroid Build Coastguard Worker # appended path separator, exists. 365*cda5da8dSAndroid Build Coastguard Worker dirpath = path + path_sep 366*cda5da8dSAndroid Build Coastguard Worker # If dirpath is present in self._files, we have a directory. 367*cda5da8dSAndroid Build Coastguard Worker return dirpath in self._files 368*cda5da8dSAndroid Build Coastguard Worker 369*cda5da8dSAndroid Build Coastguard Worker# Return some information about a module. 370*cda5da8dSAndroid Build Coastguard Workerdef _get_module_info(self, fullname): 371*cda5da8dSAndroid Build Coastguard Worker path = _get_module_path(self, fullname) 372*cda5da8dSAndroid Build Coastguard Worker for suffix, isbytecode, ispackage in _zip_searchorder: 373*cda5da8dSAndroid Build Coastguard Worker fullpath = path + suffix 374*cda5da8dSAndroid Build Coastguard Worker if fullpath in self._files: 375*cda5da8dSAndroid Build Coastguard Worker return ispackage 376*cda5da8dSAndroid Build Coastguard Worker return None 377*cda5da8dSAndroid Build Coastguard Worker 378*cda5da8dSAndroid Build Coastguard Worker 379*cda5da8dSAndroid Build Coastguard Worker# implementation 380*cda5da8dSAndroid Build Coastguard Worker 381*cda5da8dSAndroid Build Coastguard Worker# _read_directory(archive) -> files dict (new reference) 382*cda5da8dSAndroid Build Coastguard Worker# 383*cda5da8dSAndroid Build Coastguard Worker# Given a path to a Zip archive, build a dict, mapping file names 384*cda5da8dSAndroid Build Coastguard Worker# (local to the archive, using SEP as a separator) to toc entries. 385*cda5da8dSAndroid Build Coastguard Worker# 386*cda5da8dSAndroid Build Coastguard Worker# A toc_entry is a tuple: 387*cda5da8dSAndroid Build Coastguard Worker# 388*cda5da8dSAndroid Build Coastguard Worker# (__file__, # value to use for __file__, available for all files, 389*cda5da8dSAndroid Build Coastguard Worker# # encoded to the filesystem encoding 390*cda5da8dSAndroid Build Coastguard Worker# compress, # compression kind; 0 for uncompressed 391*cda5da8dSAndroid Build Coastguard Worker# data_size, # size of compressed data on disk 392*cda5da8dSAndroid Build Coastguard Worker# file_size, # size of decompressed data 393*cda5da8dSAndroid Build Coastguard Worker# file_offset, # offset of file header from start of archive 394*cda5da8dSAndroid Build Coastguard Worker# time, # mod time of file (in dos format) 395*cda5da8dSAndroid Build Coastguard Worker# date, # mod data of file (in dos format) 396*cda5da8dSAndroid Build Coastguard Worker# crc, # crc checksum of the data 397*cda5da8dSAndroid Build Coastguard Worker# ) 398*cda5da8dSAndroid Build Coastguard Worker# 399*cda5da8dSAndroid Build Coastguard Worker# Directories can be recognized by the trailing path_sep in the name, 400*cda5da8dSAndroid Build Coastguard Worker# data_size and file_offset are 0. 401*cda5da8dSAndroid Build Coastguard Workerdef _read_directory(archive): 402*cda5da8dSAndroid Build Coastguard Worker try: 403*cda5da8dSAndroid Build Coastguard Worker fp = _io.open_code(archive) 404*cda5da8dSAndroid Build Coastguard Worker except OSError: 405*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't open Zip file: {archive!r}", path=archive) 406*cda5da8dSAndroid Build Coastguard Worker 407*cda5da8dSAndroid Build Coastguard Worker with fp: 408*cda5da8dSAndroid Build Coastguard Worker # GH-87235: On macOS all file descriptors for /dev/fd/N share the same 409*cda5da8dSAndroid Build Coastguard Worker # file offset, reset the file offset after scanning the zipfile diretory 410*cda5da8dSAndroid Build Coastguard Worker # to not cause problems when some runs 'python3 /dev/fd/9 9<some_script' 411*cda5da8dSAndroid Build Coastguard Worker start_offset = fp.tell() 412*cda5da8dSAndroid Build Coastguard Worker try: 413*cda5da8dSAndroid Build Coastguard Worker try: 414*cda5da8dSAndroid Build Coastguard Worker fp.seek(-END_CENTRAL_DIR_SIZE, 2) 415*cda5da8dSAndroid Build Coastguard Worker header_position = fp.tell() 416*cda5da8dSAndroid Build Coastguard Worker buffer = fp.read(END_CENTRAL_DIR_SIZE) 417*cda5da8dSAndroid Build Coastguard Worker except OSError: 418*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 419*cda5da8dSAndroid Build Coastguard Worker if len(buffer) != END_CENTRAL_DIR_SIZE: 420*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 421*cda5da8dSAndroid Build Coastguard Worker if buffer[:4] != STRING_END_ARCHIVE: 422*cda5da8dSAndroid Build Coastguard Worker # Bad: End of Central Dir signature 423*cda5da8dSAndroid Build Coastguard Worker # Check if there's a comment. 424*cda5da8dSAndroid Build Coastguard Worker try: 425*cda5da8dSAndroid Build Coastguard Worker fp.seek(0, 2) 426*cda5da8dSAndroid Build Coastguard Worker file_size = fp.tell() 427*cda5da8dSAndroid Build Coastguard Worker except OSError: 428*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't read Zip file: {archive!r}", 429*cda5da8dSAndroid Build Coastguard Worker path=archive) 430*cda5da8dSAndroid Build Coastguard Worker max_comment_start = max(file_size - MAX_COMMENT_LEN - 431*cda5da8dSAndroid Build Coastguard Worker END_CENTRAL_DIR_SIZE, 0) 432*cda5da8dSAndroid Build Coastguard Worker try: 433*cda5da8dSAndroid Build Coastguard Worker fp.seek(max_comment_start) 434*cda5da8dSAndroid Build Coastguard Worker data = fp.read() 435*cda5da8dSAndroid Build Coastguard Worker except OSError: 436*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't read Zip file: {archive!r}", 437*cda5da8dSAndroid Build Coastguard Worker path=archive) 438*cda5da8dSAndroid Build Coastguard Worker pos = data.rfind(STRING_END_ARCHIVE) 439*cda5da8dSAndroid Build Coastguard Worker if pos < 0: 440*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f'not a Zip file: {archive!r}', 441*cda5da8dSAndroid Build Coastguard Worker path=archive) 442*cda5da8dSAndroid Build Coastguard Worker buffer = data[pos:pos+END_CENTRAL_DIR_SIZE] 443*cda5da8dSAndroid Build Coastguard Worker if len(buffer) != END_CENTRAL_DIR_SIZE: 444*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"corrupt Zip file: {archive!r}", 445*cda5da8dSAndroid Build Coastguard Worker path=archive) 446*cda5da8dSAndroid Build Coastguard Worker header_position = file_size - len(data) + pos 447*cda5da8dSAndroid Build Coastguard Worker 448*cda5da8dSAndroid Build Coastguard Worker header_size = _unpack_uint32(buffer[12:16]) 449*cda5da8dSAndroid Build Coastguard Worker header_offset = _unpack_uint32(buffer[16:20]) 450*cda5da8dSAndroid Build Coastguard Worker if header_position < header_size: 451*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f'bad central directory size: {archive!r}', path=archive) 452*cda5da8dSAndroid Build Coastguard Worker if header_position < header_offset: 453*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f'bad central directory offset: {archive!r}', path=archive) 454*cda5da8dSAndroid Build Coastguard Worker header_position -= header_size 455*cda5da8dSAndroid Build Coastguard Worker arc_offset = header_position - header_offset 456*cda5da8dSAndroid Build Coastguard Worker if arc_offset < 0: 457*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f'bad central directory size or offset: {archive!r}', path=archive) 458*cda5da8dSAndroid Build Coastguard Worker 459*cda5da8dSAndroid Build Coastguard Worker files = {} 460*cda5da8dSAndroid Build Coastguard Worker # Start of Central Directory 461*cda5da8dSAndroid Build Coastguard Worker count = 0 462*cda5da8dSAndroid Build Coastguard Worker try: 463*cda5da8dSAndroid Build Coastguard Worker fp.seek(header_position) 464*cda5da8dSAndroid Build Coastguard Worker except OSError: 465*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 466*cda5da8dSAndroid Build Coastguard Worker while True: 467*cda5da8dSAndroid Build Coastguard Worker buffer = fp.read(46) 468*cda5da8dSAndroid Build Coastguard Worker if len(buffer) < 4: 469*cda5da8dSAndroid Build Coastguard Worker raise EOFError('EOF read where not expected') 470*cda5da8dSAndroid Build Coastguard Worker # Start of file header 471*cda5da8dSAndroid Build Coastguard Worker if buffer[:4] != b'PK\x01\x02': 472*cda5da8dSAndroid Build Coastguard Worker break # Bad: Central Dir File Header 473*cda5da8dSAndroid Build Coastguard Worker if len(buffer) != 46: 474*cda5da8dSAndroid Build Coastguard Worker raise EOFError('EOF read where not expected') 475*cda5da8dSAndroid Build Coastguard Worker flags = _unpack_uint16(buffer[8:10]) 476*cda5da8dSAndroid Build Coastguard Worker compress = _unpack_uint16(buffer[10:12]) 477*cda5da8dSAndroid Build Coastguard Worker time = _unpack_uint16(buffer[12:14]) 478*cda5da8dSAndroid Build Coastguard Worker date = _unpack_uint16(buffer[14:16]) 479*cda5da8dSAndroid Build Coastguard Worker crc = _unpack_uint32(buffer[16:20]) 480*cda5da8dSAndroid Build Coastguard Worker data_size = _unpack_uint32(buffer[20:24]) 481*cda5da8dSAndroid Build Coastguard Worker file_size = _unpack_uint32(buffer[24:28]) 482*cda5da8dSAndroid Build Coastguard Worker name_size = _unpack_uint16(buffer[28:30]) 483*cda5da8dSAndroid Build Coastguard Worker extra_size = _unpack_uint16(buffer[30:32]) 484*cda5da8dSAndroid Build Coastguard Worker comment_size = _unpack_uint16(buffer[32:34]) 485*cda5da8dSAndroid Build Coastguard Worker file_offset = _unpack_uint32(buffer[42:46]) 486*cda5da8dSAndroid Build Coastguard Worker header_size = name_size + extra_size + comment_size 487*cda5da8dSAndroid Build Coastguard Worker if file_offset > header_offset: 488*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f'bad local header offset: {archive!r}', path=archive) 489*cda5da8dSAndroid Build Coastguard Worker file_offset += arc_offset 490*cda5da8dSAndroid Build Coastguard Worker 491*cda5da8dSAndroid Build Coastguard Worker try: 492*cda5da8dSAndroid Build Coastguard Worker name = fp.read(name_size) 493*cda5da8dSAndroid Build Coastguard Worker except OSError: 494*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 495*cda5da8dSAndroid Build Coastguard Worker if len(name) != name_size: 496*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 497*cda5da8dSAndroid Build Coastguard Worker # On Windows, calling fseek to skip over the fields we don't use is 498*cda5da8dSAndroid Build Coastguard Worker # slower than reading the data because fseek flushes stdio's 499*cda5da8dSAndroid Build Coastguard Worker # internal buffers. See issue #8745. 500*cda5da8dSAndroid Build Coastguard Worker try: 501*cda5da8dSAndroid Build Coastguard Worker if len(fp.read(header_size - name_size)) != header_size - name_size: 502*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 503*cda5da8dSAndroid Build Coastguard Worker except OSError: 504*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 505*cda5da8dSAndroid Build Coastguard Worker 506*cda5da8dSAndroid Build Coastguard Worker if flags & 0x800: 507*cda5da8dSAndroid Build Coastguard Worker # UTF-8 file names extension 508*cda5da8dSAndroid Build Coastguard Worker name = name.decode() 509*cda5da8dSAndroid Build Coastguard Worker else: 510*cda5da8dSAndroid Build Coastguard Worker # Historical ZIP filename encoding 511*cda5da8dSAndroid Build Coastguard Worker try: 512*cda5da8dSAndroid Build Coastguard Worker name = name.decode('ascii') 513*cda5da8dSAndroid Build Coastguard Worker except UnicodeDecodeError: 514*cda5da8dSAndroid Build Coastguard Worker name = name.decode('latin1').translate(cp437_table) 515*cda5da8dSAndroid Build Coastguard Worker 516*cda5da8dSAndroid Build Coastguard Worker name = name.replace('/', path_sep) 517*cda5da8dSAndroid Build Coastguard Worker path = _bootstrap_external._path_join(archive, name) 518*cda5da8dSAndroid Build Coastguard Worker t = (path, compress, data_size, file_size, file_offset, time, date, crc) 519*cda5da8dSAndroid Build Coastguard Worker files[name] = t 520*cda5da8dSAndroid Build Coastguard Worker count += 1 521*cda5da8dSAndroid Build Coastguard Worker finally: 522*cda5da8dSAndroid Build Coastguard Worker fp.seek(start_offset) 523*cda5da8dSAndroid Build Coastguard Worker _bootstrap._verbose_message('zipimport: found {} names in {!r}', count, archive) 524*cda5da8dSAndroid Build Coastguard Worker return files 525*cda5da8dSAndroid Build Coastguard Worker 526*cda5da8dSAndroid Build Coastguard Worker# During bootstrap, we may need to load the encodings 527*cda5da8dSAndroid Build Coastguard Worker# package from a ZIP file. But the cp437 encoding is implemented 528*cda5da8dSAndroid Build Coastguard Worker# in Python in the encodings package. 529*cda5da8dSAndroid Build Coastguard Worker# 530*cda5da8dSAndroid Build Coastguard Worker# Break out of this dependency by using the translation table for 531*cda5da8dSAndroid Build Coastguard Worker# the cp437 encoding. 532*cda5da8dSAndroid Build Coastguard Workercp437_table = ( 533*cda5da8dSAndroid Build Coastguard Worker # ASCII part, 8 rows x 16 chars 534*cda5da8dSAndroid Build Coastguard Worker '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' 535*cda5da8dSAndroid Build Coastguard Worker '\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f' 536*cda5da8dSAndroid Build Coastguard Worker ' !"#$%&\'()*+,-./' 537*cda5da8dSAndroid Build Coastguard Worker '0123456789:;<=>?' 538*cda5da8dSAndroid Build Coastguard Worker '@ABCDEFGHIJKLMNO' 539*cda5da8dSAndroid Build Coastguard Worker 'PQRSTUVWXYZ[\\]^_' 540*cda5da8dSAndroid Build Coastguard Worker '`abcdefghijklmno' 541*cda5da8dSAndroid Build Coastguard Worker 'pqrstuvwxyz{|}~\x7f' 542*cda5da8dSAndroid Build Coastguard Worker # non-ASCII part, 16 rows x 8 chars 543*cda5da8dSAndroid Build Coastguard Worker '\xc7\xfc\xe9\xe2\xe4\xe0\xe5\xe7' 544*cda5da8dSAndroid Build Coastguard Worker '\xea\xeb\xe8\xef\xee\xec\xc4\xc5' 545*cda5da8dSAndroid Build Coastguard Worker '\xc9\xe6\xc6\xf4\xf6\xf2\xfb\xf9' 546*cda5da8dSAndroid Build Coastguard Worker '\xff\xd6\xdc\xa2\xa3\xa5\u20a7\u0192' 547*cda5da8dSAndroid Build Coastguard Worker '\xe1\xed\xf3\xfa\xf1\xd1\xaa\xba' 548*cda5da8dSAndroid Build Coastguard Worker '\xbf\u2310\xac\xbd\xbc\xa1\xab\xbb' 549*cda5da8dSAndroid Build Coastguard Worker '\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556' 550*cda5da8dSAndroid Build Coastguard Worker '\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510' 551*cda5da8dSAndroid Build Coastguard Worker '\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f' 552*cda5da8dSAndroid Build Coastguard Worker '\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567' 553*cda5da8dSAndroid Build Coastguard Worker '\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b' 554*cda5da8dSAndroid Build Coastguard Worker '\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580' 555*cda5da8dSAndroid Build Coastguard Worker '\u03b1\xdf\u0393\u03c0\u03a3\u03c3\xb5\u03c4' 556*cda5da8dSAndroid Build Coastguard Worker '\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229' 557*cda5da8dSAndroid Build Coastguard Worker '\u2261\xb1\u2265\u2264\u2320\u2321\xf7\u2248' 558*cda5da8dSAndroid Build Coastguard Worker '\xb0\u2219\xb7\u221a\u207f\xb2\u25a0\xa0' 559*cda5da8dSAndroid Build Coastguard Worker) 560*cda5da8dSAndroid Build Coastguard Worker 561*cda5da8dSAndroid Build Coastguard Worker_importing_zlib = False 562*cda5da8dSAndroid Build Coastguard Worker 563*cda5da8dSAndroid Build Coastguard Worker# Return the zlib.decompress function object, or NULL if zlib couldn't 564*cda5da8dSAndroid Build Coastguard Worker# be imported. The function is cached when found, so subsequent calls 565*cda5da8dSAndroid Build Coastguard Worker# don't import zlib again. 566*cda5da8dSAndroid Build Coastguard Workerdef _get_decompress_func(): 567*cda5da8dSAndroid Build Coastguard Worker global _importing_zlib 568*cda5da8dSAndroid Build Coastguard Worker if _importing_zlib: 569*cda5da8dSAndroid Build Coastguard Worker # Someone has a zlib.py[co] in their Zip file 570*cda5da8dSAndroid Build Coastguard Worker # let's avoid a stack overflow. 571*cda5da8dSAndroid Build Coastguard Worker _bootstrap._verbose_message('zipimport: zlib UNAVAILABLE') 572*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError("can't decompress data; zlib not available") 573*cda5da8dSAndroid Build Coastguard Worker 574*cda5da8dSAndroid Build Coastguard Worker _importing_zlib = True 575*cda5da8dSAndroid Build Coastguard Worker try: 576*cda5da8dSAndroid Build Coastguard Worker from zlib import decompress 577*cda5da8dSAndroid Build Coastguard Worker except Exception: 578*cda5da8dSAndroid Build Coastguard Worker _bootstrap._verbose_message('zipimport: zlib UNAVAILABLE') 579*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError("can't decompress data; zlib not available") 580*cda5da8dSAndroid Build Coastguard Worker finally: 581*cda5da8dSAndroid Build Coastguard Worker _importing_zlib = False 582*cda5da8dSAndroid Build Coastguard Worker 583*cda5da8dSAndroid Build Coastguard Worker _bootstrap._verbose_message('zipimport: zlib available') 584*cda5da8dSAndroid Build Coastguard Worker return decompress 585*cda5da8dSAndroid Build Coastguard Worker 586*cda5da8dSAndroid Build Coastguard Worker# Given a path to a Zip file and a toc_entry, return the (uncompressed) data. 587*cda5da8dSAndroid Build Coastguard Workerdef _get_data(archive, toc_entry): 588*cda5da8dSAndroid Build Coastguard Worker datapath, compress, data_size, file_size, file_offset, time, date, crc = toc_entry 589*cda5da8dSAndroid Build Coastguard Worker if data_size < 0: 590*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError('negative data size') 591*cda5da8dSAndroid Build Coastguard Worker 592*cda5da8dSAndroid Build Coastguard Worker with _io.open_code(archive) as fp: 593*cda5da8dSAndroid Build Coastguard Worker # Check to make sure the local file header is correct 594*cda5da8dSAndroid Build Coastguard Worker try: 595*cda5da8dSAndroid Build Coastguard Worker fp.seek(file_offset) 596*cda5da8dSAndroid Build Coastguard Worker except OSError: 597*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 598*cda5da8dSAndroid Build Coastguard Worker buffer = fp.read(30) 599*cda5da8dSAndroid Build Coastguard Worker if len(buffer) != 30: 600*cda5da8dSAndroid Build Coastguard Worker raise EOFError('EOF read where not expected') 601*cda5da8dSAndroid Build Coastguard Worker 602*cda5da8dSAndroid Build Coastguard Worker if buffer[:4] != b'PK\x03\x04': 603*cda5da8dSAndroid Build Coastguard Worker # Bad: Local File Header 604*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f'bad local file header: {archive!r}', path=archive) 605*cda5da8dSAndroid Build Coastguard Worker 606*cda5da8dSAndroid Build Coastguard Worker name_size = _unpack_uint16(buffer[26:28]) 607*cda5da8dSAndroid Build Coastguard Worker extra_size = _unpack_uint16(buffer[28:30]) 608*cda5da8dSAndroid Build Coastguard Worker header_size = 30 + name_size + extra_size 609*cda5da8dSAndroid Build Coastguard Worker file_offset += header_size # Start of file data 610*cda5da8dSAndroid Build Coastguard Worker try: 611*cda5da8dSAndroid Build Coastguard Worker fp.seek(file_offset) 612*cda5da8dSAndroid Build Coastguard Worker except OSError: 613*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 614*cda5da8dSAndroid Build Coastguard Worker raw_data = fp.read(data_size) 615*cda5da8dSAndroid Build Coastguard Worker if len(raw_data) != data_size: 616*cda5da8dSAndroid Build Coastguard Worker raise OSError("zipimport: can't read data") 617*cda5da8dSAndroid Build Coastguard Worker 618*cda5da8dSAndroid Build Coastguard Worker if compress == 0: 619*cda5da8dSAndroid Build Coastguard Worker # data is not compressed 620*cda5da8dSAndroid Build Coastguard Worker return raw_data 621*cda5da8dSAndroid Build Coastguard Worker 622*cda5da8dSAndroid Build Coastguard Worker # Decompress with zlib 623*cda5da8dSAndroid Build Coastguard Worker try: 624*cda5da8dSAndroid Build Coastguard Worker decompress = _get_decompress_func() 625*cda5da8dSAndroid Build Coastguard Worker except Exception: 626*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError("can't decompress data; zlib not available") 627*cda5da8dSAndroid Build Coastguard Worker return decompress(raw_data, -15) 628*cda5da8dSAndroid Build Coastguard Worker 629*cda5da8dSAndroid Build Coastguard Worker 630*cda5da8dSAndroid Build Coastguard Worker# Lenient date/time comparison function. The precision of the mtime 631*cda5da8dSAndroid Build Coastguard Worker# in the archive is lower than the mtime stored in a .pyc: we 632*cda5da8dSAndroid Build Coastguard Worker# must allow a difference of at most one second. 633*cda5da8dSAndroid Build Coastguard Workerdef _eq_mtime(t1, t2): 634*cda5da8dSAndroid Build Coastguard Worker # dostime only stores even seconds, so be lenient 635*cda5da8dSAndroid Build Coastguard Worker return abs(t1 - t2) <= 1 636*cda5da8dSAndroid Build Coastguard Worker 637*cda5da8dSAndroid Build Coastguard Worker 638*cda5da8dSAndroid Build Coastguard Worker# Given the contents of a .py[co] file, unmarshal the data 639*cda5da8dSAndroid Build Coastguard Worker# and return the code object. Raises ImportError it the magic word doesn't 640*cda5da8dSAndroid Build Coastguard Worker# match, or if the recorded .py[co] metadata does not match the source. 641*cda5da8dSAndroid Build Coastguard Workerdef _unmarshal_code(self, pathname, fullpath, fullname, data): 642*cda5da8dSAndroid Build Coastguard Worker exc_details = { 643*cda5da8dSAndroid Build Coastguard Worker 'name': fullname, 644*cda5da8dSAndroid Build Coastguard Worker 'path': fullpath, 645*cda5da8dSAndroid Build Coastguard Worker } 646*cda5da8dSAndroid Build Coastguard Worker 647*cda5da8dSAndroid Build Coastguard Worker flags = _bootstrap_external._classify_pyc(data, fullname, exc_details) 648*cda5da8dSAndroid Build Coastguard Worker 649*cda5da8dSAndroid Build Coastguard Worker hash_based = flags & 0b1 != 0 650*cda5da8dSAndroid Build Coastguard Worker if hash_based: 651*cda5da8dSAndroid Build Coastguard Worker check_source = flags & 0b10 != 0 652*cda5da8dSAndroid Build Coastguard Worker if (_imp.check_hash_based_pycs != 'never' and 653*cda5da8dSAndroid Build Coastguard Worker (check_source or _imp.check_hash_based_pycs == 'always')): 654*cda5da8dSAndroid Build Coastguard Worker source_bytes = _get_pyc_source(self, fullpath) 655*cda5da8dSAndroid Build Coastguard Worker if source_bytes is not None: 656*cda5da8dSAndroid Build Coastguard Worker source_hash = _imp.source_hash( 657*cda5da8dSAndroid Build Coastguard Worker _bootstrap_external._RAW_MAGIC_NUMBER, 658*cda5da8dSAndroid Build Coastguard Worker source_bytes, 659*cda5da8dSAndroid Build Coastguard Worker ) 660*cda5da8dSAndroid Build Coastguard Worker 661*cda5da8dSAndroid Build Coastguard Worker _bootstrap_external._validate_hash_pyc( 662*cda5da8dSAndroid Build Coastguard Worker data, source_hash, fullname, exc_details) 663*cda5da8dSAndroid Build Coastguard Worker else: 664*cda5da8dSAndroid Build Coastguard Worker source_mtime, source_size = \ 665*cda5da8dSAndroid Build Coastguard Worker _get_mtime_and_size_of_source(self, fullpath) 666*cda5da8dSAndroid Build Coastguard Worker 667*cda5da8dSAndroid Build Coastguard Worker if source_mtime: 668*cda5da8dSAndroid Build Coastguard Worker # We don't use _bootstrap_external._validate_timestamp_pyc 669*cda5da8dSAndroid Build Coastguard Worker # to allow for a more lenient timestamp check. 670*cda5da8dSAndroid Build Coastguard Worker if (not _eq_mtime(_unpack_uint32(data[8:12]), source_mtime) or 671*cda5da8dSAndroid Build Coastguard Worker _unpack_uint32(data[12:16]) != source_size): 672*cda5da8dSAndroid Build Coastguard Worker _bootstrap._verbose_message( 673*cda5da8dSAndroid Build Coastguard Worker f'bytecode is stale for {fullname!r}') 674*cda5da8dSAndroid Build Coastguard Worker return None 675*cda5da8dSAndroid Build Coastguard Worker 676*cda5da8dSAndroid Build Coastguard Worker code = marshal.loads(data[16:]) 677*cda5da8dSAndroid Build Coastguard Worker if not isinstance(code, _code_type): 678*cda5da8dSAndroid Build Coastguard Worker raise TypeError(f'compiled module {pathname!r} is not a code object') 679*cda5da8dSAndroid Build Coastguard Worker return code 680*cda5da8dSAndroid Build Coastguard Worker 681*cda5da8dSAndroid Build Coastguard Worker_code_type = type(_unmarshal_code.__code__) 682*cda5da8dSAndroid Build Coastguard Worker 683*cda5da8dSAndroid Build Coastguard Worker 684*cda5da8dSAndroid Build Coastguard Worker# Replace any occurrences of '\r\n?' in the input string with '\n'. 685*cda5da8dSAndroid Build Coastguard Worker# This converts DOS and Mac line endings to Unix line endings. 686*cda5da8dSAndroid Build Coastguard Workerdef _normalize_line_endings(source): 687*cda5da8dSAndroid Build Coastguard Worker source = source.replace(b'\r\n', b'\n') 688*cda5da8dSAndroid Build Coastguard Worker source = source.replace(b'\r', b'\n') 689*cda5da8dSAndroid Build Coastguard Worker return source 690*cda5da8dSAndroid Build Coastguard Worker 691*cda5da8dSAndroid Build Coastguard Worker# Given a string buffer containing Python source code, compile it 692*cda5da8dSAndroid Build Coastguard Worker# and return a code object. 693*cda5da8dSAndroid Build Coastguard Workerdef _compile_source(pathname, source): 694*cda5da8dSAndroid Build Coastguard Worker source = _normalize_line_endings(source) 695*cda5da8dSAndroid Build Coastguard Worker return compile(source, pathname, 'exec', dont_inherit=True) 696*cda5da8dSAndroid Build Coastguard Worker 697*cda5da8dSAndroid Build Coastguard Worker# Convert the date/time values found in the Zip archive to a value 698*cda5da8dSAndroid Build Coastguard Worker# that's compatible with the time stamp stored in .pyc files. 699*cda5da8dSAndroid Build Coastguard Workerdef _parse_dostime(d, t): 700*cda5da8dSAndroid Build Coastguard Worker return time.mktime(( 701*cda5da8dSAndroid Build Coastguard Worker (d >> 9) + 1980, # bits 9..15: year 702*cda5da8dSAndroid Build Coastguard Worker (d >> 5) & 0xF, # bits 5..8: month 703*cda5da8dSAndroid Build Coastguard Worker d & 0x1F, # bits 0..4: day 704*cda5da8dSAndroid Build Coastguard Worker t >> 11, # bits 11..15: hours 705*cda5da8dSAndroid Build Coastguard Worker (t >> 5) & 0x3F, # bits 8..10: minutes 706*cda5da8dSAndroid Build Coastguard Worker (t & 0x1F) * 2, # bits 0..7: seconds / 2 707*cda5da8dSAndroid Build Coastguard Worker -1, -1, -1)) 708*cda5da8dSAndroid Build Coastguard Worker 709*cda5da8dSAndroid Build Coastguard Worker# Given a path to a .pyc file in the archive, return the 710*cda5da8dSAndroid Build Coastguard Worker# modification time of the matching .py file and its size, 711*cda5da8dSAndroid Build Coastguard Worker# or (0, 0) if no source is available. 712*cda5da8dSAndroid Build Coastguard Workerdef _get_mtime_and_size_of_source(self, path): 713*cda5da8dSAndroid Build Coastguard Worker try: 714*cda5da8dSAndroid Build Coastguard Worker # strip 'c' or 'o' from *.py[co] 715*cda5da8dSAndroid Build Coastguard Worker assert path[-1:] in ('c', 'o') 716*cda5da8dSAndroid Build Coastguard Worker path = path[:-1] 717*cda5da8dSAndroid Build Coastguard Worker toc_entry = self._files[path] 718*cda5da8dSAndroid Build Coastguard Worker # fetch the time stamp of the .py file for comparison 719*cda5da8dSAndroid Build Coastguard Worker # with an embedded pyc time stamp 720*cda5da8dSAndroid Build Coastguard Worker time = toc_entry[5] 721*cda5da8dSAndroid Build Coastguard Worker date = toc_entry[6] 722*cda5da8dSAndroid Build Coastguard Worker uncompressed_size = toc_entry[3] 723*cda5da8dSAndroid Build Coastguard Worker return _parse_dostime(date, time), uncompressed_size 724*cda5da8dSAndroid Build Coastguard Worker except (KeyError, IndexError, TypeError): 725*cda5da8dSAndroid Build Coastguard Worker return 0, 0 726*cda5da8dSAndroid Build Coastguard Worker 727*cda5da8dSAndroid Build Coastguard Worker 728*cda5da8dSAndroid Build Coastguard Worker# Given a path to a .pyc file in the archive, return the 729*cda5da8dSAndroid Build Coastguard Worker# contents of the matching .py file, or None if no source 730*cda5da8dSAndroid Build Coastguard Worker# is available. 731*cda5da8dSAndroid Build Coastguard Workerdef _get_pyc_source(self, path): 732*cda5da8dSAndroid Build Coastguard Worker # strip 'c' or 'o' from *.py[co] 733*cda5da8dSAndroid Build Coastguard Worker assert path[-1:] in ('c', 'o') 734*cda5da8dSAndroid Build Coastguard Worker path = path[:-1] 735*cda5da8dSAndroid Build Coastguard Worker 736*cda5da8dSAndroid Build Coastguard Worker try: 737*cda5da8dSAndroid Build Coastguard Worker toc_entry = self._files[path] 738*cda5da8dSAndroid Build Coastguard Worker except KeyError: 739*cda5da8dSAndroid Build Coastguard Worker return None 740*cda5da8dSAndroid Build Coastguard Worker else: 741*cda5da8dSAndroid Build Coastguard Worker return _get_data(self.archive, toc_entry) 742*cda5da8dSAndroid Build Coastguard Worker 743*cda5da8dSAndroid Build Coastguard Worker 744*cda5da8dSAndroid Build Coastguard Worker# Get the code object associated with the module specified by 745*cda5da8dSAndroid Build Coastguard Worker# 'fullname'. 746*cda5da8dSAndroid Build Coastguard Workerdef _get_module_code(self, fullname): 747*cda5da8dSAndroid Build Coastguard Worker path = _get_module_path(self, fullname) 748*cda5da8dSAndroid Build Coastguard Worker import_error = None 749*cda5da8dSAndroid Build Coastguard Worker for suffix, isbytecode, ispackage in _zip_searchorder: 750*cda5da8dSAndroid Build Coastguard Worker fullpath = path + suffix 751*cda5da8dSAndroid Build Coastguard Worker _bootstrap._verbose_message('trying {}{}{}', self.archive, path_sep, fullpath, verbosity=2) 752*cda5da8dSAndroid Build Coastguard Worker try: 753*cda5da8dSAndroid Build Coastguard Worker toc_entry = self._files[fullpath] 754*cda5da8dSAndroid Build Coastguard Worker except KeyError: 755*cda5da8dSAndroid Build Coastguard Worker pass 756*cda5da8dSAndroid Build Coastguard Worker else: 757*cda5da8dSAndroid Build Coastguard Worker modpath = toc_entry[0] 758*cda5da8dSAndroid Build Coastguard Worker data = _get_data(self.archive, toc_entry) 759*cda5da8dSAndroid Build Coastguard Worker code = None 760*cda5da8dSAndroid Build Coastguard Worker if isbytecode: 761*cda5da8dSAndroid Build Coastguard Worker try: 762*cda5da8dSAndroid Build Coastguard Worker code = _unmarshal_code(self, modpath, fullpath, fullname, data) 763*cda5da8dSAndroid Build Coastguard Worker except ImportError as exc: 764*cda5da8dSAndroid Build Coastguard Worker import_error = exc 765*cda5da8dSAndroid Build Coastguard Worker else: 766*cda5da8dSAndroid Build Coastguard Worker code = _compile_source(modpath, data) 767*cda5da8dSAndroid Build Coastguard Worker if code is None: 768*cda5da8dSAndroid Build Coastguard Worker # bad magic number or non-matching mtime 769*cda5da8dSAndroid Build Coastguard Worker # in byte code, try next 770*cda5da8dSAndroid Build Coastguard Worker continue 771*cda5da8dSAndroid Build Coastguard Worker modpath = toc_entry[0] 772*cda5da8dSAndroid Build Coastguard Worker return code, ispackage, modpath 773*cda5da8dSAndroid Build Coastguard Worker else: 774*cda5da8dSAndroid Build Coastguard Worker if import_error: 775*cda5da8dSAndroid Build Coastguard Worker msg = f"module load failed: {import_error}" 776*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(msg, name=fullname) from import_error 777*cda5da8dSAndroid Build Coastguard Worker else: 778*cda5da8dSAndroid Build Coastguard Worker raise ZipImportError(f"can't find module {fullname!r}", name=fullname) 779