Update prebuilt Clang to r416183b from Android.

https://android.googlesource.com/platform/prebuilts/clang/host/
linux-x86/+/06a71ddac05c22edb2d10b590e1769b3f8619bef

clang 12.0.5 (based on r416183b) from build 7284624.

Change-Id: I277a316abcf47307562d8b748b84870f31a72866
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/linux-x64/clang/python3/lib/python3.9/zipimport.py b/linux-x64/clang/python3/lib/python3.9/zipimport.py
new file mode 100644
index 0000000..5ef0a17
--- /dev/null
+++ b/linux-x64/clang/python3/lib/python3.9/zipimport.py
@@ -0,0 +1,792 @@
+"""zipimport provides support for importing Python modules from Zip archives.
+
+This module exports three objects:
+- zipimporter: a class; its constructor takes a path to a Zip archive.
+- ZipImportError: exception raised by zipimporter objects. It's a
+  subclass of ImportError, so it can be caught as ImportError, too.
+- _zip_directory_cache: a dict, mapping archive paths to zip directory
+  info dicts, as used in zipimporter._files.
+
+It is usually not needed to use the zipimport module explicitly; it is
+used by the builtin import mechanism for sys.path items that are paths
+to Zip archives.
+"""
+
+#from importlib import _bootstrap_external
+#from importlib import _bootstrap  # for _verbose_message
+import _frozen_importlib_external as _bootstrap_external
+from _frozen_importlib_external import _unpack_uint16, _unpack_uint32
+import _frozen_importlib as _bootstrap  # for _verbose_message
+import _imp  # for check_hash_based_pycs
+import _io  # for open
+import marshal  # for loads
+import sys  # for modules
+import time  # for mktime
+
+__all__ = ['ZipImportError', 'zipimporter']
+
+
+path_sep = _bootstrap_external.path_sep
+alt_path_sep = _bootstrap_external.path_separators[1:]
+
+
+class ZipImportError(ImportError):
+    pass
+
+# _read_directory() cache
+_zip_directory_cache = {}
+
+_module_type = type(sys)
+
+END_CENTRAL_DIR_SIZE = 22
+STRING_END_ARCHIVE = b'PK\x05\x06'
+MAX_COMMENT_LEN = (1 << 16) - 1
+
+class zipimporter:
+    """zipimporter(archivepath) -> zipimporter object
+
+    Create a new zipimporter instance. 'archivepath' must be a path to
+    a zipfile, or to a specific path inside a zipfile. For example, it can be
+    '/tmp/myimport.zip', or '/tmp/myimport.zip/mydirectory', if mydirectory is a
+    valid directory inside the archive.
+
+    'ZipImportError is raised if 'archivepath' doesn't point to a valid Zip
+    archive.
+
+    The 'archive' attribute of zipimporter objects contains the name of the
+    zipfile targeted.
+    """
+
+    # Split the "subdirectory" from the Zip archive path, lookup a matching
+    # entry in sys.path_importer_cache, fetch the file directory from there
+    # if found, or else read it from the archive.
+    def __init__(self, path):
+        if not isinstance(path, str):
+            import os
+            path = os.fsdecode(path)
+        if not path:
+            raise ZipImportError('archive path is empty', path=path)
+        if alt_path_sep:
+            path = path.replace(alt_path_sep, path_sep)
+
+        prefix = []
+        while True:
+            try:
+                st = _bootstrap_external._path_stat(path)
+            except (OSError, ValueError):
+                # On Windows a ValueError is raised for too long paths.
+                # Back up one path element.
+                dirname, basename = _bootstrap_external._path_split(path)
+                if dirname == path:
+                    raise ZipImportError('not a Zip file', path=path)
+                path = dirname
+                prefix.append(basename)
+            else:
+                # it exists
+                if (st.st_mode & 0o170000) != 0o100000:  # stat.S_ISREG
+                    # it's a not file
+                    raise ZipImportError('not a Zip file', path=path)
+                break
+
+        try:
+            files = _zip_directory_cache[path]
+        except KeyError:
+            files = _read_directory(path)
+            _zip_directory_cache[path] = files
+        self._files = files
+        self.archive = path
+        # a prefix directory following the ZIP file path.
+        self.prefix = _bootstrap_external._path_join(*prefix[::-1])
+        if self.prefix:
+            self.prefix += path_sep
+
+
+    # Check whether we can satisfy the import of the module named by
+    # 'fullname', or whether it could be a portion of a namespace
+    # package. Return self if we can load it, a string containing the
+    # full path if it's a possible namespace portion, None if we
+    # can't load it.
+    def find_loader(self, fullname, path=None):
+        """find_loader(fullname, path=None) -> self, str or None.
+
+        Search for a module specified by 'fullname'. 'fullname' must be the
+        fully qualified (dotted) module name. It returns the zipimporter
+        instance itself if the module was found, a string containing the
+        full path name if it's possibly a portion of a namespace package,
+        or None otherwise. The optional 'path' argument is ignored -- it's
+        there for compatibility with the importer protocol.
+        """
+        mi = _get_module_info(self, fullname)
+        if mi is not None:
+            # This is a module or package.
+            return self, []
+
+        # Not a module or regular package. See if this is a directory, and
+        # therefore possibly a portion of a namespace package.
+
+        # We're only interested in the last path component of fullname
+        # earlier components are recorded in self.prefix.
+        modpath = _get_module_path(self, fullname)
+        if _is_dir(self, modpath):
+            # This is possibly a portion of a namespace
+            # package. Return the string representing its path,
+            # without a trailing separator.
+            return None, [f'{self.archive}{path_sep}{modpath}']
+
+        return None, []
+
+
+    # Check whether we can satisfy the import of the module named by
+    # 'fullname'. Return self if we can, None if we can't.
+    def find_module(self, fullname, path=None):
+        """find_module(fullname, path=None) -> self or None.
+
+        Search for a module specified by 'fullname'. 'fullname' must be the
+        fully qualified (dotted) module name. It returns the zipimporter
+        instance itself if the module was found, or None if it wasn't.
+        The optional 'path' argument is ignored -- it's there for compatibility
+        with the importer protocol.
+        """
+        return self.find_loader(fullname, path)[0]
+
+
+    def get_code(self, fullname):
+        """get_code(fullname) -> code object.
+
+        Return the code object for the specified module. Raise ZipImportError
+        if the module couldn't be found.
+        """
+        code, ispackage, modpath = _get_module_code(self, fullname)
+        return code
+
+
+    def get_data(self, pathname):
+        """get_data(pathname) -> string with file data.
+
+        Return the data associated with 'pathname'. Raise OSError if
+        the file wasn't found.
+        """
+        if alt_path_sep:
+            pathname = pathname.replace(alt_path_sep, path_sep)
+
+        key = pathname
+        if pathname.startswith(self.archive + path_sep):
+            key = pathname[len(self.archive + path_sep):]
+
+        try:
+            toc_entry = self._files[key]
+        except KeyError:
+            raise OSError(0, '', key)
+        return _get_data(self.archive, toc_entry)
+
+
+    # Return a string matching __file__ for the named module
+    def get_filename(self, fullname):
+        """get_filename(fullname) -> filename string.
+
+        Return the filename for the specified module.
+        """
+        # Deciding the filename requires working out where the code
+        # would come from if the module was actually loaded
+        code, ispackage, modpath = _get_module_code(self, fullname)
+        return modpath
+
+
+    def get_source(self, fullname):
+        """get_source(fullname) -> source string.
+
+        Return the source code for the specified module. Raise ZipImportError
+        if the module couldn't be found, return None if the archive does
+        contain the module, but has no source for it.
+        """
+        mi = _get_module_info(self, fullname)
+        if mi is None:
+            raise ZipImportError(f"can't find module {fullname!r}", name=fullname)
+
+        path = _get_module_path(self, fullname)
+        if mi:
+            fullpath = _bootstrap_external._path_join(path, '__init__.py')
+        else:
+            fullpath = f'{path}.py'
+
+        try:
+            toc_entry = self._files[fullpath]
+        except KeyError:
+            # we have the module, but no source
+            return None
+        return _get_data(self.archive, toc_entry).decode()
+
+
+    # Return a bool signifying whether the module is a package or not.
+    def is_package(self, fullname):
+        """is_package(fullname) -> bool.
+
+        Return True if the module specified by fullname is a package.
+        Raise ZipImportError if the module couldn't be found.
+        """
+        mi = _get_module_info(self, fullname)
+        if mi is None:
+            raise ZipImportError(f"can't find module {fullname!r}", name=fullname)
+        return mi
+
+
+    # Load and return the module named by 'fullname'.
+    def load_module(self, fullname):
+        """load_module(fullname) -> module.
+
+        Load the module specified by 'fullname'. 'fullname' must be the
+        fully qualified (dotted) module name. It returns the imported
+        module, or raises ZipImportError if it wasn't found.
+        """
+        code, ispackage, modpath = _get_module_code(self, fullname)
+        mod = sys.modules.get(fullname)
+        if mod is None or not isinstance(mod, _module_type):
+            mod = _module_type(fullname)
+            sys.modules[fullname] = mod
+        mod.__loader__ = self
+
+        try:
+            if ispackage:
+                # add __path__ to the module *before* the code gets
+                # executed
+                path = _get_module_path(self, fullname)
+                fullpath = _bootstrap_external._path_join(self.archive, path)
+                mod.__path__ = [fullpath]
+
+            if not hasattr(mod, '__builtins__'):
+                mod.__builtins__ = __builtins__
+            _bootstrap_external._fix_up_module(mod.__dict__, fullname, modpath)
+            exec(code, mod.__dict__)
+        except:
+            del sys.modules[fullname]
+            raise
+
+        try:
+            mod = sys.modules[fullname]
+        except KeyError:
+            raise ImportError(f'Loaded module {fullname!r} not found in sys.modules')
+        _bootstrap._verbose_message('import {} # loaded from Zip {}', fullname, modpath)
+        return mod
+
+
+    def get_resource_reader(self, fullname):
+        """Return the ResourceReader for a package in a zip file.
+
+        If 'fullname' is a package within the zip file, return the
+        'ResourceReader' object for the package.  Otherwise return None.
+        """
+        try:
+            if not self.is_package(fullname):
+                return None
+        except ZipImportError:
+            return None
+        if not _ZipImportResourceReader._registered:
+            from importlib.abc import ResourceReader
+            ResourceReader.register(_ZipImportResourceReader)
+            _ZipImportResourceReader._registered = True
+        return _ZipImportResourceReader(self, fullname)
+
+
+    def __repr__(self):
+        return f'<zipimporter object "{self.archive}{path_sep}{self.prefix}">'
+
+
+# _zip_searchorder defines how we search for a module in the Zip
+# archive: we first search for a package __init__, then for
+# non-package .pyc, and .py entries. The .pyc entries
+# are swapped by initzipimport() if we run in optimized mode. Also,
+# '/' is replaced by path_sep there.
+_zip_searchorder = (
+    (path_sep + '__init__.pyc', True, True),
+    (path_sep + '__init__.py', False, True),
+    ('.pyc', True, False),
+    ('.py', False, False),
+)
+
+# Given a module name, return the potential file path in the
+# archive (without extension).
+def _get_module_path(self, fullname):
+    return self.prefix + fullname.rpartition('.')[2]
+
+# Does this path represent a directory?
+def _is_dir(self, path):
+    # See if this is a "directory". If so, it's eligible to be part
+    # of a namespace package. We test by seeing if the name, with an
+    # appended path separator, exists.
+    dirpath = path + path_sep
+    # If dirpath is present in self._files, we have a directory.
+    return dirpath in self._files
+
+# Return some information about a module.
+def _get_module_info(self, fullname):
+    path = _get_module_path(self, fullname)
+    for suffix, isbytecode, ispackage in _zip_searchorder:
+        fullpath = path + suffix
+        if fullpath in self._files:
+            return ispackage
+    return None
+
+
+# implementation
+
+# _read_directory(archive) -> files dict (new reference)
+#
+# Given a path to a Zip archive, build a dict, mapping file names
+# (local to the archive, using SEP as a separator) to toc entries.
+#
+# A toc_entry is a tuple:
+#
+# (__file__,        # value to use for __file__, available for all files,
+#                   # encoded to the filesystem encoding
+#  compress,        # compression kind; 0 for uncompressed
+#  data_size,       # size of compressed data on disk
+#  file_size,       # size of decompressed data
+#  file_offset,     # offset of file header from start of archive
+#  time,            # mod time of file (in dos format)
+#  date,            # mod data of file (in dos format)
+#  crc,             # crc checksum of the data
+# )
+#
+# Directories can be recognized by the trailing path_sep in the name,
+# data_size and file_offset are 0.
+def _read_directory(archive):
+    try:
+        fp = _io.open_code(archive)
+    except OSError:
+        raise ZipImportError(f"can't open Zip file: {archive!r}", path=archive)
+
+    with fp:
+        try:
+            fp.seek(-END_CENTRAL_DIR_SIZE, 2)
+            header_position = fp.tell()
+            buffer = fp.read(END_CENTRAL_DIR_SIZE)
+        except OSError:
+            raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive)
+        if len(buffer) != END_CENTRAL_DIR_SIZE:
+            raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive)
+        if buffer[:4] != STRING_END_ARCHIVE:
+            # Bad: End of Central Dir signature
+            # Check if there's a comment.
+            try:
+                fp.seek(0, 2)
+                file_size = fp.tell()
+            except OSError:
+                raise ZipImportError(f"can't read Zip file: {archive!r}",
+                                     path=archive)
+            max_comment_start = max(file_size - MAX_COMMENT_LEN -
+                                    END_CENTRAL_DIR_SIZE, 0)
+            try:
+                fp.seek(max_comment_start)
+                data = fp.read()
+            except OSError:
+                raise ZipImportError(f"can't read Zip file: {archive!r}",
+                                     path=archive)
+            pos = data.rfind(STRING_END_ARCHIVE)
+            if pos < 0:
+                raise ZipImportError(f'not a Zip file: {archive!r}',
+                                     path=archive)
+            buffer = data[pos:pos+END_CENTRAL_DIR_SIZE]
+            if len(buffer) != END_CENTRAL_DIR_SIZE:
+                raise ZipImportError(f"corrupt Zip file: {archive!r}",
+                                     path=archive)
+            header_position = file_size - len(data) + pos
+
+        header_size = _unpack_uint32(buffer[12:16])
+        header_offset = _unpack_uint32(buffer[16:20])
+        if header_position < header_size:
+            raise ZipImportError(f'bad central directory size: {archive!r}', path=archive)
+        if header_position < header_offset:
+            raise ZipImportError(f'bad central directory offset: {archive!r}', path=archive)
+        header_position -= header_size
+        arc_offset = header_position - header_offset
+        if arc_offset < 0:
+            raise ZipImportError(f'bad central directory size or offset: {archive!r}', path=archive)
+
+        files = {}
+        # Start of Central Directory
+        count = 0
+        try:
+            fp.seek(header_position)
+        except OSError:
+            raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive)
+        while True:
+            buffer = fp.read(46)
+            if len(buffer) < 4:
+                raise EOFError('EOF read where not expected')
+            # Start of file header
+            if buffer[:4] != b'PK\x01\x02':
+                break                                # Bad: Central Dir File Header
+            if len(buffer) != 46:
+                raise EOFError('EOF read where not expected')
+            flags = _unpack_uint16(buffer[8:10])
+            compress = _unpack_uint16(buffer[10:12])
+            time = _unpack_uint16(buffer[12:14])
+            date = _unpack_uint16(buffer[14:16])
+            crc = _unpack_uint32(buffer[16:20])
+            data_size = _unpack_uint32(buffer[20:24])
+            file_size = _unpack_uint32(buffer[24:28])
+            name_size = _unpack_uint16(buffer[28:30])
+            extra_size = _unpack_uint16(buffer[30:32])
+            comment_size = _unpack_uint16(buffer[32:34])
+            file_offset = _unpack_uint32(buffer[42:46])
+            header_size = name_size + extra_size + comment_size
+            if file_offset > header_offset:
+                raise ZipImportError(f'bad local header offset: {archive!r}', path=archive)
+            file_offset += arc_offset
+
+            try:
+                name = fp.read(name_size)
+            except OSError:
+                raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive)
+            if len(name) != name_size:
+                raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive)
+            # On Windows, calling fseek to skip over the fields we don't use is
+            # slower than reading the data because fseek flushes stdio's
+            # internal buffers.    See issue #8745.
+            try:
+                if len(fp.read(header_size - name_size)) != header_size - name_size:
+                    raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive)
+            except OSError:
+                raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive)
+
+            if flags & 0x800:
+                # UTF-8 file names extension
+                name = name.decode()
+            else:
+                # Historical ZIP filename encoding
+                try:
+                    name = name.decode('ascii')
+                except UnicodeDecodeError:
+                    name = name.decode('latin1').translate(cp437_table)
+
+            name = name.replace('/', path_sep)
+            path = _bootstrap_external._path_join(archive, name)
+            t = (path, compress, data_size, file_size, file_offset, time, date, crc)
+            files[name] = t
+            count += 1
+    _bootstrap._verbose_message('zipimport: found {} names in {!r}', count, archive)
+    return files
+
+# During bootstrap, we may need to load the encodings
+# package from a ZIP file. But the cp437 encoding is implemented
+# in Python in the encodings package.
+#
+# Break out of this dependency by using the translation table for
+# the cp437 encoding.
+cp437_table = (
+    # ASCII part, 8 rows x 16 chars
+    '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
+    '\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f'
+    ' !"#$%&\'()*+,-./'
+    '0123456789:;<=>?'
+    '@ABCDEFGHIJKLMNO'
+    'PQRSTUVWXYZ[\\]^_'
+    '`abcdefghijklmno'
+    'pqrstuvwxyz{|}~\x7f'
+    # non-ASCII part, 16 rows x 8 chars
+    '\xc7\xfc\xe9\xe2\xe4\xe0\xe5\xe7'
+    '\xea\xeb\xe8\xef\xee\xec\xc4\xc5'
+    '\xc9\xe6\xc6\xf4\xf6\xf2\xfb\xf9'
+    '\xff\xd6\xdc\xa2\xa3\xa5\u20a7\u0192'
+    '\xe1\xed\xf3\xfa\xf1\xd1\xaa\xba'
+    '\xbf\u2310\xac\xbd\xbc\xa1\xab\xbb'
+    '\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556'
+    '\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510'
+    '\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f'
+    '\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567'
+    '\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b'
+    '\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580'
+    '\u03b1\xdf\u0393\u03c0\u03a3\u03c3\xb5\u03c4'
+    '\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229'
+    '\u2261\xb1\u2265\u2264\u2320\u2321\xf7\u2248'
+    '\xb0\u2219\xb7\u221a\u207f\xb2\u25a0\xa0'
+)
+
+_importing_zlib = False
+
+# Return the zlib.decompress function object, or NULL if zlib couldn't
+# be imported. The function is cached when found, so subsequent calls
+# don't import zlib again.
+def _get_decompress_func():
+    global _importing_zlib
+    if _importing_zlib:
+        # Someone has a zlib.py[co] in their Zip file
+        # let's avoid a stack overflow.
+        _bootstrap._verbose_message('zipimport: zlib UNAVAILABLE')
+        raise ZipImportError("can't decompress data; zlib not available")
+
+    _importing_zlib = True
+    try:
+        from zlib import decompress
+    except Exception:
+        _bootstrap._verbose_message('zipimport: zlib UNAVAILABLE')
+        raise ZipImportError("can't decompress data; zlib not available")
+    finally:
+        _importing_zlib = False
+
+    _bootstrap._verbose_message('zipimport: zlib available')
+    return decompress
+
+# Given a path to a Zip file and a toc_entry, return the (uncompressed) data.
+def _get_data(archive, toc_entry):
+    datapath, compress, data_size, file_size, file_offset, time, date, crc = toc_entry
+    if data_size < 0:
+        raise ZipImportError('negative data size')
+
+    with _io.open_code(archive) as fp:
+        # Check to make sure the local file header is correct
+        try:
+            fp.seek(file_offset)
+        except OSError:
+            raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive)
+        buffer = fp.read(30)
+        if len(buffer) != 30:
+            raise EOFError('EOF read where not expected')
+
+        if buffer[:4] != b'PK\x03\x04':
+            # Bad: Local File Header
+            raise ZipImportError(f'bad local file header: {archive!r}', path=archive)
+
+        name_size = _unpack_uint16(buffer[26:28])
+        extra_size = _unpack_uint16(buffer[28:30])
+        header_size = 30 + name_size + extra_size
+        file_offset += header_size  # Start of file data
+        try:
+            fp.seek(file_offset)
+        except OSError:
+            raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive)
+        raw_data = fp.read(data_size)
+        if len(raw_data) != data_size:
+            raise OSError("zipimport: can't read data")
+
+    if compress == 0:
+        # data is not compressed
+        return raw_data
+
+    # Decompress with zlib
+    try:
+        decompress = _get_decompress_func()
+    except Exception:
+        raise ZipImportError("can't decompress data; zlib not available")
+    return decompress(raw_data, -15)
+
+
+# Lenient date/time comparison function. The precision of the mtime
+# in the archive is lower than the mtime stored in a .pyc: we
+# must allow a difference of at most one second.
+def _eq_mtime(t1, t2):
+    # dostime only stores even seconds, so be lenient
+    return abs(t1 - t2) <= 1
+
+
+# Given the contents of a .py[co] file, unmarshal the data
+# and return the code object. Return None if it the magic word doesn't
+# match, or if the recorded .py[co] metadata does not match the source,
+# (we do this instead of raising an exception as we fall back
+# to .py if available and we don't want to mask other errors).
+def _unmarshal_code(self, pathname, fullpath, fullname, data):
+    exc_details = {
+        'name': fullname,
+        'path': fullpath,
+    }
+
+    try:
+        flags = _bootstrap_external._classify_pyc(data, fullname, exc_details)
+    except ImportError:
+        return None
+
+    hash_based = flags & 0b1 != 0
+    if hash_based:
+        check_source = flags & 0b10 != 0
+        if (_imp.check_hash_based_pycs != 'never' and
+                (check_source or _imp.check_hash_based_pycs == 'always')):
+            source_bytes = _get_pyc_source(self, fullpath)
+            if source_bytes is not None:
+                source_hash = _imp.source_hash(
+                    _bootstrap_external._RAW_MAGIC_NUMBER,
+                    source_bytes,
+                )
+
+                try:
+                    _bootstrap_external._validate_hash_pyc(
+                        data, source_hash, fullname, exc_details)
+                except ImportError:
+                    return None
+    else:
+        source_mtime, source_size = \
+            _get_mtime_and_size_of_source(self, fullpath)
+
+        if source_mtime:
+            # We don't use _bootstrap_external._validate_timestamp_pyc
+            # to allow for a more lenient timestamp check.
+            if (not _eq_mtime(_unpack_uint32(data[8:12]), source_mtime) or
+                    _unpack_uint32(data[12:16]) != source_size):
+                _bootstrap._verbose_message(
+                    f'bytecode is stale for {fullname!r}')
+                return None
+
+    code = marshal.loads(data[16:])
+    if not isinstance(code, _code_type):
+        raise TypeError(f'compiled module {pathname!r} is not a code object')
+    return code
+
+_code_type = type(_unmarshal_code.__code__)
+
+
+# Replace any occurrences of '\r\n?' in the input string with '\n'.
+# This converts DOS and Mac line endings to Unix line endings.
+def _normalize_line_endings(source):
+    source = source.replace(b'\r\n', b'\n')
+    source = source.replace(b'\r', b'\n')
+    return source
+
+# Given a string buffer containing Python source code, compile it
+# and return a code object.
+def _compile_source(pathname, source):
+    source = _normalize_line_endings(source)
+    return compile(source, pathname, 'exec', dont_inherit=True)
+
+# Convert the date/time values found in the Zip archive to a value
+# that's compatible with the time stamp stored in .pyc files.
+def _parse_dostime(d, t):
+    return time.mktime((
+        (d >> 9) + 1980,    # bits 9..15: year
+        (d >> 5) & 0xF,     # bits 5..8: month
+        d & 0x1F,           # bits 0..4: day
+        t >> 11,            # bits 11..15: hours
+        (t >> 5) & 0x3F,    # bits 8..10: minutes
+        (t & 0x1F) * 2,     # bits 0..7: seconds / 2
+        -1, -1, -1))
+
+# Given a path to a .pyc file in the archive, return the
+# modification time of the matching .py file and its size,
+# or (0, 0) if no source is available.
+def _get_mtime_and_size_of_source(self, path):
+    try:
+        # strip 'c' or 'o' from *.py[co]
+        assert path[-1:] in ('c', 'o')
+        path = path[:-1]
+        toc_entry = self._files[path]
+        # fetch the time stamp of the .py file for comparison
+        # with an embedded pyc time stamp
+        time = toc_entry[5]
+        date = toc_entry[6]
+        uncompressed_size = toc_entry[3]
+        return _parse_dostime(date, time), uncompressed_size
+    except (KeyError, IndexError, TypeError):
+        return 0, 0
+
+
+# Given a path to a .pyc file in the archive, return the
+# contents of the matching .py file, or None if no source
+# is available.
+def _get_pyc_source(self, path):
+    # strip 'c' or 'o' from *.py[co]
+    assert path[-1:] in ('c', 'o')
+    path = path[:-1]
+
+    try:
+        toc_entry = self._files[path]
+    except KeyError:
+        return None
+    else:
+        return _get_data(self.archive, toc_entry)
+
+
+# Get the code object associated with the module specified by
+# 'fullname'.
+def _get_module_code(self, fullname):
+    path = _get_module_path(self, fullname)
+    for suffix, isbytecode, ispackage in _zip_searchorder:
+        fullpath = path + suffix
+        _bootstrap._verbose_message('trying {}{}{}', self.archive, path_sep, fullpath, verbosity=2)
+        try:
+            toc_entry = self._files[fullpath]
+        except KeyError:
+            pass
+        else:
+            modpath = toc_entry[0]
+            data = _get_data(self.archive, toc_entry)
+            if isbytecode:
+                code = _unmarshal_code(self, modpath, fullpath, fullname, data)
+            else:
+                code = _compile_source(modpath, data)
+            if code is None:
+                # bad magic number or non-matching mtime
+                # in byte code, try next
+                continue
+            modpath = toc_entry[0]
+            return code, ispackage, modpath
+    else:
+        raise ZipImportError(f"can't find module {fullname!r}", name=fullname)
+
+
+class _ZipImportResourceReader:
+    """Private class used to support ZipImport.get_resource_reader().
+
+    This class is allowed to reference all the innards and private parts of
+    the zipimporter.
+    """
+    _registered = False
+
+    def __init__(self, zipimporter, fullname):
+        self.zipimporter = zipimporter
+        self.fullname = fullname
+
+    def open_resource(self, resource):
+        fullname_as_path = self.fullname.replace('.', '/')
+        path = f'{fullname_as_path}/{resource}'
+        from io import BytesIO
+        try:
+            return BytesIO(self.zipimporter.get_data(path))
+        except OSError:
+            raise FileNotFoundError(path)
+
+    def resource_path(self, resource):
+        # All resources are in the zip file, so there is no path to the file.
+        # Raising FileNotFoundError tells the higher level API to extract the
+        # binary data and create a temporary file.
+        raise FileNotFoundError
+
+    def is_resource(self, name):
+        # Maybe we could do better, but if we can get the data, it's a
+        # resource.  Otherwise it isn't.
+        fullname_as_path = self.fullname.replace('.', '/')
+        path = f'{fullname_as_path}/{name}'
+        try:
+            self.zipimporter.get_data(path)
+        except OSError:
+            return False
+        return True
+
+    def contents(self):
+        # This is a bit convoluted, because fullname will be a module path,
+        # but _files is a list of file names relative to the top of the
+        # archive's namespace.  We want to compare file paths to find all the
+        # names of things inside the module represented by fullname.  So we
+        # turn the module path of fullname into a file path relative to the
+        # top of the archive, and then we iterate through _files looking for
+        # names inside that "directory".
+        from pathlib import Path
+        fullname_path = Path(self.zipimporter.get_filename(self.fullname))
+        relative_path = fullname_path.relative_to(self.zipimporter.archive)
+        # Don't forget that fullname names a package, so its path will include
+        # __init__.py, which we want to ignore.
+        assert relative_path.name == '__init__.py'
+        package_path = relative_path.parent
+        subdirs_seen = set()
+        for filename in self.zipimporter._files:
+            try:
+                relative = Path(filename).relative_to(package_path)
+            except ValueError:
+                continue
+            # If the path of the file (which is relative to the top of the zip
+            # namespace), relative to the package given when the resource
+            # reader was created, has a parent, then it's a name in a
+            # subdirectory and thus we skip it.
+            parent_name = relative.parent.name
+            if len(parent_name) == 0:
+                yield relative.name
+            elif parent_name not in subdirs_seen:
+                subdirs_seen.add(parent_name)
+                yield parent_name