xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/zipimport.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
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