├── LICENSE ├── Python-3.8.2.tgz ├── README.md ├── build-x64.bat ├── build-x86.bat ├── cba ├── cba_zipimport.py ├── cmoduleloader │ ├── include │ │ └── internal │ │ │ └── pycore_pylifecycle.h │ ├── modules │ │ └── _ctypes │ │ │ ├── _ctypes.c │ │ │ ├── callbacks.c │ │ │ ├── cba_moduleloader.c │ │ │ └── cba_moduleloader.h │ └── python │ │ ├── cba_dynload_win.c │ │ ├── cba_importdl.c │ │ ├── cba_importdl.h │ │ ├── cba_importinit.c │ │ ├── cba_moduleloader.c │ │ ├── cba_moduleloader.h │ │ ├── cba_python38_lib.h │ │ ├── cba_python38_pyd_win32.c │ │ ├── cba_python38_pyd_win64.c │ │ ├── clinic │ │ └── import.c.h │ │ ├── frozen.c │ │ ├── import.c │ │ └── pylifecycle.c └── settings │ ├── _ctypes.vcxproj │ ├── _hashlib.vcxproj │ ├── libffi.props │ ├── openssl.props │ ├── python.props │ ├── pythoncore.vcxproj │ └── sqlite3.vcxproj ├── libffi_code └── libffi.zip ├── openssl-1.1.1g.tar.gz ├── scripts ├── untar.py ├── xxd.py └── zip_folder.py ├── zlib-1.2.11.tar.gz └── zlib-patch └── zlibstat.vcxproj /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (C) 2021 SCYTHE, Inc. 3 | 4 | Authors: 5 | Ateeq Sharfuddin 6 | Brian Chapman 7 | Chris Balles 8 | 9 | In-memory Network Loader Authors: 10 | Originally written by Benjamin Dagana (forked from https://github.com/fancycode/MemoryModule). 11 | Updated by Ateeq Sharfuddin to support TLS. 12 | Updated by Jonathan Lim to support AMD64. 13 | Updated by Ateeq Sharfuddin to support in-memory Python embedding. 14 | 15 | (NOTE: cba\cmoduleloader\python\cba_moduleloader.c is also licensed under Mozilla Public License 2.0) 16 | 17 | Based on John Levine's "Loaders and Linkers" (ISBN: 1558604960). 18 | 19 | This software is provided 'as-is', without any express or implied 20 | warranty. In no event will the authors be held liable for any damages 21 | arising from the use of this software. 22 | 23 | Permission is granted to anyone to use this software for any purpose, 24 | including commercial applications, and to alter it and redistribute it 25 | freely, subject to the following restrictions: 26 | 27 | 1. The origin of this software must not be misrepresented; you must not 28 | claim that you wrote the original software. If you use this software 29 | in a product, an acknowledgment in the product documentation would be 30 | appreciated but is not required. 31 | 2. Altered source versions must be plainly marked as such, and must not be 32 | misrepresented as being the original software. 33 | 3. This notice may not be removed or altered from any source distribution. 34 | 35 | 36 | Other software used such as CPython, zlib, OpenSSL, libffi, etc. has its 37 | own license. -------------------------------------------------------------------------------- /Python-3.8.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farfella/in-memory-cpython/cf414bff256561f029553b3018d9609f36992223/Python-3.8.2.tgz -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # An In-memory Embedding of CPython 2 | This repository contains all the build artifacts necessary to build an embedding of CPython 3.8.2 that can be run entirely from memory. 3 | 4 | ## Authors 5 | * Ateeq Sharfuddin 6 | * Brian Chapman 7 | * Chris Balles 8 | 9 | ## Building 10 | * Requires NASM and Strawberry Pearl. 11 | * Originally built using NASM 2.15.05 and Strawberry Pearl 5.30.1.1. 12 | * Read the remarks (REM lines) in build-x64.bat 13 | * Use build-x64.bat to successfully build everything. 14 | 15 | ## Artifacts 16 | * https://doi.org/10.5281/zenodo.4638251 17 | -------------------------------------------------------------------------------- /build-x64.bat: -------------------------------------------------------------------------------- 1 | REM x64 2 | REM Dependencies: NASM for openssl, Perl to run Configure 3 | REM first, extract the tar gz files 4 | REM build zlib, openssl, libffi static libraries 5 | REM generate a zip out of Python's lib folder (so __pycache__ aren't in it) 6 | REM run python's build.bat 7 | REM copy the static libraries into Python's external folder 8 | REM freeze our zipimport.py 9 | REM copy the updated vc project files into Python's PCBuild folder 10 | REM copy the cba_ files into the appropriate directories 11 | REM msbuild Python solution- this generates all the PYDs 12 | REM generate zip of Python's PCBuild\amd64 13 | REM msbuild Pythoncore.dll <- done 14 | REM 15 | 16 | \Python38\python scripts\untar.py zlib-1.2.11.tar.gz 17 | \Python38\python scripts\untar.py openssl-1.1.1g.tar.gz 18 | \Python38\python scripts\untar.py Python-3.8.2.tgz 19 | 20 | copy zlib-patch\zlibstat.vcxproj zlib-1.2.11\contrib\vstudio\vc14 21 | 22 | REM Build zlib static library 23 | REM 24 | pushd zlib-1.2.11\contrib\vstudio\vc14 25 | msbuild zlibstat.vcxproj -p:Configuration=ReleaseWithoutAsm -t:Clean 26 | msbuild zlibstat.vcxproj -p:Configuration=ReleaseWithoutAsm 27 | popd 28 | 29 | REM Build openssl static library 30 | REM 31 | pushd openssl-1.1.1g 32 | set path=%path%;c:\nasm 33 | set path=%path%;C:\Strawberry\perl\bin 34 | perl Configure no-zlib-dynamic no-shared no-zlib VC-WIN64A --with-zlib-include=zlib-1.2.11 --with-zlib-lib=zlib-1.2.11\contrib\vstudio\vc14\x64\ZlibStatReleaseWithoutAsm\zlibstat.lib -DOPENSSL_USE_NODELETE 35 | nmake clean 36 | nmake 37 | popd 38 | 39 | REM for win32 use VC-WIN32 instead of VC-WIN64A above. 40 | 41 | REM ffi 42 | pushd libffi\msvc_build\amd64 43 | msbuild Ffi_staticLib.vcxproj -p:Configuration=Release -t:Clean 44 | msbuild Ffi_staticLib.vcxproj -p:Configuration=Release 45 | popd 46 | 47 | REM do this before running build.bat as it produces __pycache__ 48 | xcopy /S /Y Python-3.8.2\Lib scripts\generated\Lib 49 | \Python38\python.exe scripts\zip_folder.py scripts\generated\Lib scripts\generated\python382_lib.zip 50 | \Python38\python scripts\xxd.py python38_lib scripts\generated\python382_lib.zip > Python-3.8.2\Python\cba_python38_lib.c 51 | 52 | REM call to get externs that we will update 53 | pushd Python-3.8.2\PCbuild 54 | call build.bat 55 | popd 56 | 57 | mkdir Python-3.8.2\externals\openssl-bin-1.1.1g 58 | mkdir Python-3.8.2\externals\openssl-bin-1.1.1g\amd64 59 | mkdir Python-3.8.2\externals\openssl-bin-1.1.1g\amd64\include 60 | mkdir Python-3.8.2\externals\openssl-bin-1.1.1g\amd64\include\openssl 61 | copy openssl-1.1.1g\libcrypto.lib Python-3.8.2\externals\openssl-bin-1.1.1g\amd64 62 | copy openssl-1.1.1g\libssl.lib Python-3.8.2\externals\openssl-bin-1.1.1g\amd64 63 | xcopy /s openssl-1.1.1g\include\openssl Python-3.8.2\externals\openssl-bin-1.1.1g\amd64\include\openssl 64 | copy openssl-1.1.1g\ms\applink.c Python-3.8.2\externals\openssl-bin-1.1.1g\amd64\include 65 | 66 | REM replace the libffi with static ones for ctypes 67 | copy /Y libffi\msvc_build\amd64\x64\Release\Ffi_staticLib_amd64.lib Python-3.8.2\externals\libffi\amd64\libffi-7.lib 68 | copy /Y libffi\msvc_build\amd64\amd64_include\*.h Python-3.8.2\externals\libffi\amd64 69 | 70 | REM win32: 71 | REM copy /Y libffi\msvc_build\x86\Release\Ffi_staticLib_x86.lib Python-3.8.2\externals\libffi\win32\libffi-7.lib 72 | 73 | del cba\cmoduleloader\python\cba_zipimport_frozen.h 74 | Python-3.8.2\PCbuild\win32\_freeze_importlib.exe cba_zipimport cba\cba_zipimport.py cba\cmoduleloader\python\cba_zipimport_frozen.h 75 | 76 | REM copy the vcxproj changes now, except pythoncore... we do not have pyd file yet. 77 | copy /Y cba\settings Python-3.8.2\PCbuild 78 | xcopy /Y /S cba\cmoduleloader Python-3.8.2 79 | REM BUILD solution again 80 | msbuild Python-3.8.2\PCbuild\pcbuild.sln 81 | 82 | REM generate C array for pyd files. 83 | copy /Y Python-3.8.2\PCbuild\amd64\*.pyd scripts\generated\pyd\win64 84 | 85 | \Python38\python.exe scripts\zip_folder.py scripts\generated\pyd\win64 scripts\generated\python382_pyd_win64.zip 86 | \Python38\python scripts\xxd.py python38_pyd_win64 scripts\generated\python382_pyd_win64.zip > Python-3.8.2\Python\cba_python38_pyd_win64.c 87 | 88 | msbuild Python-3.8.2\PCbuild\pythoncore.vcxproj -p:Configuration=Release -------------------------------------------------------------------------------- /build-x86.bat: -------------------------------------------------------------------------------- 1 | REM x64 2 | REM zlib 3 | pushd zlib-1.2.11\contrib\vstudio\vc14 4 | msbuild zlibstat.vcxproj -p:Configuration=ReleaseWithoutAsm -t:Clean 5 | msbuild zlibstat.vcxproj -p:Configuration=ReleaseWithoutAsm 6 | popd 7 | 8 | REM openssl 9 | pushd openssl-1.1.1g 10 | set path=%path%;c:\nasm 11 | set path=%path%;C:\Strawberry\perl\bin 12 | perl Configure no-zlib-dynamic no-shared no-zlib VC-WIN64A --with-zlib-include=zlib-1.2.11 --with-zlib-lib=zlib-1.2.11\contrib\vstudio\vc14\x64\ZlibStatReleaseWithoutAsm\zlibstat.lib -DOPENSSL_USE_NODELETE 13 | nmake clean 14 | nmake 15 | popd 16 | 17 | % for win32 use VC-WIN32 instead of VC-WIN64A above. 18 | 19 | REM ffi 20 | pushd libffi\msvc_build\amd64 21 | msbuild Ffi_staticLib.vcxproj -p:Configuration=Release -t:Clean 22 | msbuild Ffi_staticLib.vcxproj -p:Configuration=Release 23 | popd 24 | 25 | pushd Python-3.8.2\PCbuild 26 | build.bat 27 | popd 28 | 29 | mkdir Python-3.8.2\openssl-bin-1.1.1g\amd64 30 | copy openssl-1.1.1g\libcrypto.lib Python-3.8.2\externals\openssl-bin-1.1.1g\amd64 31 | copy openssl-1.1.1g\libssl.lib Python-3.8.2\externals\openssl-bin-1.1.1g\amd64 32 | copy openssl-1.1.1g\include\openssl Python-3.8.2\externals\openssl-bin-1.1.1g\amd64\include\openssl 33 | copy openssl-1.1.1g\ms\applink.c Python-3.8.2\externals\openssl-bin-1.1.1g\amd64\include 34 | 35 | copy /Y libffi\msvc_build\amd64\x64\Release\Ffi_staticLib_amd64.lib Python-3.8.2\externals\libffi\amd64\libffi-7.lib 36 | 37 | copy /Y libffi\msvc_build\x86\Release\Ffi_staticLib_x86.lib Python-3.8.2\externals\libffi\win32\libffi-7.lib 38 | 39 | copy /Y libffi\msvc_build\amd64\amd64_include\*.h Python-3.8.2\externals\libffi\amd64 40 | 41 | 42 | Python-3.8.2\PCbuild\win32\_freeze_importlib.exe cba_zipimport cba\cba_zipimport.py cba\cba_zipimport_frozen.h 43 | 44 | \python38\python xxd\xxd.py python38_lib C:\Work\papers\usenix\2021\code\Python-3.8.2\Lib\python382_lib.zip > C:\Work\papers\usenix\2021\code\Python-3.8.2\Python\cba_python38_lib.c 45 | 46 | \python38\python xxd\xxd.py python38_pyd_win32 C:\Work\papers\usenix\2021\code\Python-3.8.2\PCbuild\win32\python382_pyd_win32.zip > C:\Work\papers\usenix\2021\code\Python-3.8.2\Python\cba_python38_pyd_win32.c 47 | 48 | \python38\python xxd\xxd.py python38_pyd_win64 C:\Work\papers\usenix\2021\code\Python-3.8.2\PCbuild\amd64\python382_pyd_win64.zip > C:\Work\papers\usenix\2021\code\Python-3.8.2\Python\cba_python38_pyd_win64.c -------------------------------------------------------------------------------- /cba/cba_zipimport.py: -------------------------------------------------------------------------------- 1 | """zipimport provides support for importing Python modules from Zip archives. 2 | 3 | This module exports three objects: 4 | - zipimporter: a class; its constructor takes a path to a Zip archive. 5 | - ZipImportError: exception raised by zipimporter objects. It's a 6 | subclass of ImportError, so it can be caught as ImportError, too. 7 | - _zip_directory_cache: a dict, mapping archive paths to zip directory 8 | info dicts, as used in zipimporter._files. 9 | 10 | It is usually not needed to use the zipimport module explicitly; it is 11 | used by the builtin import mechanism for sys.path items that are paths 12 | to Zip archives. 13 | """ 14 | 15 | #from importlib import _bootstrap_external 16 | #from importlib import _bootstrap # for _verbose_message 17 | import _frozen_importlib_external as _bootstrap_external 18 | from _frozen_importlib_external import _unpack_uint16, _unpack_uint32 19 | import _frozen_importlib as _bootstrap # for _verbose_message 20 | import _imp # for check_hash_based_pycs 21 | import _io # for open 22 | import marshal # for loads 23 | import sys # for modules 24 | import time # for mktime 25 | 26 | __all__ = ['ZipImportError', 'zipimporter', 'CBAMetaFinder', 'CBAImportLoader', 'install_cba_metafinder'] 27 | 28 | __finder = None 29 | __loader = None 30 | 31 | 32 | def install_cba_metafinder(zip_name, zip_data): 33 | """ 34 | 35 | :param str zip_name: 36 | :param bytes zip_data: 37 | :return: 38 | """ 39 | global __loader 40 | if __loader is None: 41 | loader = CBAImportLoader() 42 | __loader = loader 43 | __loader.add_library(zip_name, zip_data) 44 | 45 | global __finder 46 | if __finder is None: 47 | # only add one 48 | finder = CBAMetaFinder(__loader) 49 | sys.meta_path.insert(2, finder) # search before PathFinder but after __import__ 50 | __finder = finder 51 | 52 | 53 | def add_modules(zip_name, zip_data): 54 | """ 55 | 56 | :param str zip_name: 57 | :param btes zip_data: 58 | :return: None 59 | """ 60 | __finder.add_library(zip_name, zip_data) 61 | 62 | 63 | class CBAMetaFinder: 64 | """ 65 | MetaFinder for in-memory ZIP archives 66 | """ 67 | def __init__(self, loader): 68 | self._loader = loader 69 | 70 | def find_module(self, fullname, path): 71 | result = self._loader.find_module(fullname, path) 72 | return result 73 | 74 | def add_library(self, zip_name, zip_data): 75 | self._loader.add_library(zip_name, zip_data) 76 | 77 | def invalidate_caches(self): 78 | """ 79 | 80 | :return: None 81 | """ 82 | 83 | class CBAImportLoader: 84 | """ 85 | ImportLoader for in-memory ZIP archives 86 | """ 87 | def __init__(self): 88 | """ 89 | 90 | """ 91 | self.zip = dict() 92 | self.mapper= dict() 93 | sys.memzip = {} 94 | 95 | def add_library(self, zip_name, zip_data): 96 | """ 97 | 98 | :param str zip_name: 99 | :param bytes zip_data: 100 | :return: 101 | """ 102 | self.mapper[zip_name] = zip_data 103 | new_zip = zipimporter(zip_name, self.mapper) 104 | self.zip[zip_name] = new_zip 105 | 106 | def create_module(self, spec): 107 | raise NotImplementedError 108 | 109 | def load_module(self, fullname): 110 | for item in self.zip: 111 | result = self.zip[item].find_module(fullname.replace(".", "\\")) 112 | if result: 113 | return self.zip[item].load_module(fullname.replace(".", "\\")) 114 | return None 115 | 116 | def find_module(self, fullname, path): 117 | result = False 118 | for item in self.zip: 119 | result = self.zip[item].find_module(fullname.replace(".", "\\"), path) 120 | if result: 121 | break 122 | return result 123 | 124 | 125 | path_sep = _bootstrap_external.path_sep 126 | alt_path_sep = _bootstrap_external.path_separators[1:] 127 | 128 | 129 | class ZipImportError(ImportError): 130 | """ 131 | Not implemented 132 | """ 133 | pass 134 | 135 | 136 | # _read_directory() cache 137 | _zip_directory_cache = {} 138 | 139 | _module_type = type(sys) 140 | 141 | _mapper = dict() 142 | 143 | END_CENTRAL_DIR_SIZE = 22 144 | STRING_END_ARCHIVE = b'PK\x05\x06' 145 | MAX_COMMENT_LEN = (1 << 16) - 1 146 | 147 | 148 | class zipimporter: 149 | """zipimporter(archivepath) -> zipimporter object 150 | 151 | Create a new zipimporter instance. 'archivepath' must be a path to 152 | a zipfile, or to a specific path inside a zipfile. For example, it can be 153 | '/tmp/myimport.zip', or '/tmp/myimport.zip/mydirectory', if mydirectory is a 154 | valid directory inside the archive. 155 | 156 | 'ZipImportError is raised if 'archivepath' doesn't point to a valid Zip 157 | archive. 158 | 159 | The 'archive' attribute of zipimporter objects contains the name of the 160 | zipfile targeted. 161 | """ 162 | 163 | # Split the "subdirectory" from the Zip archive path, lookup a matching 164 | # entry in sys.path_importer_cache, fetch the file directory from there 165 | # if found, or else read it from the archive. 166 | def __init__(self, path, mapper=None): 167 | """ 168 | 169 | :param str path: A zip file. If path contains a '#' it implies zip bytes is in mapper dict 170 | :param dict or None mapper: None if zip file on disk. 171 | """ 172 | if not isinstance(path, str): 173 | import os 174 | path = os.fsdecode(path) 175 | if not path: 176 | raise ZipImportError('archive path is empty', path=path) 177 | if alt_path_sep: 178 | path = path.replace(alt_path_sep, path_sep) 179 | 180 | prefix = [] 181 | if "#" not in path: 182 | while True: 183 | try: 184 | st = _bootstrap_external._path_stat(path) 185 | except (OSError, ValueError): 186 | # On Windows a ValueError is raised for too long paths. 187 | # Back up one path element. 188 | dirname, basename = _bootstrap_external._path_split(path) 189 | if dirname == path: 190 | raise ZipImportError('not a Zip file', path=path) 191 | path = dirname 192 | prefix.append(basename) 193 | else: 194 | # it exists 195 | if (st.st_mode & 0o170000) != 0o100000: # stat.S_ISREG 196 | # it's a not file 197 | raise ZipImportError('not a Zip file', path=path) 198 | break 199 | 200 | if mapper: 201 | # needs to be before _read_directory call below 202 | _mapper.update(mapper) 203 | 204 | try: 205 | files = _zip_directory_cache[path] 206 | except KeyError: 207 | files = _read_directory(path) 208 | _zip_directory_cache[path] = files 209 | self._files = files 210 | self.archive = path 211 | # a prefix directory following the ZIP file path. 212 | self.prefix = _bootstrap_external._path_join(*prefix[::-1]) 213 | if self.prefix: 214 | self.prefix += path_sep 215 | 216 | 217 | 218 | # Check whether we can satisfy the import of the module named by 219 | # 'fullname', or whether it could be a portion of a namespace 220 | # package. Return self if we can load it, a string containing the 221 | # full path if it's a possible namespace portion, None if we 222 | # can't load it. 223 | def find_loader(self, fullname, path=None): 224 | """find_loader(fullname, path=None) -> self, str or None. 225 | 226 | Search for a module specified by 'fullname'. 'fullname' must be the 227 | fully qualified (dotted) module name. It returns the zipimporter 228 | instance itself if the module was found, a string containing the 229 | full path name if it's possibly a portion of a namespace package, 230 | or None otherwise. The optional 'path' argument is ignored -- it's 231 | there for compatibility with the importer protocol. 232 | """ 233 | mi = _get_module_info(self, fullname) 234 | 235 | _bootstrap._verbose_message("cba_zipimport::find_loader {}, path: {}, mi: {}", fullname, path, mi) 236 | 237 | if mi is not None: 238 | # This is a module or package. 239 | return self, [] 240 | 241 | # Not a module or regular package. See if this is a directory, and 242 | # therefore possibly a portion of a namespace package. 243 | 244 | # We're only interested in the last path component of fullname 245 | # earlier components are recorded in self.prefix. 246 | modpath = _get_module_path(self, fullname) 247 | if _is_dir(self, modpath): 248 | # This is possibly a portion of a namespace 249 | # package. Return the string representing its path, 250 | # without a trailing separator. 251 | return None, [f'{self.archive}{path_sep}{modpath}'] 252 | 253 | return None, [] 254 | 255 | 256 | # Check whether we can satisfy the import of the module named by 257 | # 'fullname'. Return self if we can, None if we can't. 258 | def find_module(self, fullname, path=None): 259 | """find_module(fullname, path=None) -> self or None. 260 | 261 | Search for a module specified by 'fullname'. 'fullname' must be the 262 | fully qualified (dotted) module name. It returns the zipimporter 263 | instance itself if the module was found, or None if it wasn't. 264 | The optional 'path' argument is ignored -- it's there for compatibility 265 | with the importer protocol. 266 | """ 267 | _bootstrap._verbose_message("cba_zipimport::find_module {}, path: {}", fullname, path) 268 | return self.find_loader(fullname, path)[0] 269 | 270 | 271 | def get_code(self, fullname): 272 | """get_code(fullname) -> code object. 273 | 274 | Return the code object for the specified module. Raise ZipImportError 275 | if the module couldn't be found. 276 | """ 277 | _bootstrap._verbose_message("cba_zipimport::get_code: fullname {}", fullname) 278 | code, ispackage, modpath, isnative = _get_module_code(self, fullname) 279 | return code 280 | 281 | 282 | def get_data(self, pathname): 283 | """get_data(pathname) -> string with file data. 284 | 285 | Return the data associated with 'pathname'. Raise OSError if 286 | the file wasn't found. 287 | """ 288 | _bootstrap._verbose_message("cba_zipimport::get_data: pathname {}", pathname) 289 | if alt_path_sep: 290 | pathname = pathname.replace(alt_path_sep, path_sep) 291 | 292 | key = pathname 293 | if pathname.startswith(self.archive + path_sep): 294 | key = pathname[len(self.archive + path_sep):] 295 | 296 | try: 297 | toc_entry = self._files[key] 298 | except KeyError: 299 | raise OSError(0, '', key) 300 | return _get_data(self.archive, toc_entry) 301 | 302 | 303 | # Return a string matching __file__ for the named module 304 | def get_filename(self, fullname): 305 | """get_filename(fullname) -> filename string. 306 | 307 | Return the filename for the specified module. 308 | """ 309 | _bootstrap._verbose_message("cba_zipimport::get_filename: fullname {}", fullname) 310 | # Deciding the filename requires working out where the code 311 | # would come from if the module was actually loaded 312 | code, ispackage, modpath, isnative = _get_module_code(self, fullname) 313 | return modpath 314 | 315 | 316 | def get_source(self, fullname): 317 | """get_source(fullname) -> source string. 318 | 319 | Return the source code for the specified module. Raise ZipImportError 320 | if the module couldn't be found, return None if the archive does 321 | contain the module, but has no source for it. 322 | """ 323 | _bootstrap._verbose_message("cba_zipimport::get_source: fullname {}", fullname) 324 | mi = _get_module_info(self, fullname) 325 | if mi is None: 326 | raise ZipImportError(f"can't find module {fullname!r}", name=fullname) 327 | 328 | path = _get_module_path(self, fullname) 329 | if mi: 330 | fullpath = _bootstrap_external._path_join(path, '__init__.py') 331 | else: 332 | fullpath = f'{path}.py' 333 | 334 | try: 335 | toc_entry = self._files[fullpath] 336 | except KeyError: 337 | # we have the module, but no source 338 | return None 339 | return _get_data(self.archive, toc_entry).decode() 340 | 341 | 342 | # Return a bool signifying whether the module is a package or not. 343 | def is_package(self, fullname): 344 | """is_package(fullname) -> bool. 345 | 346 | Return True if the module specified by fullname is a package. 347 | Raise ZipImportError if the module couldn't be found. 348 | """ 349 | _bootstrap._verbose_message("cba_zipimport: is_package: fullname {}", fullname) 350 | mi = _get_module_info(self, fullname) 351 | if mi is None: 352 | raise ZipImportError(f"can't find module {fullname!r}", name=fullname) 353 | return mi 354 | 355 | 356 | # Load and return the module named by 'fullname'. 357 | def load_module(self, fullname): 358 | """load_module(fullname) -> module. 359 | 360 | Load the module specified by 'fullname'. 'fullname' must be the 361 | fully qualified (dotted) module name. It returns the imported 362 | module, or raises ZipImportError if it wasn't found. 363 | """ 364 | _bootstrap._verbose_message("cba_zipimport::load_module: loading... {}", fullname) 365 | code, ispackage, modpath, isnative = _get_module_code(self, fullname) 366 | mod = sys.modules.get(fullname) 367 | _bootstrap._verbose_message("cba_zipimport::load_module: mod... {}, fullname {}", mod, fullname) 368 | if mod is None or not isinstance(mod, _module_type): 369 | mod = _module_type(fullname) 370 | sys.modules[fullname] = mod 371 | mod.__loader__ = self 372 | 373 | try: 374 | if ispackage: 375 | # add __path__ to the module *before* the code gets 376 | # executed 377 | path = _get_module_path(self, fullname) 378 | fullpath = _bootstrap_external._path_join(self.archive, path) 379 | mod.__path__ = [fullpath] 380 | 381 | if not hasattr(mod, '__builtins__'): 382 | mod.__builtins__ = __builtins__ 383 | _bootstrap_external._fix_up_module(mod.__dict__, fullname, modpath) 384 | 385 | if not isnative: 386 | exec(code, mod.__dict__) 387 | else: 388 | mod = _native_code(fullname, code) 389 | except: 390 | del sys.modules[fullname] 391 | raise 392 | 393 | try: 394 | mod = sys.modules[fullname] 395 | except KeyError: 396 | raise ImportError(f'Loaded module {fullname!r} not found in sys.modules') 397 | _bootstrap._verbose_message('import {} # loaded from Zip {}', fullname, modpath) 398 | return mod 399 | 400 | 401 | def get_resource_reader(self, fullname): 402 | """Return the ResourceReader for a package in a zip file. 403 | 404 | If 'fullname' is a package within the zip file, return the 405 | 'ResourceReader' object for the package. Otherwise return None. 406 | """ 407 | try: 408 | if not self.is_package(fullname): 409 | return None 410 | except ZipImportError: 411 | return None 412 | if not _ZipImportResourceReader._registered: 413 | from importlib.abc import ResourceReader 414 | ResourceReader.register(_ZipImportResourceReader) 415 | _ZipImportResourceReader._registered = True 416 | return _ZipImportResourceReader(self, fullname) 417 | 418 | 419 | def __repr__(self): 420 | return f'' 421 | 422 | 423 | # _zip_searchorder defines how we search for a module in the Zip 424 | # archive: we first search for a package __init__, then for 425 | # non-package .pyc, and .py entries. The .pyc entries 426 | # are swapped by initzipimport() if we run in optimized mode. Also, 427 | # '/' is replaced by path_sep there. 428 | # AS: .pyd 429 | _zip_searchorder = ( 430 | (path_sep + '__init__.pyc', True, True, False), 431 | (path_sep + '__init__.py', False, True, False), 432 | ('.pyc', True, False, False), 433 | ('.py', False, False, False), 434 | ('.pyd', False, False, True), 435 | ) 436 | 437 | # Given a module name, return the potential file path in the 438 | # archive (without extension). 439 | def _get_module_path(self, fullname): 440 | _bootstrap._verbose_message("cba_zipimport: _get_module_path fullname: {}", fullname) 441 | # return self.prefix + fullname.rpartition('.')[2] 442 | # AS 443 | return fullname.replace(".", "\\") 444 | 445 | # Does this path represent a directory? 446 | def _is_dir(self, path): 447 | # See if this is a "directory". If so, it's eligible to be part 448 | # of a namespace package. We test by seeing if the name, with an 449 | # appended path separator, exists. 450 | dirpath = path + path_sep 451 | # If dirpath is present in self._files, we have a directory. 452 | return dirpath in self._files 453 | 454 | # Return some information about a module. 455 | def _get_module_info(self, fullname): 456 | path = _get_module_path(self, fullname) 457 | _bootstrap._verbose_message("cba_zipimport:: _get_module_info fullname: {} path: {}", fullname, path) 458 | for suffix, isbytecode, ispackage, isnative in _zip_searchorder: 459 | #if isnative and __debug__: 460 | # fullpath = path + "_d" + suffix 461 | #else: 462 | fullpath = path + suffix 463 | 464 | _bootstrap._verbose_message("cba_zipimport:: _get_module_info searching: {}", fullpath) 465 | if fullpath in self._files: 466 | return ispackage 467 | _bootstrap._verbose_message("cba_zipimport:: _get_module_info returning NOne") 468 | return None 469 | 470 | 471 | # implementation 472 | 473 | # _read_directory(archive) -> files dict (new reference) 474 | # 475 | # Given a path to a Zip archive, build a dict, mapping file names 476 | # (local to the archive, using SEP as a separator) to toc entries. 477 | # 478 | # A toc_entry is a tuple: 479 | # 480 | # (__file__, # value to use for __file__, available for all files, 481 | # # encoded to the filesystem encoding 482 | # compress, # compression kind; 0 for uncompressed 483 | # data_size, # size of compressed data on disk 484 | # file_size, # size of decompressed data 485 | # file_offset, # offset of file header from start of archive 486 | # time, # mod time of file (in dos format) 487 | # date, # mod data of file (in dos format) 488 | # crc, # crc checksum of the data 489 | # ) 490 | # 491 | # Directories can be recognized by the trailing path_sep in the name, 492 | # data_size and file_offset are 0. 493 | def _read_directory(archive): 494 | if "#" not in archive: 495 | try: 496 | fp = _io.open_code(archive) 497 | except OSError: 498 | raise ZipImportError(f"can't open Zip file: {archive!r}", path=archive) 499 | else: 500 | fp = _io.BytesIO(_mapper.get(archive)) 501 | if not fp: 502 | raise ZipImportError(f"can't open Zip file: {archive!r}", path=archive) 503 | 504 | _bootstrap._verbose_message("cba_zipimport:: _read_directory {}", archive) 505 | 506 | with fp: 507 | try: 508 | fp.seek(-END_CENTRAL_DIR_SIZE, 2) 509 | header_position = fp.tell() 510 | buffer = fp.read(END_CENTRAL_DIR_SIZE) 511 | except OSError: 512 | raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 513 | if len(buffer) != END_CENTRAL_DIR_SIZE: 514 | raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 515 | if buffer[:4] != STRING_END_ARCHIVE: 516 | # Bad: End of Central Dir signature 517 | # Check if there's a comment. 518 | try: 519 | fp.seek(0, 2) 520 | file_size = fp.tell() 521 | except OSError: 522 | raise ZipImportError(f"can't read Zip file: {archive!r}", 523 | path=archive) 524 | max_comment_start = max(file_size - MAX_COMMENT_LEN - 525 | END_CENTRAL_DIR_SIZE, 0) 526 | try: 527 | fp.seek(max_comment_start) 528 | data = fp.read() 529 | except OSError: 530 | raise ZipImportError(f"can't read Zip file: {archive!r}", 531 | path=archive) 532 | pos = data.rfind(STRING_END_ARCHIVE) 533 | if pos < 0: 534 | raise ZipImportError(f'not a Zip file: {archive!r}', 535 | path=archive) 536 | buffer = data[pos:pos+END_CENTRAL_DIR_SIZE] 537 | if len(buffer) != END_CENTRAL_DIR_SIZE: 538 | raise ZipImportError(f"corrupt Zip file: {archive!r}", 539 | path=archive) 540 | header_position = file_size - len(data) + pos 541 | 542 | header_size = _unpack_uint32(buffer[12:16]) 543 | header_offset = _unpack_uint32(buffer[16:20]) 544 | if header_position < header_size: 545 | raise ZipImportError(f'bad central directory size: {archive!r}', path=archive) 546 | if header_position < header_offset: 547 | raise ZipImportError(f'bad central directory offset: {archive!r}', path=archive) 548 | header_position -= header_size 549 | arc_offset = header_position - header_offset 550 | if arc_offset < 0: 551 | raise ZipImportError(f'bad central directory size or offset: {archive!r}', path=archive) 552 | 553 | files = {} 554 | # Start of Central Directory 555 | count = 0 556 | try: 557 | fp.seek(header_position) 558 | except OSError: 559 | raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 560 | while True: 561 | buffer = fp.read(46) 562 | if len(buffer) < 4: 563 | raise EOFError('EOF read where not expected') 564 | # Start of file header 565 | if buffer[:4] != b'PK\x01\x02': 566 | break # Bad: Central Dir File Header 567 | if len(buffer) != 46: 568 | raise EOFError('EOF read where not expected') 569 | flags = _unpack_uint16(buffer[8:10]) 570 | compress = _unpack_uint16(buffer[10:12]) 571 | time = _unpack_uint16(buffer[12:14]) 572 | date = _unpack_uint16(buffer[14:16]) 573 | crc = _unpack_uint32(buffer[16:20]) 574 | data_size = _unpack_uint32(buffer[20:24]) 575 | file_size = _unpack_uint32(buffer[24:28]) 576 | name_size = _unpack_uint16(buffer[28:30]) 577 | extra_size = _unpack_uint16(buffer[30:32]) 578 | comment_size = _unpack_uint16(buffer[32:34]) 579 | file_offset = _unpack_uint32(buffer[42:46]) 580 | header_size = name_size + extra_size + comment_size 581 | if file_offset > header_offset: 582 | raise ZipImportError(f'bad local header offset: {archive!r}', path=archive) 583 | file_offset += arc_offset 584 | 585 | try: 586 | name = fp.read(name_size) 587 | except OSError: 588 | raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 589 | if len(name) != name_size: 590 | raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 591 | # On Windows, calling fseek to skip over the fields we don't use is 592 | # slower than reading the data because fseek flushes stdio's 593 | # internal buffers. See issue #8745. 594 | try: 595 | if len(fp.read(header_size - name_size)) != header_size - name_size: 596 | raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 597 | except OSError: 598 | raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 599 | 600 | if flags & 0x800: 601 | # UTF-8 file names extension 602 | name = name.decode() 603 | else: 604 | # Historical ZIP filename encoding 605 | try: 606 | name = name.decode('ascii') 607 | except UnicodeDecodeError: 608 | name = name.decode('latin1').translate(cp437_table) 609 | 610 | name = name.replace('/', path_sep) 611 | path = _bootstrap_external._path_join(archive, name) 612 | t = (path, compress, data_size, file_size, file_offset, time, date, crc) 613 | files[name] = t 614 | count += 1 615 | _bootstrap._verbose_message('zipimport: found {} names in {!r}', count, archive) 616 | return files 617 | 618 | # During bootstrap, we may need to load the encodings 619 | # package from a ZIP file. But the cp437 encoding is implemented 620 | # in Python in the encodings package. 621 | # 622 | # Break out of this dependency by using the translation table for 623 | # the cp437 encoding. 624 | cp437_table = ( 625 | # ASCII part, 8 rows x 16 chars 626 | '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' 627 | '\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f' 628 | ' !"#$%&\'()*+,-./' 629 | '0123456789:;<=>?' 630 | '@ABCDEFGHIJKLMNO' 631 | 'PQRSTUVWXYZ[\\]^_' 632 | '`abcdefghijklmno' 633 | 'pqrstuvwxyz{|}~\x7f' 634 | # non-ASCII part, 16 rows x 8 chars 635 | '\xc7\xfc\xe9\xe2\xe4\xe0\xe5\xe7' 636 | '\xea\xeb\xe8\xef\xee\xec\xc4\xc5' 637 | '\xc9\xe6\xc6\xf4\xf6\xf2\xfb\xf9' 638 | '\xff\xd6\xdc\xa2\xa3\xa5\u20a7\u0192' 639 | '\xe1\xed\xf3\xfa\xf1\xd1\xaa\xba' 640 | '\xbf\u2310\xac\xbd\xbc\xa1\xab\xbb' 641 | '\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556' 642 | '\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510' 643 | '\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f' 644 | '\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567' 645 | '\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b' 646 | '\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580' 647 | '\u03b1\xdf\u0393\u03c0\u03a3\u03c3\xb5\u03c4' 648 | '\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229' 649 | '\u2261\xb1\u2265\u2264\u2320\u2321\xf7\u2248' 650 | '\xb0\u2219\xb7\u221a\u207f\xb2\u25a0\xa0' 651 | ) 652 | 653 | _importing_zlib = False 654 | 655 | # Return the zlib.decompress function object, or NULL if zlib couldn't 656 | # be imported. The function is cached when found, so subsequent calls 657 | # don't import zlib again. 658 | def _get_decompress_func(): 659 | global _importing_zlib 660 | if _importing_zlib: 661 | # Someone has a zlib.py[co] in their Zip file 662 | # let's avoid a stack overflow. 663 | _bootstrap._verbose_message('cba_zipimport: zlib UNAVAILABLE') 664 | raise ZipImportError("can't decompress data; zlib not available") 665 | 666 | _importing_zlib = True 667 | try: 668 | from zlib import decompress 669 | except Exception: 670 | _bootstrap._verbose_message('cba_zipimport: zlib UNAVAILABLE') 671 | raise ZipImportError("can't decompress data; zlib not available") 672 | finally: 673 | _importing_zlib = False 674 | 675 | _bootstrap._verbose_message('cba_zipimport: zlib available') 676 | return decompress 677 | 678 | # Given a path to a Zip file and a toc_entry, return the (uncompressed) data. 679 | def _get_data(archive, toc_entry): 680 | datapath, compress, data_size, file_size, file_offset, time, date, crc = toc_entry 681 | if data_size < 0: 682 | raise ZipImportError('negative data size') 683 | 684 | if "#" in archive: 685 | fp = _io.BytesIO(_mapper.get(archive)) 686 | else: 687 | fp = _io.open_code(archive) 688 | 689 | with fp: 690 | # Check to make sure the local file header is correct 691 | try: 692 | fp.seek(file_offset) 693 | except OSError: 694 | raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 695 | buffer = fp.read(30) 696 | if len(buffer) != 30: 697 | raise EOFError('EOF read where not expected') 698 | 699 | if buffer[:4] != b'PK\x03\x04': 700 | # Bad: Local File Header 701 | raise ZipImportError(f'bad local file header: {archive!r}', path=archive) 702 | 703 | name_size = _unpack_uint16(buffer[26:28]) 704 | extra_size = _unpack_uint16(buffer[28:30]) 705 | header_size = 30 + name_size + extra_size 706 | file_offset += header_size # Start of file data 707 | try: 708 | fp.seek(file_offset) 709 | except OSError: 710 | raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) 711 | raw_data = fp.read(data_size) 712 | if len(raw_data) != data_size: 713 | raise OSError("cba_zipimport: can't read data") 714 | 715 | if compress == 0: 716 | # data is not compressed 717 | return raw_data 718 | 719 | # Decompress with zlib 720 | try: 721 | decompress = _get_decompress_func() 722 | except Exception: 723 | raise ZipImportError("can't decompress data; zlib not available") 724 | return decompress(raw_data, -15) 725 | 726 | 727 | # Lenient date/time comparison function. The precision of the mtime 728 | # in the archive is lower than the mtime stored in a .pyc: we 729 | # must allow a difference of at most one second. 730 | def _eq_mtime(t1, t2): 731 | # dostime only stores even seconds, so be lenient 732 | return abs(t1 - t2) <= 1 733 | 734 | 735 | def _native_code(fullname, data): 736 | """ 737 | 738 | :param data: MZ header... 739 | :return: 740 | """ 741 | _bootstrap._verbose_message("cba_zipimport: _native_code...{}", fullname) 742 | #open(r"c:\temp\haha.dll", "wb").write(data) 743 | # check Lib\importlib\_bootstrap.py for ModuleSpec... it has a loader... 744 | spec = _bootstrap.ModuleSpec(name=fullname, loader=None, origin=r"[memory]") # *loader 745 | mod = _imp.create_dynamic_inmemory(spec, data) 746 | return mod 747 | 748 | # Given the contents of a .py[co] file, unmarshal the data 749 | # and return the code object. Return None if it the magic word doesn't 750 | # match, or if the recorded .py[co] metadata does not match the source, 751 | # (we do this instead of raising an exception as we fall back 752 | # to .py if available and we don't want to mask other errors). 753 | def _unmarshal_code(self, pathname, fullpath, fullname, data): 754 | exc_details = { 755 | 'name': fullname, 756 | 'path': fullpath, 757 | } 758 | 759 | try: 760 | flags = _bootstrap_external._classify_pyc(data, fullname, exc_details) 761 | except ImportError: 762 | return None 763 | 764 | hash_based = flags & 0b1 != 0 765 | if hash_based: 766 | check_source = flags & 0b10 != 0 767 | if (_imp.check_hash_based_pycs != 'never' and 768 | (check_source or _imp.check_hash_based_pycs == 'always')): 769 | source_bytes = _get_pyc_source(self, fullpath) 770 | if source_bytes is not None: 771 | source_hash = _imp.source_hash( 772 | _bootstrap_external._RAW_MAGIC_NUMBER, 773 | source_bytes, 774 | ) 775 | 776 | try: 777 | _bootstrap_external._validate_hash_pyc( 778 | data, source_hash, fullname, exc_details) 779 | except ImportError: 780 | return None 781 | else: 782 | source_mtime, source_size = \ 783 | _get_mtime_and_size_of_source(self, fullpath) 784 | 785 | if source_mtime: 786 | # We don't use _bootstrap_external._validate_timestamp_pyc 787 | # to allow for a more lenient timestamp check. 788 | if (not _eq_mtime(_unpack_uint32(data[8:12]), source_mtime) or 789 | _unpack_uint32(data[12:16]) != source_size): 790 | _bootstrap._verbose_message( 791 | f'bytecode is stale for {fullname!r}') 792 | return None 793 | 794 | code = marshal.loads(data[16:]) 795 | if not isinstance(code, _code_type): 796 | raise TypeError(f'compiled module {pathname!r} is not a code object') 797 | return code 798 | 799 | _code_type = type(_unmarshal_code.__code__) 800 | 801 | 802 | # Replace any occurrences of '\r\n?' in the input string with '\n'. 803 | # This converts DOS and Mac line endings to Unix line endings. 804 | def _normalize_line_endings(source): 805 | source = source.replace(b'\r\n', b'\n') 806 | source = source.replace(b'\r', b'\n') 807 | return source 808 | 809 | # Given a string buffer containing Python source code, compile it 810 | # and return a code object. 811 | def _compile_source(pathname, source): 812 | source = _normalize_line_endings(source) 813 | return compile(source, pathname, 'exec', dont_inherit=True) 814 | 815 | # Convert the date/time values found in the Zip archive to a value 816 | # that's compatible with the time stamp stored in .pyc files. 817 | def _parse_dostime(d, t): 818 | return time.mktime(( 819 | (d >> 9) + 1980, # bits 9..15: year 820 | (d >> 5) & 0xF, # bits 5..8: month 821 | d & 0x1F, # bits 0..4: day 822 | t >> 11, # bits 11..15: hours 823 | (t >> 5) & 0x3F, # bits 8..10: minutes 824 | (t & 0x1F) * 2, # bits 0..7: seconds / 2 825 | -1, -1, -1)) 826 | 827 | # Given a path to a .pyc file in the archive, return the 828 | # modification time of the matching .py file and its size, 829 | # or (0, 0) if no source is available. 830 | def _get_mtime_and_size_of_source(self, path): 831 | try: 832 | # strip 'c' or 'o' from *.py[co] 833 | assert path[-1:] in ('c', 'o') 834 | path = path[:-1] 835 | toc_entry = self._files[path] 836 | # fetch the time stamp of the .py file for comparison 837 | # with an embedded pyc time stamp 838 | time = toc_entry[5] 839 | date = toc_entry[6] 840 | uncompressed_size = toc_entry[3] 841 | return _parse_dostime(date, time), uncompressed_size 842 | except (KeyError, IndexError, TypeError): 843 | return 0, 0 844 | 845 | 846 | # Given a path to a .pyc file in the archive, return the 847 | # contents of the matching .py file, or None if no source 848 | # is available. 849 | def _get_pyc_source(self, path): 850 | # strip 'c' or 'o' from *.py[co] 851 | assert path[-1:] in ('c', 'o') 852 | path = path[:-1] 853 | 854 | try: 855 | toc_entry = self._files[path] 856 | except KeyError: 857 | return None 858 | else: 859 | return _get_data(self.archive, toc_entry) 860 | 861 | 862 | # Get the code object associated with the module specified by 863 | # 'fullname'. 864 | def _get_module_code(self, fullname): 865 | _bootstrap._verbose_message("cba_zipimport: _get_module_code fullname: {}", fullname) 866 | path = _get_module_path(self, fullname) 867 | for suffix, isbytecode, ispackage, isnative in _zip_searchorder: 868 | #if isnative and __debug__: 869 | # fullpath = path + "_d" + suffix 870 | #else: 871 | fullpath = path + suffix 872 | 873 | _bootstrap._verbose_message("fullpath: {}", fullpath) 874 | _bootstrap._verbose_message('trying {}{}{}', self.archive, path_sep, fullpath, verbosity=2) 875 | try: 876 | toc_entry = self._files[fullpath] 877 | except KeyError: 878 | pass 879 | else: 880 | modpath = toc_entry[0] 881 | data = _get_data(self.archive, toc_entry) 882 | _bootstrap._verbose_message("cba_zipimport: _get_module_code, isnative: {}, debug: {}, toc_entry {}", isnative, __debug__, modpath) 883 | if isbytecode: 884 | code = _unmarshal_code(self, modpath, fullpath, fullname, data) 885 | elif isnative: 886 | code = data #_native_code(self, modpath, fullpath, fullname, data) 887 | else: 888 | code = _compile_source(modpath, data) 889 | if code is None: 890 | # bad magic number or non-matching mtime 891 | # in byte code, try next 892 | continue 893 | modpath = toc_entry[0] 894 | return code, ispackage, modpath, isnative 895 | else: 896 | raise ZipImportError(f"can't find module {fullname!r}", name=fullname) 897 | 898 | 899 | class _ZipImportResourceReader: 900 | """Private class used to support ZipImport.get_resource_reader(). 901 | 902 | This class is allowed to reference all the innards and private parts of 903 | the zipimporter. 904 | """ 905 | _registered = False 906 | 907 | def __init__(self, zipimporter, fullname): 908 | self.zipimporter = zipimporter 909 | self.fullname = fullname 910 | 911 | def open_resource(self, resource): 912 | fullname_as_path = self.fullname.replace('.', '/') 913 | path = f'{fullname_as_path}/{resource}' 914 | from io import BytesIO 915 | try: 916 | return BytesIO(self.zipimporter.get_data(path)) 917 | except OSError: 918 | raise FileNotFoundError(path) 919 | 920 | def resource_path(self, resource): 921 | # All resources are in the zip file, so there is no path to the file. 922 | # Raising FileNotFoundError tells the higher level API to extract the 923 | # binary data and create a temporary file. 924 | raise FileNotFoundError 925 | 926 | def is_resource(self, name): 927 | # Maybe we could do better, but if we can get the data, it's a 928 | # resource. Otherwise it isn't. 929 | fullname_as_path = self.fullname.replace('.', '/') 930 | path = f'{fullname_as_path}/{name}' 931 | try: 932 | self.zipimporter.get_data(path) 933 | except OSError: 934 | return False 935 | return True 936 | 937 | def contents(self): 938 | # This is a bit convoluted, because fullname will be a module path, 939 | # but _files is a list of file names relative to the top of the 940 | # archive's namespace. We want to compare file paths to find all the 941 | # names of things inside the module represented by fullname. So we 942 | # turn the module path of fullname into a file path relative to the 943 | # top of the archive, and then we iterate through _files looking for 944 | # names inside that "directory". 945 | from pathlib import Path 946 | fullname_path = Path(self.zipimporter.get_filename(self.fullname)) 947 | relative_path = fullname_path.relative_to(self.zipimporter.archive) 948 | # Don't forget that fullname names a package, so its path will include 949 | # __init__.py, which we want to ignore. 950 | assert relative_path.name == '__init__.py' 951 | package_path = relative_path.parent 952 | subdirs_seen = set() 953 | for filename in self.zipimporter._files: 954 | try: 955 | relative = Path(filename).relative_to(package_path) 956 | except ValueError: 957 | continue 958 | # If the path of the file (which is relative to the top of the zip 959 | # namespace), relative to the package given when the resource 960 | # reader was created, has a parent, then it's a name in a 961 | # subdirectory and thus we skip it. 962 | parent_name = relative.parent.name 963 | if len(parent_name) == 0: 964 | yield relative.name 965 | elif parent_name not in subdirs_seen: 966 | subdirs_seen.add(parent_name) 967 | yield parent_name 968 | -------------------------------------------------------------------------------- /cba/cmoduleloader/include/internal/pycore_pylifecycle.h: -------------------------------------------------------------------------------- 1 | #ifndef Py_INTERNAL_LIFECYCLE_H 2 | #define Py_INTERNAL_LIFECYCLE_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #ifndef Py_BUILD_CORE 8 | # error "this header requires Py_BUILD_CORE define" 9 | #endif 10 | 11 | #include "pycore_initconfig.h" /* _PyArgv */ 12 | #include "pycore_pystate.h" /* _PyRuntimeState */ 13 | 14 | /* True if the main interpreter thread exited due to an unhandled 15 | * KeyboardInterrupt exception, suggesting the user pressed ^C. */ 16 | PyAPI_DATA(int) _Py_UnhandledKeyboardInterrupt; 17 | 18 | extern int _Py_SetFileSystemEncoding( 19 | const char *encoding, 20 | const char *errors); 21 | extern void _Py_ClearFileSystemEncoding(void); 22 | extern PyStatus _PyUnicode_InitEncodings(PyThreadState *tstate); 23 | #ifdef MS_WINDOWS 24 | extern int _PyUnicode_EnableLegacyWindowsFSEncoding(void); 25 | #endif 26 | 27 | PyAPI_FUNC(void) _Py_ClearStandardStreamEncoding(void); 28 | 29 | PyAPI_FUNC(int) _Py_IsLocaleCoercionTarget(const char *ctype_loc); 30 | 31 | /* Various one-time initializers */ 32 | 33 | extern PyStatus _PyUnicode_Init(void); 34 | extern int _PyStructSequence_Init(void); 35 | extern int _PyLong_Init(void); 36 | extern PyStatus _PyFaulthandler_Init(int enable); 37 | extern int _PyTraceMalloc_Init(int enable); 38 | extern PyObject * _PyBuiltin_Init(void); 39 | extern PyStatus _PySys_Create( 40 | _PyRuntimeState *runtime, 41 | PyInterpreterState *interp, 42 | PyObject **sysmod_p); 43 | extern PyStatus _PySys_SetPreliminaryStderr(PyObject *sysdict); 44 | extern PyStatus _PySys_ReadPreinitWarnOptions(PyWideStringList *options); 45 | extern PyStatus _PySys_ReadPreinitXOptions(PyConfig *config); 46 | extern int _PySys_InitMain( 47 | _PyRuntimeState *runtime, 48 | PyInterpreterState *interp); 49 | extern PyStatus _PyImport_Init(PyInterpreterState *interp); 50 | extern PyStatus _PyExc_Init(void); 51 | extern PyStatus _PyErr_Init(void); 52 | extern PyStatus _PyBuiltins_AddExceptions(PyObject * bltinmod); 53 | extern PyStatus _PyImportHooks_Init(void); 54 | extern int _PyFloat_Init(void); 55 | extern PyStatus _Py_HashRandomization_Init(const PyConfig *); 56 | 57 | extern PyStatus _PyTypes_Init(void); 58 | extern PyStatus _PyImportZip_Init(PyInterpreterState *interp); 59 | 60 | /* Begin CBA */ 61 | /* implemented in cba_importinit.c */ 62 | extern PyStatus _PyCBAImport_Init(PyInterpreterState* interp); 63 | /* End CBA*/ 64 | 65 | 66 | /* Various internal finalizers */ 67 | 68 | extern void PyMethod_Fini(void); 69 | extern void PyFrame_Fini(void); 70 | extern void PyCFunction_Fini(void); 71 | extern void PyDict_Fini(void); 72 | extern void PyTuple_Fini(void); 73 | extern void PyList_Fini(void); 74 | extern void PySet_Fini(void); 75 | extern void PyBytes_Fini(void); 76 | extern void PyFloat_Fini(void); 77 | extern void PyOS_FiniInterrupts(void); 78 | extern void PySlice_Fini(void); 79 | extern void PyAsyncGen_Fini(void); 80 | 81 | extern void _PyExc_Fini(void); 82 | extern void _PyImport_Fini(void); 83 | extern void _PyImport_Fini2(void); 84 | extern void _PyGC_Fini(_PyRuntimeState *runtime); 85 | extern void _PyType_Fini(void); 86 | extern void _Py_HashRandomization_Fini(void); 87 | extern void _PyUnicode_Fini(void); 88 | extern void PyLong_Fini(void); 89 | extern void _PyFaulthandler_Fini(void); 90 | extern void _PyHash_Fini(void); 91 | extern void _PyTraceMalloc_Fini(void); 92 | extern void _PyWarnings_Fini(PyInterpreterState *interp); 93 | 94 | extern void _PyGILState_Init( 95 | _PyRuntimeState *runtime, 96 | PyInterpreterState *interp, 97 | PyThreadState *tstate); 98 | extern void _PyGILState_Fini(_PyRuntimeState *runtime); 99 | 100 | PyAPI_FUNC(void) _PyGC_DumpShutdownStats(_PyRuntimeState *runtime); 101 | 102 | PyAPI_FUNC(PyStatus) _Py_PreInitializeFromPyArgv( 103 | const PyPreConfig *src_config, 104 | const _PyArgv *args); 105 | PyAPI_FUNC(PyStatus) _Py_PreInitializeFromConfig( 106 | const PyConfig *config, 107 | const _PyArgv *args); 108 | 109 | 110 | PyAPI_FUNC(int) _Py_HandleSystemExit(int *exitcode_p); 111 | 112 | PyAPI_FUNC(PyObject*) _PyErr_WriteUnraisableDefaultHook(PyObject *unraisable); 113 | 114 | PyAPI_FUNC(void) _PyErr_Print(PyThreadState *tstate); 115 | PyAPI_FUNC(void) _PyErr_Display(PyObject *file, PyObject *exception, 116 | PyObject *value, PyObject *tb); 117 | 118 | #ifdef __cplusplus 119 | } 120 | #endif 121 | #endif /* !Py_INTERNAL_LIFECYCLE_H */ 122 | -------------------------------------------------------------------------------- /cba/cmoduleloader/modules/_ctypes/callbacks.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | #include "frameobject.h" 3 | 4 | #include 5 | #ifdef MS_WIN32 6 | #include 7 | // SCYTHE 8 | void * PyWin_DLLhModule; 9 | // SCYTHE 10 | 11 | #endif 12 | #include "ctypes.h" 13 | 14 | 15 | /**************************************************************/ 16 | 17 | static void 18 | CThunkObject_dealloc(PyObject *myself) 19 | { 20 | CThunkObject *self = (CThunkObject *)myself; 21 | PyObject_GC_UnTrack(self); 22 | Py_XDECREF(self->converters); 23 | Py_XDECREF(self->callable); 24 | Py_XDECREF(self->restype); 25 | if (self->pcl_write) 26 | ffi_closure_free(self->pcl_write); 27 | PyObject_GC_Del(self); 28 | } 29 | 30 | static int 31 | CThunkObject_traverse(PyObject *myself, visitproc visit, void *arg) 32 | { 33 | CThunkObject *self = (CThunkObject *)myself; 34 | Py_VISIT(self->converters); 35 | Py_VISIT(self->callable); 36 | Py_VISIT(self->restype); 37 | return 0; 38 | } 39 | 40 | static int 41 | CThunkObject_clear(PyObject *myself) 42 | { 43 | CThunkObject *self = (CThunkObject *)myself; 44 | Py_CLEAR(self->converters); 45 | Py_CLEAR(self->callable); 46 | Py_CLEAR(self->restype); 47 | return 0; 48 | } 49 | 50 | PyTypeObject PyCThunk_Type = { 51 | PyVarObject_HEAD_INIT(NULL, 0) 52 | "_ctypes.CThunkObject", 53 | sizeof(CThunkObject), /* tp_basicsize */ 54 | sizeof(ffi_type), /* tp_itemsize */ 55 | CThunkObject_dealloc, /* tp_dealloc */ 56 | 0, /* tp_vectorcall_offset */ 57 | 0, /* tp_getattr */ 58 | 0, /* tp_setattr */ 59 | 0, /* tp_as_async */ 60 | 0, /* tp_repr */ 61 | 0, /* tp_as_number */ 62 | 0, /* tp_as_sequence */ 63 | 0, /* tp_as_mapping */ 64 | 0, /* tp_hash */ 65 | 0, /* tp_call */ 66 | 0, /* tp_str */ 67 | 0, /* tp_getattro */ 68 | 0, /* tp_setattro */ 69 | 0, /* tp_as_buffer */ 70 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 71 | "CThunkObject", /* tp_doc */ 72 | CThunkObject_traverse, /* tp_traverse */ 73 | CThunkObject_clear, /* tp_clear */ 74 | 0, /* tp_richcompare */ 75 | 0, /* tp_weaklistoffset */ 76 | 0, /* tp_iter */ 77 | 0, /* tp_iternext */ 78 | 0, /* tp_methods */ 79 | 0, /* tp_members */ 80 | }; 81 | 82 | /**************************************************************/ 83 | 84 | static void 85 | PrintError(const char *msg, ...) 86 | { 87 | char buf[512]; 88 | PyObject *f = PySys_GetObject("stderr"); 89 | va_list marker; 90 | 91 | va_start(marker, msg); 92 | vsnprintf(buf, sizeof(buf), msg, marker); 93 | va_end(marker); 94 | if (f != NULL && f != Py_None) 95 | PyFile_WriteString(buf, f); 96 | PyErr_Print(); 97 | } 98 | 99 | 100 | #ifdef MS_WIN32 101 | /* 102 | * We must call AddRef() on non-NULL COM pointers we receive as arguments 103 | * to callback functions - these functions are COM method implementations. 104 | * The Python instances we create have a __del__ method which calls Release(). 105 | * 106 | * The presence of a class attribute named '_needs_com_addref_' triggers this 107 | * behaviour. It would also be possible to call the AddRef() Python method, 108 | * after checking for PyObject_IsTrue(), but this would probably be somewhat 109 | * slower. 110 | */ 111 | static void 112 | TryAddRef(StgDictObject *dict, CDataObject *obj) 113 | { 114 | IUnknown *punk; 115 | _Py_IDENTIFIER(_needs_com_addref_); 116 | 117 | if (!_PyDict_GetItemIdWithError((PyObject *)dict, &PyId__needs_com_addref_)) { 118 | if (PyErr_Occurred()) { 119 | PrintError("getting _needs_com_addref_"); 120 | } 121 | return; 122 | } 123 | 124 | punk = *(IUnknown **)obj->b_ptr; 125 | if (punk) 126 | punk->lpVtbl->AddRef(punk); 127 | return; 128 | } 129 | #endif 130 | 131 | /****************************************************************************** 132 | * 133 | * Call the python object with all arguments 134 | * 135 | */ 136 | static void _CallPythonObject(void *mem, 137 | ffi_type *restype, 138 | SETFUNC setfunc, 139 | PyObject *callable, 140 | PyObject *converters, 141 | int flags, 142 | void **pArgs) 143 | { 144 | Py_ssize_t i; 145 | PyObject *result; 146 | PyObject *arglist = NULL; 147 | Py_ssize_t nArgs; 148 | PyObject *error_object = NULL; 149 | int *space; 150 | PyGILState_STATE state = PyGILState_Ensure(); 151 | 152 | nArgs = PySequence_Length(converters); 153 | /* Hm. What to return in case of error? 154 | For COM, 0xFFFFFFFF seems better than 0. 155 | */ 156 | if (nArgs < 0) { 157 | PrintError("BUG: PySequence_Length"); 158 | goto Done; 159 | } 160 | 161 | arglist = PyTuple_New(nArgs); 162 | if (!arglist) { 163 | PrintError("PyTuple_New()"); 164 | goto Done; 165 | } 166 | for (i = 0; i < nArgs; ++i) { 167 | /* Note: new reference! */ 168 | PyObject *cnv = PySequence_GetItem(converters, i); 169 | StgDictObject *dict; 170 | if (cnv) 171 | dict = PyType_stgdict(cnv); 172 | else { 173 | PrintError("Getting argument converter %zd\n", i); 174 | goto Done; 175 | } 176 | 177 | if (dict && dict->getfunc && !_ctypes_simple_instance(cnv)) { 178 | PyObject *v = dict->getfunc(*pArgs, dict->size); 179 | if (!v) { 180 | PrintError("create argument %zd:\n", i); 181 | Py_DECREF(cnv); 182 | goto Done; 183 | } 184 | PyTuple_SET_ITEM(arglist, i, v); 185 | /* XXX XXX XX 186 | We have the problem that c_byte or c_short have dict->size of 187 | 1 resp. 4, but these parameters are pushed as sizeof(int) bytes. 188 | BTW, the same problem occurs when they are pushed as parameters 189 | */ 190 | } else if (dict) { 191 | /* Hm, shouldn't we use PyCData_AtAddress() or something like that instead? */ 192 | CDataObject *obj = (CDataObject *)_PyObject_CallNoArg(cnv); 193 | if (!obj) { 194 | PrintError("create argument %zd:\n", i); 195 | Py_DECREF(cnv); 196 | goto Done; 197 | } 198 | if (!CDataObject_Check(obj)) { 199 | Py_DECREF(obj); 200 | Py_DECREF(cnv); 201 | PrintError("unexpected result of create argument %zd:\n", i); 202 | goto Done; 203 | } 204 | memcpy(obj->b_ptr, *pArgs, dict->size); 205 | PyTuple_SET_ITEM(arglist, i, (PyObject *)obj); 206 | #ifdef MS_WIN32 207 | TryAddRef(dict, obj); 208 | #endif 209 | } else { 210 | PyErr_SetString(PyExc_TypeError, 211 | "cannot build parameter"); 212 | PrintError("Parsing argument %zd\n", i); 213 | Py_DECREF(cnv); 214 | goto Done; 215 | } 216 | Py_DECREF(cnv); 217 | /* XXX error handling! */ 218 | pArgs++; 219 | } 220 | 221 | #define CHECK(what, x) \ 222 | if (x == NULL) _PyTraceback_Add(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print() 223 | 224 | if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR)) { 225 | error_object = _ctypes_get_errobj(&space); 226 | if (error_object == NULL) 227 | goto Done; 228 | if (flags & FUNCFLAG_USE_ERRNO) { 229 | int temp = space[0]; 230 | space[0] = errno; 231 | errno = temp; 232 | } 233 | #ifdef MS_WIN32 234 | if (flags & FUNCFLAG_USE_LASTERROR) { 235 | int temp = space[1]; 236 | space[1] = GetLastError(); 237 | SetLastError(temp); 238 | } 239 | #endif 240 | } 241 | 242 | result = PyObject_CallObject(callable, arglist); 243 | CHECK("'calling callback function'", result); 244 | 245 | #ifdef MS_WIN32 246 | if (flags & FUNCFLAG_USE_LASTERROR) { 247 | int temp = space[1]; 248 | space[1] = GetLastError(); 249 | SetLastError(temp); 250 | } 251 | #endif 252 | if (flags & FUNCFLAG_USE_ERRNO) { 253 | int temp = space[0]; 254 | space[0] = errno; 255 | errno = temp; 256 | } 257 | Py_XDECREF(error_object); 258 | 259 | if ((restype != &ffi_type_void) && result) { 260 | PyObject *keep; 261 | assert(setfunc); 262 | #ifdef WORDS_BIGENDIAN 263 | /* See the corresponding code in callproc.c, around line 961 */ 264 | if (restype->type != FFI_TYPE_FLOAT && restype->size < sizeof(ffi_arg)) 265 | mem = (char *)mem + sizeof(ffi_arg) - restype->size; 266 | #endif 267 | keep = setfunc(mem, result, 0); 268 | CHECK("'converting callback result'", keep); 269 | /* keep is an object we have to keep alive so that the result 270 | stays valid. If there is no such object, the setfunc will 271 | have returned Py_None. 272 | 273 | If there is such an object, we have no choice than to keep 274 | it alive forever - but a refcount and/or memory leak will 275 | be the result. EXCEPT when restype is py_object - Python 276 | itself knows how to manage the refcount of these objects. 277 | */ 278 | if (keep == NULL) /* Could not convert callback result. */ 279 | PyErr_WriteUnraisable(callable); 280 | else if (keep == Py_None) /* Nothing to keep */ 281 | Py_DECREF(keep); 282 | else if (setfunc != _ctypes_get_fielddesc("O")->setfunc) { 283 | if (-1 == PyErr_WarnEx(PyExc_RuntimeWarning, 284 | "memory leak in callback function.", 285 | 1)) 286 | PyErr_WriteUnraisable(callable); 287 | } 288 | } 289 | Py_XDECREF(result); 290 | Done: 291 | Py_XDECREF(arglist); 292 | PyGILState_Release(state); 293 | } 294 | 295 | static void closure_fcn(ffi_cif *cif, 296 | void *resp, 297 | void **args, 298 | void *userdata) 299 | { 300 | CThunkObject *p = (CThunkObject *)userdata; 301 | 302 | _CallPythonObject(resp, 303 | p->ffi_restype, 304 | p->setfunc, 305 | p->callable, 306 | p->converters, 307 | p->flags, 308 | args); 309 | } 310 | 311 | static CThunkObject* CThunkObject_new(Py_ssize_t nArgs) 312 | { 313 | CThunkObject *p; 314 | Py_ssize_t i; 315 | 316 | p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nArgs); 317 | if (p == NULL) { 318 | return NULL; 319 | } 320 | 321 | p->pcl_write = NULL; 322 | p->pcl_exec = NULL; 323 | memset(&p->cif, 0, sizeof(p->cif)); 324 | p->flags = 0; 325 | p->converters = NULL; 326 | p->callable = NULL; 327 | p->restype = NULL; 328 | p->setfunc = NULL; 329 | p->ffi_restype = NULL; 330 | 331 | for (i = 0; i < nArgs + 1; ++i) 332 | p->atypes[i] = NULL; 333 | PyObject_GC_Track((PyObject *)p); 334 | return p; 335 | } 336 | 337 | CThunkObject *_ctypes_alloc_callback(PyObject *callable, 338 | PyObject *converters, 339 | PyObject *restype, 340 | int flags) 341 | { 342 | int result; 343 | CThunkObject *p; 344 | Py_ssize_t nArgs, i; 345 | ffi_abi cc; 346 | 347 | nArgs = PySequence_Size(converters); 348 | p = CThunkObject_new(nArgs); 349 | if (p == NULL) 350 | return NULL; 351 | 352 | assert(CThunk_CheckExact((PyObject *)p)); 353 | 354 | p->pcl_write = ffi_closure_alloc(sizeof(ffi_closure), 355 | &p->pcl_exec); 356 | if (p->pcl_write == NULL) { 357 | PyErr_NoMemory(); 358 | goto error; 359 | } 360 | 361 | p->flags = flags; 362 | for (i = 0; i < nArgs; ++i) { 363 | PyObject *cnv = PySequence_GetItem(converters, i); 364 | if (cnv == NULL) 365 | goto error; 366 | p->atypes[i] = _ctypes_get_ffi_type(cnv); 367 | Py_DECREF(cnv); 368 | } 369 | p->atypes[i] = NULL; 370 | 371 | Py_INCREF(restype); 372 | p->restype = restype; 373 | if (restype == Py_None) { 374 | p->setfunc = NULL; 375 | p->ffi_restype = &ffi_type_void; 376 | } else { 377 | StgDictObject *dict = PyType_stgdict(restype); 378 | if (dict == NULL || dict->setfunc == NULL) { 379 | PyErr_SetString(PyExc_TypeError, 380 | "invalid result type for callback function"); 381 | goto error; 382 | } 383 | p->setfunc = dict->setfunc; 384 | p->ffi_restype = &dict->ffi_type_pointer; 385 | } 386 | 387 | cc = FFI_DEFAULT_ABI; 388 | #if defined(MS_WIN32) && !defined(_WIN32_WCE) && !defined(MS_WIN64) && !defined(_M_ARM) 389 | if ((flags & FUNCFLAG_CDECL) == 0) 390 | cc = FFI_STDCALL; 391 | #endif 392 | result = ffi_prep_cif(&p->cif, cc, 393 | Py_SAFE_DOWNCAST(nArgs, Py_ssize_t, int), 394 | _ctypes_get_ffi_type(restype), 395 | &p->atypes[0]); 396 | if (result != FFI_OK) { 397 | PyErr_Format(PyExc_RuntimeError, 398 | "ffi_prep_cif failed with %d", result); 399 | goto error; 400 | } 401 | #if defined(X86_DARWIN) || defined(POWERPC_DARWIN) 402 | result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p); 403 | #else 404 | result = ffi_prep_closure_loc(p->pcl_write, &p->cif, closure_fcn, 405 | p, 406 | p->pcl_exec); 407 | #endif 408 | if (result != FFI_OK) { 409 | PyErr_Format(PyExc_RuntimeError, 410 | "ffi_prep_closure failed with %d", result); 411 | goto error; 412 | } 413 | 414 | Py_INCREF(converters); 415 | p->converters = converters; 416 | Py_INCREF(callable); 417 | p->callable = callable; 418 | return p; 419 | 420 | error: 421 | Py_XDECREF(p); 422 | return NULL; 423 | } 424 | 425 | #ifdef MS_WIN32 426 | 427 | static void LoadPython(void) 428 | { 429 | if (!Py_IsInitialized()) { 430 | Py_Initialize(); 431 | PyEval_InitThreads(); 432 | } 433 | } 434 | 435 | /******************************************************************/ 436 | 437 | long Call_GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 438 | { 439 | PyObject *mod, *func, *result; 440 | long retval; 441 | static PyObject *context; 442 | 443 | if (context == NULL) 444 | context = PyUnicode_InternFromString("_ctypes.DllGetClassObject"); 445 | 446 | mod = PyImport_ImportModuleNoBlock("ctypes"); 447 | if (!mod) { 448 | PyErr_WriteUnraisable(context ? context : Py_None); 449 | /* There has been a warning before about this already */ 450 | return E_FAIL; 451 | } 452 | 453 | func = PyObject_GetAttrString(mod, "DllGetClassObject"); 454 | Py_DECREF(mod); 455 | if (!func) { 456 | PyErr_WriteUnraisable(context ? context : Py_None); 457 | return E_FAIL; 458 | } 459 | 460 | { 461 | PyObject *py_rclsid = PyLong_FromVoidPtr((void *)rclsid); 462 | PyObject *py_riid = PyLong_FromVoidPtr((void *)riid); 463 | PyObject *py_ppv = PyLong_FromVoidPtr(ppv); 464 | if (!py_rclsid || !py_riid || !py_ppv) { 465 | Py_XDECREF(py_rclsid); 466 | Py_XDECREF(py_riid); 467 | Py_XDECREF(py_ppv); 468 | Py_DECREF(func); 469 | PyErr_WriteUnraisable(context ? context : Py_None); 470 | return E_FAIL; 471 | } 472 | result = PyObject_CallFunctionObjArgs(func, 473 | py_rclsid, 474 | py_riid, 475 | py_ppv, 476 | NULL); 477 | Py_DECREF(py_rclsid); 478 | Py_DECREF(py_riid); 479 | Py_DECREF(py_ppv); 480 | } 481 | Py_DECREF(func); 482 | if (!result) { 483 | PyErr_WriteUnraisable(context ? context : Py_None); 484 | return E_FAIL; 485 | } 486 | 487 | retval = PyLong_AsLong(result); 488 | if (PyErr_Occurred()) { 489 | PyErr_WriteUnraisable(context ? context : Py_None); 490 | retval = E_FAIL; 491 | } 492 | Py_DECREF(result); 493 | return retval; 494 | } 495 | 496 | STDAPI DllGetClassObject(REFCLSID rclsid, 497 | REFIID riid, 498 | LPVOID *ppv) 499 | { 500 | long result; 501 | PyGILState_STATE state; 502 | 503 | LoadPython(); 504 | state = PyGILState_Ensure(); 505 | result = Call_GetClassObject(rclsid, riid, ppv); 506 | PyGILState_Release(state); 507 | return result; 508 | } 509 | 510 | long Call_CanUnloadNow(void) 511 | { 512 | PyObject *mod, *func, *result; 513 | long retval; 514 | static PyObject *context; 515 | 516 | if (context == NULL) 517 | context = PyUnicode_InternFromString("_ctypes.DllCanUnloadNow"); 518 | 519 | mod = PyImport_ImportModuleNoBlock("ctypes"); 520 | if (!mod) { 521 | /* OutputDebugString("Could not import ctypes"); */ 522 | /* We assume that this error can only occur when shutting 523 | down, so we silently ignore it */ 524 | PyErr_Clear(); 525 | return E_FAIL; 526 | } 527 | /* Other errors cannot be raised, but are printed to stderr */ 528 | func = PyObject_GetAttrString(mod, "DllCanUnloadNow"); 529 | Py_DECREF(mod); 530 | if (!func) { 531 | PyErr_WriteUnraisable(context ? context : Py_None); 532 | return E_FAIL; 533 | } 534 | 535 | result = _PyObject_CallNoArg(func); 536 | Py_DECREF(func); 537 | if (!result) { 538 | PyErr_WriteUnraisable(context ? context : Py_None); 539 | return E_FAIL; 540 | } 541 | 542 | retval = PyLong_AsLong(result); 543 | if (PyErr_Occurred()) { 544 | PyErr_WriteUnraisable(context ? context : Py_None); 545 | retval = E_FAIL; 546 | } 547 | Py_DECREF(result); 548 | return retval; 549 | } 550 | 551 | /* 552 | DllRegisterServer and DllUnregisterServer still missing 553 | */ 554 | 555 | STDAPI DllCanUnloadNow(void) 556 | { 557 | long result; 558 | PyGILState_STATE state = PyGILState_Ensure(); 559 | result = Call_CanUnloadNow(); 560 | PyGILState_Release(state); 561 | return result; 562 | } 563 | 564 | #ifndef Py_NO_ENABLE_SHARED 565 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvRes) 566 | { 567 | switch(fdwReason) { 568 | case DLL_PROCESS_ATTACH: 569 | DisableThreadLibraryCalls(hinstDLL); 570 | PyWin_DLLhModule = 0; 571 | break; 572 | } 573 | return TRUE; 574 | } 575 | #endif 576 | 577 | #endif 578 | 579 | /* 580 | Local Variables: 581 | compile-command: "cd .. && python setup.py -q build_ext" 582 | End: 583 | */ 584 | -------------------------------------------------------------------------------- /cba/cmoduleloader/modules/_ctypes/cba_moduleloader.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farfella/in-memory-cpython/cf414bff256561f029553b3018d9609f36992223/cba/cmoduleloader/modules/_ctypes/cba_moduleloader.c -------------------------------------------------------------------------------- /cba/cmoduleloader/modules/_ctypes/cba_moduleloader.h: -------------------------------------------------------------------------------- 1 | #ifndef __CUSTOM_MODULELOADER_H__ 2 | #define __CUSTOM_MODULELOADER_H__ 3 | 4 | #if defined (_MSC_VER) && (_MSC_VER >= 1020) 5 | #pragma once 6 | #endif 7 | 8 | #include 9 | 10 | typedef struct _LOADEDMODULE 11 | { 12 | PIMAGE_NT_HEADERS pHeaders; 13 | PBYTE pCodeBase; 14 | HINSTANCE * pModules; 15 | INT nModules; 16 | BOOL fInitialized; 17 | BOOL fRelocated; 18 | DWORD dwPageSize; 19 | } LOADEDMODULE, *PLOADEDMODULE; 20 | 21 | typedef PVOID HLOADEDMODULE; 22 | 23 | PLOADEDMODULE _LoadModuleFromInstance(HINSTANCE hInstance); 24 | __checkReturn __success(return != NULL) PLOADEDMODULE LoadModuleFromMemory(PVOID lpData, DWORD dwSize); 25 | FARPROC _GetProcAddress(PLOADEDMODULE pModule, LPCSTR FuncName); 26 | void FreeLibraryResources(PLOADEDMODULE pModule); 27 | __checkReturn __success(return == TRUE) BOOL IsPEHeaderValid(__in PVOID lpData, __in DWORD dwSize); 28 | PVOID _FindResource(PLOADEDMODULE module, LPCTSTR name, LPCTSTR type); 29 | LPVOID _LoadResource(PLOADEDMODULE module, PVOID resource); 30 | DWORD _SizeofResource(PLOADEDMODULE module, PVOID resource); 31 | 32 | // Section data from file header 33 | typedef struct _SECTIONDATA 34 | { 35 | LPVOID pAddress; 36 | LPVOID pAlignedAddress; 37 | uintptr_t Size; 38 | DWORD dwCharacteristics; 39 | BOOL fLast; 40 | } SECTIONDATA, *PSECTIONDATA; 41 | 42 | 43 | #define ARCHITECTURE_TYPE_X86 0x00000000 44 | #define ARCHITECTURE_TYPE_X64 0x00000001 45 | 46 | // MIN/MAX of address aligned 47 | #define MIN_ALIGNED(address, alignment) (LPVOID)((uintptr_t)(address) & ~((alignment) - 1)) 48 | #define MAX_ALIGNED(value, alignment) (((value) + (alignment) - 1) & ~((alignment) - 1)) 49 | 50 | typedef BOOL(WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); 51 | 52 | #define DEFAULT_LANGUAGE MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) 53 | 54 | #endif /* __CUSTOM_MODULELOADER_H__ */ -------------------------------------------------------------------------------- /cba/cmoduleloader/python/cba_dynload_win.c: -------------------------------------------------------------------------------- 1 | 2 | /* Support for dynamic loading of extension modules */ 3 | 4 | #include "Python.h" 5 | 6 | #ifdef HAVE_DIRECT_H 7 | #include 8 | #endif 9 | #include 10 | 11 | #include "importdl.h" 12 | #include "patchlevel.h" 13 | #include "cba_moduleloader.h" 14 | #include 15 | 16 | 17 | #ifdef _DEBUG 18 | #define PYD_DEBUG_SUFFIX "_d" 19 | #else 20 | #define PYD_DEBUG_SUFFIX "" 21 | #endif 22 | 23 | #ifdef PYD_PLATFORM_TAG 24 | #define PYD_TAGGED_SUFFIX PYD_DEBUG_SUFFIX ".cp" Py_STRINGIFY(PY_MAJOR_VERSION) Py_STRINGIFY(PY_MINOR_VERSION) "-" PYD_PLATFORM_TAG ".pyd" 25 | #else 26 | #define PYD_TAGGED_SUFFIX PYD_DEBUG_SUFFIX ".cp" Py_STRINGIFY(PY_MAJOR_VERSION) Py_STRINGIFY(PY_MINOR_VERSION) ".pyd" 27 | #endif 28 | 29 | #define PYD_UNTAGGED_SUFFIX PYD_DEBUG_SUFFIX ".pyd" 30 | 31 | /* Function to return the name of the "python" DLL that the supplied module 32 | directly imports. Looks through the list of imported modules and 33 | returns the first entry that starts with "python" (case sensitive) and 34 | is followed by nothing but numbers until the separator (period). 35 | 36 | Returns a pointer to the import name, or NULL if no matching name was 37 | located. 38 | 39 | This function parses through the PE header for the module as loaded in 40 | memory by the system loader. The PE header is accessed as documented by 41 | Microsoft in the MSDN PE and COFF specification (2/99), and handles 42 | both PE32 and PE32+. It only worries about the direct import table and 43 | not the delay load import table since it's unlikely an extension is 44 | going to be delay loading Python (after all, it's already loaded). 45 | 46 | If any magic values are not found (e.g., the PE header or optional 47 | header magic), then this function simply returns NULL. */ 48 | 49 | #define DWORD_AT(mem) (*(DWORD *)(mem)) 50 | #define WORD_AT(mem) (*(WORD *)(mem)) 51 | 52 | static char *CBA_GetPythonImport (PLOADEDMODULE pModule) 53 | { 54 | unsigned char *dllbase, *import_data, *import_name; 55 | DWORD pe_offset, opt_offset; 56 | WORD opt_magic; 57 | int num_dict_off, import_off; 58 | 59 | /* Safety check input */ 60 | if (pModule == NULL) { 61 | return NULL; 62 | } 63 | 64 | /* Module instance is also the base load address. First portion of 65 | memory is the MS-DOS loader, which holds the offset to the PE 66 | header (from the load base) at 0x3C */ 67 | dllbase = (unsigned char *)pModule->pCodeBase; 68 | pe_offset = DWORD_AT(dllbase + 0x3C); 69 | 70 | /* The PE signature must be "PE\0\0" */ 71 | if (memcmp(dllbase+pe_offset,"PE\0\0",4)) { 72 | return NULL; 73 | } 74 | 75 | /* Following the PE signature is the standard COFF header (20 76 | bytes) and then the optional header. The optional header starts 77 | with a magic value of 0x10B for PE32 or 0x20B for PE32+ (PE32+ 78 | uses 64-bits for some fields). It might also be 0x107 for a ROM 79 | image, but we don't process that here. 80 | 81 | The optional header ends with a data dictionary that directly 82 | points to certain types of data, among them the import entries 83 | (in the second table entry). Based on the header type, we 84 | determine offsets for the data dictionary count and the entry 85 | within the dictionary pointing to the imports. */ 86 | 87 | opt_offset = pe_offset + 4 + 20; 88 | opt_magic = WORD_AT(dllbase+opt_offset); 89 | if (opt_magic == 0x10B) { 90 | /* PE32 */ 91 | num_dict_off = 92; 92 | import_off = 104; 93 | } else if (opt_magic == 0x20B) { 94 | /* PE32+ */ 95 | num_dict_off = 108; 96 | import_off = 120; 97 | } else { 98 | /* Unsupported */ 99 | return NULL; 100 | } 101 | 102 | /* Now if an import table exists, offset to it and walk the list of 103 | imports. The import table is an array (ending when an entry has 104 | empty values) of structures (20 bytes each), which contains (at 105 | offset 12) a relative address (to the module base) at which a 106 | string constant holding the import name is located. */ 107 | 108 | if (DWORD_AT(dllbase + opt_offset + num_dict_off) >= 2) { 109 | /* We have at least 2 tables - the import table is the second 110 | one. But still it may be that the table size is zero */ 111 | if (0 == DWORD_AT(dllbase + opt_offset + import_off + sizeof(DWORD))) 112 | return NULL; 113 | import_data = dllbase + DWORD_AT(dllbase + 114 | opt_offset + 115 | import_off); 116 | while (DWORD_AT(import_data)) { 117 | import_name = dllbase + DWORD_AT(import_data+12); 118 | if (strlen(import_name) >= 6 && 119 | !strncmp(import_name,"python",6)) { 120 | char *pch; 121 | 122 | #ifndef _DEBUG 123 | /* In a release version, don't claim that python3.dll is 124 | a Python DLL. */ 125 | if (strcmp(import_name, "python3.dll") == 0) { 126 | import_data += 20; 127 | continue; 128 | } 129 | #endif 130 | 131 | /* Ensure python prefix is followed only 132 | by numbers to the end of the basename */ 133 | pch = import_name + 6; 134 | #ifdef _DEBUG 135 | while (*pch && pch[0] != '_' && pch[1] != 'd' && pch[2] != '.') { 136 | #else 137 | while (*pch && *pch != '.') { 138 | #endif 139 | if (*pch >= '0' && *pch <= '9') { 140 | pch++; 141 | } else { 142 | pch = NULL; 143 | break; 144 | } 145 | } 146 | 147 | if (pch) { 148 | /* Found it - return the name */ 149 | return import_name; 150 | } 151 | } 152 | import_data += 20; 153 | } 154 | } 155 | 156 | return NULL; 157 | } 158 | 159 | dl_funcptr _PyImport_CBA_FindSharedFuncptrWindows(const char *prefix, 160 | const char *shortname, 161 | void * hModule, 162 | Py_ssize_t size) 163 | { 164 | dl_funcptr p; 165 | char funcname[258], *import_python; 166 | 167 | #ifndef _DEBUG 168 | _Py_CheckPython3(); 169 | #endif 170 | 171 | PyOS_snprintf(funcname, sizeof(funcname), "%.20s_%.200s", prefix, shortname); 172 | 173 | { 174 | PLOADEDMODULE pModule = NULL; 175 | unsigned int old_mode; 176 | 177 | /* Don't display a message box when Python can't load a DLL */ 178 | old_mode = SetErrorMode(SEM_FAILCRITICALERRORS); 179 | 180 | /* bpo-36085: We use LoadLibraryEx with restricted search paths 181 | to avoid DLL preloading attacks and enable use of the 182 | AddDllDirectory function. We add SEARCH_DLL_LOAD_DIR to 183 | ensure DLLs adjacent to the PYD are preferred. */ 184 | Py_BEGIN_ALLOW_THREADS 185 | 186 | pModule = LoadModuleFromMemory(hModule, (DWORD)size); 187 | 188 | Py_END_ALLOW_THREADS 189 | 190 | /* restore old error mode settings */ 191 | SetErrorMode(old_mode); 192 | 193 | if (pModule==NULL){ 194 | PyObject *message; 195 | unsigned int errorCode; 196 | 197 | /* Get an error string from Win32 error code */ 198 | wchar_t theInfo[256]; /* Pointer to error text 199 | from system */ 200 | int theLength; /* Length of error text */ 201 | 202 | errorCode = GetLastError(); 203 | 204 | theLength = FormatMessageW( 205 | FORMAT_MESSAGE_FROM_SYSTEM | 206 | FORMAT_MESSAGE_IGNORE_INSERTS, /* flags */ 207 | NULL, /* message source */ 208 | errorCode, /* the message (error) ID */ 209 | MAKELANGID(LANG_NEUTRAL, 210 | SUBLANG_DEFAULT), 211 | /* Default language */ 212 | theInfo, /* the buffer */ 213 | sizeof(theInfo) / sizeof(wchar_t), /* size in wchars */ 214 | NULL); /* no additional format args. */ 215 | 216 | /* Problem: could not get the error message. 217 | This should not happen if called correctly. */ 218 | if (theLength == 0) { 219 | message = PyUnicode_FromFormat( 220 | "DLL load failed with error code %u while importing %s", 221 | errorCode, shortname); 222 | } else { 223 | /* For some reason a \r\n 224 | is appended to the text */ 225 | if (theLength >= 2 && 226 | theInfo[theLength-2] == '\r' && 227 | theInfo[theLength-1] == '\n') { 228 | theLength -= 2; 229 | theInfo[theLength] = '\0'; 230 | } 231 | message = PyUnicode_FromFormat( 232 | "DLL load failed while importing %s: ", shortname); 233 | 234 | PyUnicode_AppendAndDel(&message, 235 | PyUnicode_FromWideChar( 236 | theInfo, 237 | theLength)); 238 | } 239 | if (message != NULL) { 240 | PyObject *shortname_obj = PyUnicode_FromString(shortname); 241 | PyErr_SetImportError(message, shortname_obj, Py_None); 242 | Py_XDECREF(shortname_obj); 243 | Py_DECREF(message); 244 | } 245 | return NULL; 246 | } else { 247 | char buffer[256]; 248 | 249 | PyOS_snprintf(buffer, sizeof(buffer), 250 | #ifdef _DEBUG 251 | "python%d%d_d.dll", 252 | #else 253 | "python%d%d.dll", 254 | #endif 255 | PY_MAJOR_VERSION,PY_MINOR_VERSION); 256 | import_python = CBA_GetPythonImport(pModule); 257 | 258 | if (import_python && 259 | _stricmp(buffer,import_python)) { 260 | PyErr_Format(PyExc_ImportError, 261 | "Module use of %.150s conflicts " 262 | "with this version of Python.", 263 | import_python); 264 | Py_BEGIN_ALLOW_THREADS 265 | FreeLibraryResources(pModule); 266 | Py_END_ALLOW_THREADS 267 | return NULL; 268 | } 269 | } 270 | Py_BEGIN_ALLOW_THREADS 271 | p = _GetProcAddress(pModule, funcname); 272 | Py_END_ALLOW_THREADS 273 | } 274 | 275 | return p; 276 | } 277 | -------------------------------------------------------------------------------- /cba/cmoduleloader/python/cba_importdl.c: -------------------------------------------------------------------------------- 1 | 2 | /* Support for dynamic loading of extension modules */ 3 | 4 | #include "Python.h" 5 | 6 | /* ./configure sets HAVE_DYNAMIC_LOADING if dynamic loading of modules is 7 | supported on this platform. configure will then compile and link in one 8 | of the dynload_*.c files, as appropriate. We will call a function in 9 | those modules to get a function pointer to the module's init function. 10 | */ 11 | #ifdef HAVE_DYNAMIC_LOADING 12 | 13 | #include "importdl.h" 14 | #include "cba_importdl.h" 15 | 16 | #ifdef MS_WINDOWS 17 | extern dl_funcptr _PyImport_CBA_FindSharedFuncptrWindows(const char *prefix, 18 | const char *shortname, 19 | void * hModule, Py_ssize_t size); 20 | #else 21 | extern dl_funcptr _PyImport_CBA_FindSharedFuncptr(const char *prefix, 22 | const char *shortname, 23 | const char *pathname, void * hModule); 24 | #endif 25 | 26 | static const char * const ascii_only_prefix = "PyInit"; 27 | static const char * const nonascii_prefix = "PyInitU"; 28 | 29 | /* Get the variable part of a module's export symbol name. 30 | * Returns a bytes instance. For non-ASCII-named modules, the name is 31 | * encoded as per PEP 489. 32 | * The hook_prefix pointer is set to either ascii_only_prefix or 33 | * nonascii_prefix, as appropriate. 34 | */ 35 | static PyObject * 36 | get_encoded_name(PyObject *name, const char **hook_prefix) { 37 | PyObject *tmp; 38 | PyObject *encoded = NULL; 39 | PyObject *modname = NULL; 40 | Py_ssize_t name_len, lastdot; 41 | _Py_IDENTIFIER(replace); 42 | 43 | /* Get the short name (substring after last dot) */ 44 | name_len = PyUnicode_GetLength(name); 45 | lastdot = PyUnicode_FindChar(name, '.', 0, name_len, -1); 46 | if (lastdot < -1) { 47 | return NULL; 48 | } else if (lastdot >= 0) { 49 | tmp = PyUnicode_Substring(name, lastdot + 1, name_len); 50 | if (tmp == NULL) 51 | return NULL; 52 | name = tmp; 53 | /* "name" now holds a new reference to the substring */ 54 | } else { 55 | Py_INCREF(name); 56 | } 57 | 58 | /* Encode to ASCII or Punycode, as needed */ 59 | encoded = PyUnicode_AsEncodedString(name, "ascii", NULL); 60 | if (encoded != NULL) { 61 | *hook_prefix = ascii_only_prefix; 62 | } else { 63 | if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) { 64 | PyErr_Clear(); 65 | encoded = PyUnicode_AsEncodedString(name, "punycode", NULL); 66 | if (encoded == NULL) { 67 | goto error; 68 | } 69 | *hook_prefix = nonascii_prefix; 70 | } else { 71 | goto error; 72 | } 73 | } 74 | 75 | /* Replace '-' by '_' */ 76 | modname = _PyObject_CallMethodId(encoded, &PyId_replace, "cc", '-', '_'); 77 | if (modname == NULL) 78 | goto error; 79 | 80 | Py_DECREF(name); 81 | Py_DECREF(encoded); 82 | return modname; 83 | error: 84 | Py_DECREF(name); 85 | Py_XDECREF(encoded); 86 | return NULL; 87 | } 88 | 89 | PyObject * 90 | _PyImport_CBA_LoadDynamicModuleWithSpec(PyObject *spec, PyObject * data) 91 | { 92 | #ifndef MS_WINDOWS 93 | PyObject *pathbytes = NULL; 94 | #endif 95 | PyObject *name_unicode = NULL, *name = NULL, *m = NULL; 96 | const char *name_buf, *hook_prefix; 97 | const char *oldcontext; 98 | dl_funcptr exportfunc; 99 | PyModuleDef *def; 100 | PyObject *(*p0)(void); 101 | 102 | char *module_data = NULL; 103 | Py_ssize_t module_size; 104 | 105 | name_unicode = PyObject_GetAttrString(spec, "name"); 106 | if (name_unicode == NULL) { 107 | return NULL; 108 | } 109 | if (!PyUnicode_Check(name_unicode)) { 110 | PyErr_SetString(PyExc_TypeError, 111 | "spec.name must be a string"); 112 | goto error; 113 | } 114 | 115 | name = get_encoded_name(name_unicode, &hook_prefix); 116 | if (name == NULL) { 117 | goto error; 118 | } 119 | name_buf = PyBytes_AS_STRING(name); 120 | 121 | 122 | if (PySys_Audit("import", "OOOOO", name_unicode, Py_None, 123 | Py_None, Py_None, Py_None) < 0) { 124 | return NULL; 125 | } 126 | 127 | if (PyBytes_AsStringAndSize(data, &module_data, &module_size)) 128 | { 129 | goto error; 130 | } 131 | 132 | #ifdef MS_WINDOWS 133 | exportfunc = _PyImport_CBA_FindSharedFuncptrWindows(hook_prefix, name_buf, module_data, module_size); 134 | #else 135 | pathbytes = PyUnicode_EncodeFSDefault(path); 136 | if (pathbytes == NULL) 137 | goto error; 138 | exportfunc = _PyImport_FindSharedFuncptr(hook_prefix, name_buf, 139 | PyBytes_AS_STRING(pathbytes), 140 | fp); 141 | Py_DECREF(pathbytes); 142 | #endif 143 | 144 | if (exportfunc == NULL) { 145 | if (!PyErr_Occurred()) { 146 | PyObject *msg; 147 | msg = PyUnicode_FromFormat( 148 | "dynamic module does not define " 149 | "module export function (%s_%s)", 150 | hook_prefix, name_buf); 151 | if (msg == NULL) 152 | goto error; 153 | PyErr_SetImportError(msg, name_unicode, Py_None); 154 | Py_DECREF(msg); 155 | } 156 | goto error; 157 | } 158 | 159 | p0 = (PyObject *(*)(void))exportfunc; 160 | 161 | /* Package context is needed for single-phase init */ 162 | oldcontext = _Py_PackageContext; 163 | _Py_PackageContext = PyUnicode_AsUTF8(name_unicode); 164 | if (_Py_PackageContext == NULL) { 165 | _Py_PackageContext = oldcontext; 166 | goto error; 167 | } 168 | m = p0(); 169 | _Py_PackageContext = oldcontext; 170 | 171 | if (m == NULL) { 172 | if (!PyErr_Occurred()) { 173 | PyErr_Format( 174 | PyExc_SystemError, 175 | "initialization of %s failed without raising an exception", 176 | name_buf); 177 | } 178 | goto error; 179 | } else if (PyErr_Occurred()) { 180 | PyErr_Clear(); 181 | PyErr_Format( 182 | PyExc_SystemError, 183 | "initialization of %s raised unreported exception", 184 | name_buf); 185 | m = NULL; 186 | goto error; 187 | } 188 | if (Py_TYPE(m) == NULL) { 189 | /* This can happen when a PyModuleDef is returned without calling 190 | * PyModuleDef_Init on it 191 | */ 192 | PyErr_Format(PyExc_SystemError, 193 | "init function of %s returned uninitialized object", 194 | name_buf); 195 | m = NULL; /* prevent segfault in DECREF */ 196 | goto error; 197 | } 198 | if (PyObject_TypeCheck(m, &PyModuleDef_Type)) { 199 | Py_DECREF(name_unicode); 200 | Py_DECREF(name); 201 | return PyModule_FromDefAndSpec((PyModuleDef*)m, spec); 202 | } 203 | 204 | /* Fall back to single-phase init mechanism */ 205 | 206 | if (hook_prefix == nonascii_prefix) { 207 | /* don't allow legacy init for non-ASCII module names */ 208 | PyErr_Format( 209 | PyExc_SystemError, 210 | "initialization of * did not return PyModuleDef", 211 | name_buf); 212 | goto error; 213 | } 214 | 215 | /* Remember pointer to module init function. */ 216 | def = PyModule_GetDef(m); 217 | if (def == NULL) { 218 | PyErr_Format(PyExc_SystemError, 219 | "initialization of %s did not return an extension " 220 | "module", name_buf); 221 | goto error; 222 | } 223 | def->m_base.m_init = p0; 224 | 225 | /* Remember the filename as the __file__ attribute */ 226 | if (PyModule_AddObject(m, "__file__", Py_None) < 0) 227 | PyErr_Clear(); /* Not important enough to report */ 228 | 229 | PyObject *modules = PyImport_GetModuleDict(); 230 | if (_PyImport_FixupExtensionObject(m, name_unicode, Py_None, modules) < 0) 231 | goto error; 232 | 233 | Py_DECREF(name_unicode); 234 | Py_DECREF(name); 235 | 236 | return m; 237 | 238 | error: 239 | Py_DECREF(name_unicode); 240 | Py_XDECREF(name); 241 | Py_XDECREF(m); 242 | return NULL; 243 | } 244 | 245 | #endif /* HAVE_DYNAMIC_LOADING */ 246 | -------------------------------------------------------------------------------- /cba/cmoduleloader/python/cba_importdl.h: -------------------------------------------------------------------------------- 1 | #ifndef CBA_Py_IMPORTDL_H 2 | #define CBA_Py_IMPORTDL_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | extern PyObject *_PyImport_CBA_LoadDynamicModuleWithSpec(PyObject *spec, PyObject * data); 9 | 10 | 11 | #ifdef __cplusplus 12 | } 13 | #endif 14 | #endif /* !CBA_Py_IMPORTDL_H */ 15 | -------------------------------------------------------------------------------- /cba/cmoduleloader/python/cba_importinit.c: -------------------------------------------------------------------------------- 1 | /* Module definition and import implementation */ 2 | 3 | #include "Python.h" 4 | #include "pycore_pylifecycle.h" 5 | 6 | #include "cba_python38_lib.h" 7 | 8 | 9 | /* 10 | * Called by init_importlib_external; initialized immediately before _PyImportZip_Init. 11 | */ 12 | PyStatus _PyCBAImport_Init(PyInterpreterState* interp) 13 | { 14 | 15 | PyObject* cba_zipimport; 16 | int err = 0; 17 | 18 | int verbose = interp->config.verbose; 19 | if (verbose) { 20 | PySys_WriteStderr("# installing cba_zipimport hook\n"); 21 | } 22 | 23 | cba_zipimport = PyImport_ImportModule("cba_zipimport"); 24 | if (cba_zipimport == NULL) { 25 | PyErr_Clear(); /* No zip import module -- okay */ 26 | if (verbose) { 27 | PySys_WriteStderr("# can't import cba_zipimport\n"); 28 | } 29 | } 30 | else { 31 | _Py_IDENTIFIER(install_cba_metafinder); 32 | PyObject* install_cba_metafinder = _PyObject_GetAttrId(cba_zipimport, 33 | &PyId_install_cba_metafinder); 34 | Py_DECREF(cba_zipimport); 35 | if (install_cba_metafinder == NULL) { 36 | PyErr_Clear(); /* No zipimporter object -- okay */ 37 | if (verbose) { 38 | PySys_WriteStderr("# can't import cba_zipimport.install_cba_metafinder\n"); 39 | } 40 | } 41 | else { 42 | 43 | #if defined _M_ARM 44 | #error Building for ARM is not set up. 45 | #endif 46 | PyObject* ppyd_zip_name = PyUnicode_FromString("#cba_python38_pyd.zip"); 47 | PyObject* ppyd_zip_data = 48 | #ifdef _WIN64 49 | PyByteArray_FromStringAndSize((char*)_CBA_python38_pyd_win64, _CBA_python38_pyd_win64_size); 50 | #else 51 | PyByteArray_FromStringAndSize((char*)_CBA_python38_pyd_win32, _CBA_python38_pyd_win32_size); 52 | #endif 53 | PyObject* tmp_pyd = PyObject_CallFunction(install_cba_metafinder, "(OO)", ppyd_zip_name, ppyd_zip_data); 54 | Py_DECREF(ppyd_zip_name); 55 | Py_DECREF(ppyd_zip_data); 56 | Py_DECREF(tmp_pyd); 57 | 58 | 59 | PyObject* plib_zip_name = PyUnicode_FromString("#cba_python38_lib.zip"); 60 | PyObject* plib_zip_data = PyByteArray_FromStringAndSize((char*)_CBA_python38_lib, _CBA_python38_lib_size); 61 | PyObject* tmp = PyObject_CallFunction(install_cba_metafinder, "(OO)", plib_zip_name, plib_zip_data); 62 | Py_DECREF(plib_zip_name); 63 | Py_DECREF(plib_zip_data); 64 | Py_DECREF(tmp); 65 | 66 | 67 | Py_DECREF(install_cba_metafinder); 68 | 69 | if (err < 0) { 70 | goto error; 71 | } 72 | if (verbose) { 73 | PySys_WriteStderr("# installed cba_zipimport hook\n"); 74 | } 75 | 76 | } 77 | } 78 | 79 | return _PyStatus_OK(); 80 | 81 | error: 82 | PyErr_Print(); 83 | return _PyStatus_ERR("initializing zipimport failed"); 84 | } 85 | -------------------------------------------------------------------------------- /cba/cmoduleloader/python/cba_moduleloader.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farfella/in-memory-cpython/cf414bff256561f029553b3018d9609f36992223/cba/cmoduleloader/python/cba_moduleloader.c -------------------------------------------------------------------------------- /cba/cmoduleloader/python/cba_moduleloader.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2021 SCYTHE, Inc. 3 | 4 | Authors: 5 | Originally written by Benjamin Dagana. 6 | Updated by Ateeq Sharfuddin to support TLS. 7 | Updated by Jonathan Lim to support AMD64. 8 | Updated by Ateeq Sharfuddin to support in-memory Python embedding. 9 | 10 | Based on John Levine's "Loaders and Linkers" (ISBN: 1558604960). 11 | 12 | This software is provided 'as-is', without any express or implied 13 | warranty. In no event will the authors be held liable for any damages 14 | arising from the use of this software. 15 | 16 | Permission is granted to anyone to use this software for any purpose, 17 | including commercial applications, and to alter it and redistribute it 18 | freely, subject to the following restrictions: 19 | 20 | 1. The origin of this software must not be misrepresented; you must not 21 | claim that you wrote the original software. If you use this software 22 | in a product, an acknowledgment in the product documentation would be 23 | appreciated but is not required. 24 | 2. Altered source versions must be plainly marked as such, and must not be 25 | misrepresented as being the original software. 26 | 3. This notice may not be removed or altered from any source distribution. 27 | 28 | */ 29 | 30 | #ifndef __CUSTOM_MODULELOADER_H__ 31 | #define __CUSTOM_MODULELOADER_H__ 32 | 33 | #if defined (_MSC_VER) && (_MSC_VER >= 1020) 34 | #pragma once 35 | #endif 36 | 37 | #include 38 | 39 | typedef struct _LOADEDMODULE 40 | { 41 | PIMAGE_NT_HEADERS pHeaders; 42 | PBYTE pCodeBase; 43 | HINSTANCE * pModules; 44 | INT nModules; 45 | BOOL fInitialized; 46 | BOOL fRelocated; 47 | DWORD dwPageSize; 48 | } LOADEDMODULE, *PLOADEDMODULE; 49 | 50 | typedef PVOID HLOADEDMODULE; 51 | 52 | PLOADEDMODULE _LoadModuleFromInstance(HINSTANCE hInstance); 53 | __checkReturn __success(return != NULL) PLOADEDMODULE LoadModuleFromMemory(PVOID lpData, DWORD dwSize); 54 | FARPROC _GetProcAddress(PLOADEDMODULE pModule, LPCSTR FuncName); 55 | void FreeLibraryResources(PLOADEDMODULE pModule); 56 | __checkReturn __success(return == TRUE) BOOL IsPEHeaderValid(__in PVOID lpData, __in DWORD dwSize); 57 | PVOID _FindResource(PLOADEDMODULE module, LPCTSTR name, LPCTSTR type); 58 | LPVOID _LoadResource(PLOADEDMODULE module, PVOID resource); 59 | DWORD _SizeofResource(PLOADEDMODULE module, PVOID resource); 60 | 61 | // Section data from file header 62 | typedef struct _SECTIONDATA 63 | { 64 | LPVOID pAddress; 65 | LPVOID pAlignedAddress; 66 | uintptr_t Size; 67 | DWORD dwCharacteristics; 68 | BOOL fLast; 69 | } SECTIONDATA, *PSECTIONDATA; 70 | 71 | 72 | #define ARCHITECTURE_TYPE_X86 0x00000000 73 | #define ARCHITECTURE_TYPE_X64 0x00000001 74 | 75 | // MIN/MAX of address aligned 76 | #define MIN_ALIGNED(address, alignment) (LPVOID)((uintptr_t)(address) & ~((alignment) - 1)) 77 | #define MAX_ALIGNED(value, alignment) (((value) + (alignment) - 1) & ~((alignment) - 1)) 78 | 79 | typedef BOOL(WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); 80 | 81 | #define DEFAULT_LANGUAGE MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) 82 | 83 | #endif /* __CUSTOM_MODULELOADER_H__ */ -------------------------------------------------------------------------------- /cba/cmoduleloader/python/cba_python38_lib.h: -------------------------------------------------------------------------------- 1 | #ifndef __CBA_PYTHON38_LIB_H__ 2 | #define __CBA_PYTHON38_LIB_H__ 3 | 4 | #if defined (_MSC_VER) && (_MSC_VER >= 1020) 5 | #pragma once 6 | #endif 7 | 8 | extern const unsigned char _CBA_python38_lib[]; 9 | extern unsigned int _CBA_python38_lib_size; 10 | 11 | #ifdef MS_WINDOWS 12 | #ifdef _WIN64 13 | extern const unsigned char _CBA_python38_pyd_win64[]; 14 | extern unsigned int _CBA_python38_pyd_win64_size; 15 | #else /* WIN32 */ 16 | extern const unsigned char _CBA_python38_pyd_win32[]; 17 | extern unsigned int _CBA_python38_pyd_win32_size; 18 | #endif /* WIN32, _WIN64 */ 19 | 20 | #endif /* MS_WINDOWS*/ 21 | 22 | #endif /* __CBA_PYTHON38_LIB_H__ */ -------------------------------------------------------------------------------- /cba/cmoduleloader/python/cba_python38_pyd_win32.c: -------------------------------------------------------------------------------- 1 | /* Auto-generated by scripts/xxd.py */ 2 | const unsigned char _CBA_python38_pyd_win32[] = { 3 | 0x50,0x4B,0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 4 | 0x00,0x00,0x00,0x00,0x00,0x00,}; 5 | const unsigned int _CBA_python38_pyd_win32_size = 22; 6 | -------------------------------------------------------------------------------- /cba/cmoduleloader/python/cba_python38_pyd_win64.c: -------------------------------------------------------------------------------- 1 | /* Auto-generated by scripts/xxd.py */ 2 | const unsigned char _CBA_python38_pyd_win64[] = { 3 | 0x50,0x4B,0x05,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 4 | 0x00,0x00,0x00,0x00,0x00,0x00,}; 5 | const unsigned int _CBA_python38_pyd_win64_size = 22; 6 | -------------------------------------------------------------------------------- /cba/cmoduleloader/python/clinic/import.c.h: -------------------------------------------------------------------------------- 1 | /*[clinic input] 2 | preserve 3 | [clinic start generated code]*/ 4 | 5 | PyDoc_STRVAR(_imp_lock_held__doc__, 6 | "lock_held($module, /)\n" 7 | "--\n" 8 | "\n" 9 | "Return True if the import lock is currently held, else False.\n" 10 | "\n" 11 | "On platforms without threads, return False."); 12 | 13 | #define _IMP_LOCK_HELD_METHODDEF \ 14 | {"lock_held", (PyCFunction)_imp_lock_held, METH_NOARGS, _imp_lock_held__doc__}, 15 | 16 | static PyObject * 17 | _imp_lock_held_impl(PyObject *module); 18 | 19 | static PyObject * 20 | _imp_lock_held(PyObject *module, PyObject *Py_UNUSED(ignored)) 21 | { 22 | return _imp_lock_held_impl(module); 23 | } 24 | 25 | PyDoc_STRVAR(_imp_acquire_lock__doc__, 26 | "acquire_lock($module, /)\n" 27 | "--\n" 28 | "\n" 29 | "Acquires the interpreter\'s import lock for the current thread.\n" 30 | "\n" 31 | "This lock should be used by import hooks to ensure thread-safety when importing\n" 32 | "modules. On platforms without threads, this function does nothing."); 33 | 34 | #define _IMP_ACQUIRE_LOCK_METHODDEF \ 35 | {"acquire_lock", (PyCFunction)_imp_acquire_lock, METH_NOARGS, _imp_acquire_lock__doc__}, 36 | 37 | static PyObject * 38 | _imp_acquire_lock_impl(PyObject *module); 39 | 40 | static PyObject * 41 | _imp_acquire_lock(PyObject *module, PyObject *Py_UNUSED(ignored)) 42 | { 43 | return _imp_acquire_lock_impl(module); 44 | } 45 | 46 | PyDoc_STRVAR(_imp_release_lock__doc__, 47 | "release_lock($module, /)\n" 48 | "--\n" 49 | "\n" 50 | "Release the interpreter\'s import lock.\n" 51 | "\n" 52 | "On platforms without threads, this function does nothing."); 53 | 54 | #define _IMP_RELEASE_LOCK_METHODDEF \ 55 | {"release_lock", (PyCFunction)_imp_release_lock, METH_NOARGS, _imp_release_lock__doc__}, 56 | 57 | static PyObject * 58 | _imp_release_lock_impl(PyObject *module); 59 | 60 | static PyObject * 61 | _imp_release_lock(PyObject *module, PyObject *Py_UNUSED(ignored)) 62 | { 63 | return _imp_release_lock_impl(module); 64 | } 65 | 66 | PyDoc_STRVAR(_imp__fix_co_filename__doc__, 67 | "_fix_co_filename($module, code, path, /)\n" 68 | "--\n" 69 | "\n" 70 | "Changes code.co_filename to specify the passed-in file path.\n" 71 | "\n" 72 | " code\n" 73 | " Code object to change.\n" 74 | " path\n" 75 | " File path to use."); 76 | 77 | #define _IMP__FIX_CO_FILENAME_METHODDEF \ 78 | {"_fix_co_filename", (PyCFunction)(void(*)(void))_imp__fix_co_filename, METH_FASTCALL, _imp__fix_co_filename__doc__}, 79 | 80 | static PyObject * 81 | _imp__fix_co_filename_impl(PyObject *module, PyCodeObject *code, 82 | PyObject *path); 83 | 84 | static PyObject * 85 | _imp__fix_co_filename(PyObject *module, PyObject *const *args, Py_ssize_t nargs) 86 | { 87 | PyObject *return_value = NULL; 88 | PyCodeObject *code; 89 | PyObject *path; 90 | 91 | if (!_PyArg_CheckPositional("_fix_co_filename", nargs, 2, 2)) { 92 | goto exit; 93 | } 94 | if (!PyObject_TypeCheck(args[0], &PyCode_Type)) { 95 | _PyArg_BadArgument("_fix_co_filename", "argument 1", (&PyCode_Type)->tp_name, args[0]); 96 | goto exit; 97 | } 98 | code = (PyCodeObject *)args[0]; 99 | if (!PyUnicode_Check(args[1])) { 100 | _PyArg_BadArgument("_fix_co_filename", "argument 2", "str", args[1]); 101 | goto exit; 102 | } 103 | if (PyUnicode_READY(args[1]) == -1) { 104 | goto exit; 105 | } 106 | path = args[1]; 107 | return_value = _imp__fix_co_filename_impl(module, code, path); 108 | 109 | exit: 110 | return return_value; 111 | } 112 | 113 | PyDoc_STRVAR(_imp_create_builtin__doc__, 114 | "create_builtin($module, spec, /)\n" 115 | "--\n" 116 | "\n" 117 | "Create an extension module."); 118 | 119 | #define _IMP_CREATE_BUILTIN_METHODDEF \ 120 | {"create_builtin", (PyCFunction)_imp_create_builtin, METH_O, _imp_create_builtin__doc__}, 121 | 122 | PyDoc_STRVAR(_imp_extension_suffixes__doc__, 123 | "extension_suffixes($module, /)\n" 124 | "--\n" 125 | "\n" 126 | "Returns the list of file suffixes used to identify extension modules."); 127 | 128 | #define _IMP_EXTENSION_SUFFIXES_METHODDEF \ 129 | {"extension_suffixes", (PyCFunction)_imp_extension_suffixes, METH_NOARGS, _imp_extension_suffixes__doc__}, 130 | 131 | static PyObject * 132 | _imp_extension_suffixes_impl(PyObject *module); 133 | 134 | static PyObject * 135 | _imp_extension_suffixes(PyObject *module, PyObject *Py_UNUSED(ignored)) 136 | { 137 | return _imp_extension_suffixes_impl(module); 138 | } 139 | 140 | PyDoc_STRVAR(_imp_init_frozen__doc__, 141 | "init_frozen($module, name, /)\n" 142 | "--\n" 143 | "\n" 144 | "Initializes a frozen module."); 145 | 146 | #define _IMP_INIT_FROZEN_METHODDEF \ 147 | {"init_frozen", (PyCFunction)_imp_init_frozen, METH_O, _imp_init_frozen__doc__}, 148 | 149 | static PyObject * 150 | _imp_init_frozen_impl(PyObject *module, PyObject *name); 151 | 152 | static PyObject * 153 | _imp_init_frozen(PyObject *module, PyObject *arg) 154 | { 155 | PyObject *return_value = NULL; 156 | PyObject *name; 157 | 158 | if (!PyUnicode_Check(arg)) { 159 | _PyArg_BadArgument("init_frozen", "argument", "str", arg); 160 | goto exit; 161 | } 162 | if (PyUnicode_READY(arg) == -1) { 163 | goto exit; 164 | } 165 | name = arg; 166 | return_value = _imp_init_frozen_impl(module, name); 167 | 168 | exit: 169 | return return_value; 170 | } 171 | 172 | PyDoc_STRVAR(_imp_get_frozen_object__doc__, 173 | "get_frozen_object($module, name, /)\n" 174 | "--\n" 175 | "\n" 176 | "Create a code object for a frozen module."); 177 | 178 | #define _IMP_GET_FROZEN_OBJECT_METHODDEF \ 179 | {"get_frozen_object", (PyCFunction)_imp_get_frozen_object, METH_O, _imp_get_frozen_object__doc__}, 180 | 181 | static PyObject * 182 | _imp_get_frozen_object_impl(PyObject *module, PyObject *name); 183 | 184 | static PyObject * 185 | _imp_get_frozen_object(PyObject *module, PyObject *arg) 186 | { 187 | PyObject *return_value = NULL; 188 | PyObject *name; 189 | 190 | if (!PyUnicode_Check(arg)) { 191 | _PyArg_BadArgument("get_frozen_object", "argument", "str", arg); 192 | goto exit; 193 | } 194 | if (PyUnicode_READY(arg) == -1) { 195 | goto exit; 196 | } 197 | name = arg; 198 | return_value = _imp_get_frozen_object_impl(module, name); 199 | 200 | exit: 201 | return return_value; 202 | } 203 | 204 | PyDoc_STRVAR(_imp_is_frozen_package__doc__, 205 | "is_frozen_package($module, name, /)\n" 206 | "--\n" 207 | "\n" 208 | "Returns True if the module name is of a frozen package."); 209 | 210 | #define _IMP_IS_FROZEN_PACKAGE_METHODDEF \ 211 | {"is_frozen_package", (PyCFunction)_imp_is_frozen_package, METH_O, _imp_is_frozen_package__doc__}, 212 | 213 | static PyObject * 214 | _imp_is_frozen_package_impl(PyObject *module, PyObject *name); 215 | 216 | static PyObject * 217 | _imp_is_frozen_package(PyObject *module, PyObject *arg) 218 | { 219 | PyObject *return_value = NULL; 220 | PyObject *name; 221 | 222 | if (!PyUnicode_Check(arg)) { 223 | _PyArg_BadArgument("is_frozen_package", "argument", "str", arg); 224 | goto exit; 225 | } 226 | if (PyUnicode_READY(arg) == -1) { 227 | goto exit; 228 | } 229 | name = arg; 230 | return_value = _imp_is_frozen_package_impl(module, name); 231 | 232 | exit: 233 | return return_value; 234 | } 235 | 236 | PyDoc_STRVAR(_imp_is_builtin__doc__, 237 | "is_builtin($module, name, /)\n" 238 | "--\n" 239 | "\n" 240 | "Returns True if the module name corresponds to a built-in module."); 241 | 242 | #define _IMP_IS_BUILTIN_METHODDEF \ 243 | {"is_builtin", (PyCFunction)_imp_is_builtin, METH_O, _imp_is_builtin__doc__}, 244 | 245 | static PyObject * 246 | _imp_is_builtin_impl(PyObject *module, PyObject *name); 247 | 248 | static PyObject * 249 | _imp_is_builtin(PyObject *module, PyObject *arg) 250 | { 251 | PyObject *return_value = NULL; 252 | PyObject *name; 253 | 254 | if (!PyUnicode_Check(arg)) { 255 | _PyArg_BadArgument("is_builtin", "argument", "str", arg); 256 | goto exit; 257 | } 258 | if (PyUnicode_READY(arg) == -1) { 259 | goto exit; 260 | } 261 | name = arg; 262 | return_value = _imp_is_builtin_impl(module, name); 263 | 264 | exit: 265 | return return_value; 266 | } 267 | 268 | PyDoc_STRVAR(_imp_is_frozen__doc__, 269 | "is_frozen($module, name, /)\n" 270 | "--\n" 271 | "\n" 272 | "Returns True if the module name corresponds to a frozen module."); 273 | 274 | #define _IMP_IS_FROZEN_METHODDEF \ 275 | {"is_frozen", (PyCFunction)_imp_is_frozen, METH_O, _imp_is_frozen__doc__}, 276 | 277 | static PyObject * 278 | _imp_is_frozen_impl(PyObject *module, PyObject *name); 279 | 280 | static PyObject * 281 | _imp_is_frozen(PyObject *module, PyObject *arg) 282 | { 283 | PyObject *return_value = NULL; 284 | PyObject *name; 285 | 286 | if (!PyUnicode_Check(arg)) { 287 | _PyArg_BadArgument("is_frozen", "argument", "str", arg); 288 | goto exit; 289 | } 290 | if (PyUnicode_READY(arg) == -1) { 291 | goto exit; 292 | } 293 | name = arg; 294 | return_value = _imp_is_frozen_impl(module, name); 295 | 296 | exit: 297 | return return_value; 298 | } 299 | 300 | #if defined(HAVE_DYNAMIC_LOADING) 301 | // CBA 302 | PyDoc_STRVAR(_imp_create_dynamic_inmemory__doc__, 303 | "create_dynamic_inmemory($module, spec, file=, /)\n" 304 | "--\n" 305 | "\n" 306 | "Create an extension module in memory."); 307 | 308 | #define _IMP_CREATE_DYNAMIC_INMEMORY_METHODDEF \ 309 | {"create_dynamic_inmemory", (PyCFunction)(void(*)(void))_imp_create_dynamic_inmemory, METH_FASTCALL, _imp_create_dynamic_inmemory__doc__}, 310 | 311 | static PyObject* 312 | _imp_create_dynamic_inmemory_impl(PyObject* module, PyObject* spec, PyObject* data); 313 | 314 | static PyObject* 315 | _imp_create_dynamic_inmemory(PyObject* module, PyObject* const* args, Py_ssize_t nargs) 316 | { 317 | PyObject* return_value = NULL; 318 | PyObject* spec; 319 | PyObject* data; 320 | 321 | if (!_PyArg_CheckPositional("create_dynamic_inmemory", nargs, 2, 2)) { 322 | goto exit; 323 | } 324 | spec = args[0]; 325 | data = args[1]; 326 | 327 | return_value = _imp_create_dynamic_inmemory_impl(module, spec, data); 328 | 329 | exit: 330 | return return_value; 331 | } 332 | 333 | // CBA 334 | 335 | PyDoc_STRVAR(_imp_create_dynamic__doc__, 336 | "create_dynamic($module, spec, file=, /)\n" 337 | "--\n" 338 | "\n" 339 | "Create an extension module."); 340 | 341 | #define _IMP_CREATE_DYNAMIC_METHODDEF \ 342 | {"create_dynamic", (PyCFunction)(void(*)(void))_imp_create_dynamic, METH_FASTCALL, _imp_create_dynamic__doc__}, 343 | 344 | static PyObject * 345 | _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file); 346 | 347 | static PyObject * 348 | _imp_create_dynamic(PyObject *module, PyObject *const *args, Py_ssize_t nargs) 349 | { 350 | PyObject *return_value = NULL; 351 | PyObject *spec; 352 | PyObject *file = NULL; 353 | 354 | if (!_PyArg_CheckPositional("create_dynamic", nargs, 1, 2)) { 355 | goto exit; 356 | } 357 | spec = args[0]; 358 | if (nargs < 2) { 359 | goto skip_optional; 360 | } 361 | file = args[1]; 362 | skip_optional: 363 | return_value = _imp_create_dynamic_impl(module, spec, file); 364 | 365 | exit: 366 | return return_value; 367 | } 368 | 369 | #endif /* defined(HAVE_DYNAMIC_LOADING) */ 370 | 371 | #if defined(HAVE_DYNAMIC_LOADING) 372 | 373 | PyDoc_STRVAR(_imp_exec_dynamic__doc__, 374 | "exec_dynamic($module, mod, /)\n" 375 | "--\n" 376 | "\n" 377 | "Initialize an extension module."); 378 | 379 | #define _IMP_EXEC_DYNAMIC_METHODDEF \ 380 | {"exec_dynamic", (PyCFunction)_imp_exec_dynamic, METH_O, _imp_exec_dynamic__doc__}, 381 | 382 | static int 383 | _imp_exec_dynamic_impl(PyObject *module, PyObject *mod); 384 | 385 | static PyObject * 386 | _imp_exec_dynamic(PyObject *module, PyObject *mod) 387 | { 388 | PyObject *return_value = NULL; 389 | int _return_value; 390 | 391 | _return_value = _imp_exec_dynamic_impl(module, mod); 392 | if ((_return_value == -1) && PyErr_Occurred()) { 393 | goto exit; 394 | } 395 | return_value = PyLong_FromLong((long)_return_value); 396 | 397 | exit: 398 | return return_value; 399 | } 400 | 401 | #endif /* defined(HAVE_DYNAMIC_LOADING) */ 402 | 403 | PyDoc_STRVAR(_imp_exec_builtin__doc__, 404 | "exec_builtin($module, mod, /)\n" 405 | "--\n" 406 | "\n" 407 | "Initialize a built-in module."); 408 | 409 | #define _IMP_EXEC_BUILTIN_METHODDEF \ 410 | {"exec_builtin", (PyCFunction)_imp_exec_builtin, METH_O, _imp_exec_builtin__doc__}, 411 | 412 | static int 413 | _imp_exec_builtin_impl(PyObject *module, PyObject *mod); 414 | 415 | static PyObject * 416 | _imp_exec_builtin(PyObject *module, PyObject *mod) 417 | { 418 | PyObject *return_value = NULL; 419 | int _return_value; 420 | 421 | _return_value = _imp_exec_builtin_impl(module, mod); 422 | if ((_return_value == -1) && PyErr_Occurred()) { 423 | goto exit; 424 | } 425 | return_value = PyLong_FromLong((long)_return_value); 426 | 427 | exit: 428 | return return_value; 429 | } 430 | 431 | PyDoc_STRVAR(_imp_source_hash__doc__, 432 | "source_hash($module, /, key, source)\n" 433 | "--\n" 434 | "\n"); 435 | 436 | #define _IMP_SOURCE_HASH_METHODDEF \ 437 | {"source_hash", (PyCFunction)(void(*)(void))_imp_source_hash, METH_FASTCALL|METH_KEYWORDS, _imp_source_hash__doc__}, 438 | 439 | static PyObject * 440 | _imp_source_hash_impl(PyObject *module, long key, Py_buffer *source); 441 | 442 | static PyObject * 443 | _imp_source_hash(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) 444 | { 445 | PyObject *return_value = NULL; 446 | static const char * const _keywords[] = {"key", "source", NULL}; 447 | static _PyArg_Parser _parser = {NULL, _keywords, "source_hash", 0}; 448 | PyObject *argsbuf[2]; 449 | long key; 450 | Py_buffer source = {NULL, NULL}; 451 | 452 | args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); 453 | if (!args) { 454 | goto exit; 455 | } 456 | if (PyFloat_Check(args[0])) { 457 | PyErr_SetString(PyExc_TypeError, 458 | "integer argument expected, got float" ); 459 | goto exit; 460 | } 461 | key = PyLong_AsLong(args[0]); 462 | if (key == -1 && PyErr_Occurred()) { 463 | goto exit; 464 | } 465 | if (PyObject_GetBuffer(args[1], &source, PyBUF_SIMPLE) != 0) { 466 | goto exit; 467 | } 468 | if (!PyBuffer_IsContiguous(&source, 'C')) { 469 | _PyArg_BadArgument("source_hash", "argument 'source'", "contiguous buffer", args[1]); 470 | goto exit; 471 | } 472 | return_value = _imp_source_hash_impl(module, key, &source); 473 | 474 | exit: 475 | /* Cleanup for source */ 476 | if (source.obj) { 477 | PyBuffer_Release(&source); 478 | } 479 | 480 | return return_value; 481 | } 482 | 483 | #ifndef _IMP_CREATE_DYNAMIC_METHODDEF 484 | #define _IMP_CREATE_DYNAMIC_METHODDEF 485 | #endif /* !defined(_IMP_CREATE_DYNAMIC_METHODDEF) */ 486 | 487 | #ifndef _IMP_EXEC_DYNAMIC_METHODDEF 488 | #define _IMP_EXEC_DYNAMIC_METHODDEF 489 | #endif /* !defined(_IMP_EXEC_DYNAMIC_METHODDEF) */ 490 | /*[clinic end generated code: output=3dc495e9c64d944e input=a9049054013a1b77]*/ 491 | -------------------------------------------------------------------------------- /cba/cmoduleloader/python/frozen.c: -------------------------------------------------------------------------------- 1 | 2 | /* Dummy frozen modules initializer */ 3 | 4 | #include "Python.h" 5 | #include "importlib.h" 6 | #include "importlib_external.h" 7 | #include "importlib_zipimport.h" 8 | #include "cba_zipimport_frozen.h" 9 | 10 | /* In order to test the support for frozen modules, by default we 11 | define a single frozen module, __hello__. Loading it will print 12 | some famous words... */ 13 | 14 | /* To regenerate this data after the bytecode or marshal format has changed, 15 | go to ../Tools/freeze/ and freeze the flag.py file; then copy and paste 16 | the appropriate bytes from M___main__.c. */ 17 | 18 | static unsigned char M___hello__[] = { 19 | 227,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 20 | 0,2,0,0,0,64,0,0,0,115,16,0,0,0,100,0, 21 | 90,0,101,1,100,1,131,1,1,0,100,2,83,0,41,3, 22 | 84,122,12,72,101,108,108,111,32,119,111,114,108,100,33,78, 23 | 41,2,218,11,105,110,105,116,105,97,108,105,122,101,100,218, 24 | 5,112,114,105,110,116,169,0,114,3,0,0,0,114,3,0, 25 | 0,0,250,20,84,111,111,108,115,47,102,114,101,101,122,101, 26 | 47,102,108,97,103,46,112,121,218,8,60,109,111,100,117,108, 27 | 101,62,1,0,0,0,115,2,0,0,0,4,1, 28 | }; 29 | 30 | #define SIZE (int)sizeof(M___hello__) 31 | 32 | static const struct _frozen _PyImport_FrozenModules[] = { 33 | /* importlib */ 34 | {"_frozen_importlib", _Py_M__importlib_bootstrap, 35 | (int)sizeof(_Py_M__importlib_bootstrap)}, 36 | {"_frozen_importlib_external", _Py_M__importlib_bootstrap_external, 37 | (int)sizeof(_Py_M__importlib_bootstrap_external)}, 38 | {"cba_zipimport", _Py_M__cba_zipimport, (int)sizeof(_Py_M__cba_zipimport)}, 39 | {"zipimport", _Py_M__zipimport, 40 | (int)sizeof(_Py_M__zipimport)}, 41 | /* Test module */ 42 | {"__hello__", M___hello__, SIZE}, 43 | /* Test package (negative size indicates package-ness) */ 44 | {"__phello__", M___hello__, -SIZE}, 45 | {"__phello__.spam", M___hello__, SIZE}, 46 | {0, 0, 0} /* sentinel */ 47 | }; 48 | 49 | /* Embedding apps may change this pointer to point to their favorite 50 | collection of frozen modules: */ 51 | 52 | const struct _frozen *PyImport_FrozenModules = _PyImport_FrozenModules; 53 | -------------------------------------------------------------------------------- /cba/settings/_ctypes.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | ARM64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | Debug 18 | x64 19 | 20 | 21 | PGInstrument 22 | ARM 23 | 24 | 25 | PGInstrument 26 | ARM64 27 | 28 | 29 | PGInstrument 30 | Win32 31 | 32 | 33 | PGInstrument 34 | x64 35 | 36 | 37 | PGUpdate 38 | ARM 39 | 40 | 41 | PGUpdate 42 | ARM64 43 | 44 | 45 | PGUpdate 46 | Win32 47 | 48 | 49 | PGUpdate 50 | x64 51 | 52 | 53 | Release 54 | ARM 55 | 56 | 57 | Release 58 | ARM64 59 | 60 | 61 | Release 62 | Win32 63 | 64 | 65 | Release 66 | x64 67 | 68 | 69 | 70 | {0E9791DB-593A-465F-98BC-681011311618} 71 | _ctypes 72 | Win32Proj 73 | 74 | 75 | 76 | 77 | DynamicLibrary 78 | NotSet 79 | 80 | 81 | 82 | .pyd 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | <_ProjectFileVersion>10.0.40219.1 94 | 95 | 96 | 97 | FFI_BUILDING;%(PreprocessorDefinitions) 98 | 99 | 100 | /EXPORT:DllGetClassObject,PRIVATE /EXPORT:DllCanUnloadNow,PRIVATE %(AdditionalOptions) 101 | false 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | {cf7ac3d1-e2df-41d2-bea6-1e2556cdea26} 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /cba/settings/_hashlib.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | ARM64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | Debug 18 | x64 19 | 20 | 21 | PGInstrument 22 | ARM 23 | 24 | 25 | PGInstrument 26 | ARM64 27 | 28 | 29 | PGInstrument 30 | Win32 31 | 32 | 33 | PGInstrument 34 | x64 35 | 36 | 37 | PGUpdate 38 | ARM 39 | 40 | 41 | PGUpdate 42 | ARM64 43 | 44 | 45 | PGUpdate 46 | Win32 47 | 48 | 49 | PGUpdate 50 | x64 51 | 52 | 53 | Release 54 | ARM 55 | 56 | 57 | Release 58 | ARM64 59 | 60 | 61 | Release 62 | Win32 63 | 64 | 65 | Release 66 | x64 67 | 68 | 69 | 70 | {447F05A8-F581-4CAC-A466-5AC7936E207E} 71 | _hashlib 72 | Win32Proj 73 | 74 | 75 | 76 | 77 | DynamicLibrary 78 | NotSet 79 | 80 | 81 | 82 | .pyd 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | <_ProjectFileVersion>10.0.30319.1 94 | 95 | 96 | 97 | ws2_32.lib;crypt32.lib;%(AdditionalDependencies) 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | {cf7ac3d1-e2df-41d2-bea6-1e2556cdea26} 109 | false 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /cba/settings/libffi.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $(libffiIncludeDir);%(AdditionalIncludeDirectories) 6 | 7 | 8 | $(libffiOutDir);%(AdditionalLibraryDirectories) 9 | libffi-7.lib;%(AdditionalDependencies) 10 | 11 | 12 | 13 | <_LIBFFIDLL Include="$(libffiOutDir)\libffi-7.dll" /> 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /cba/settings/openssl.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $(opensslIncludeDir);%(AdditionalIncludeDirectories) 6 | 7 | 8 | $(opensslOutDir);%(AdditionalLibraryDirectories) 9 | ws2_32.lib;libcrypto.lib;libssl.lib;%(AdditionalDependencies) 10 | 11 | 12 | 13 | <_DLLSuffix>-1_1 14 | <_DLLSuffix Condition="$(Platform) == 'ARM'">$(_DLLSuffix)-arm 15 | <_DLLSuffix Condition="$(Platform) == 'ARM64'">$(_DLLSuffix)-arm64 16 | 17 | 18 | <_SSLDLL Include="$(opensslOutDir)\libcrypto$(_DLLSuffix).dll" /> 19 | <_SSLDLL Include="$(opensslOutDir)\libcrypto$(_DLLSuffix).pdb" /> 20 | <_SSLDLL Include="$(opensslOutDir)\libssl$(_DLLSuffix).dll" /> 21 | <_SSLDLL Include="$(opensslOutDir)\libssl$(_DLLSuffix).pdb" /> 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /cba/settings/python.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <__Python_Props_Imported>true 5 | Win32 6 | Release 7 | 14 | v142 15 | v141 16 | v140 17 | v120 18 | v110 19 | v100 20 | 21 | $(BasePlatformToolset) 22 | false 23 | true 24 | 25 | 29 | amd64 30 | arm32 31 | arm64 32 | win32 33 | 34 | 35 | $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\)) 36 | $(PySourcePath)\ 37 | 38 | 39 | $(PySourcePath)PCbuild\win32\ 40 | $(Py_OutDir)\win32\ 41 | $(PySourcePath)PCbuild\amd64\ 42 | $(Py_OutDir)\amd64\ 43 | $(PySourcePath)PCbuild\arm32\ 44 | $(Py_OutDir)\arm32\ 45 | $(PySourcePath)PCbuild\arm64\ 46 | $(Py_OutDir)\arm64\ 47 | $(BuildPath32) 48 | $(BuildPath64) 49 | $(BuildPathArm32) 50 | $(BuildPathArm64) 51 | $(PySourcePath)PCbuild\$(ArchName)\ 52 | $(BuildPath)\ 53 | $(BuildPath)instrumented\ 54 | 55 | 56 | $(EXTERNALS_DIR) 57 | $([System.IO.Path]::GetFullPath(`$(PySourcePath)externals`)) 58 | $(ExternalsDir)\ 59 | $(ExternalsDir)sqlite-3.28.0.0\ 60 | $(ExternalsDir)bzip2-1.0.6\ 61 | $(ExternalsDir)xz-5.2.2\ 62 | $(ExternalsDir)libffi\ 63 | $(ExternalsDir)libffi\$(ArchName)\ 64 | $(libffiOutDir)include 65 | $(ExternalsDir)openssl-1.1.1g\ 66 | $(ExternalsDir)openssl-bin-1.1.1g\$(ArchName)\ 67 | $(opensslOutDir)include 68 | $(ExternalsDir)\nasm-2.11.06\ 69 | $(ExternalsDir)\zlib-1.2.11\ 70 | 71 | 72 | _d 73 | 74 | 75 | -test 76 | 77 | 78 | -32 79 | -arm32 80 | -arm64 81 | 82 | 83 | $(BuildPath)python$(PyDebugExt).exe 84 | 85 | 86 | true 87 | 88 | 89 | 90 | true 91 | 92 | 93 | 94 | true 95 | 96 | 97 | 98 | 104 | <_RegistryVersion>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion) 105 | <_RegistryVersion Condition="$(_RegistryVersion) == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion) 106 | 107 | <_RegistryVersion Condition="$(_RegistryVersion) != '' and !$(_RegistryVersion.EndsWith('.0'))">$(_RegistryVersion).0 108 | 109 | 110 | 10.0.10586.0 111 | $(_RegistryVersion) 112 | 113 | 114 | 115 | $(DefaultWindowsSDKVersion) 116 | 117 | 118 | 119 | 133 | <_PatchLevelContent>$([System.IO.File]::ReadAllText(`$(PySourcePath)Include\patchlevel.h`)) 134 | $([System.Text.RegularExpressions.Regex]::Match($(_PatchLevelContent), `define\s+PY_MAJOR_VERSION\s+(\d+)`).Groups[1].Value) 135 | $([System.Text.RegularExpressions.Regex]::Match($(_PatchLevelContent), `define\s+PY_MINOR_VERSION\s+(\d+)`).Groups[1].Value) 136 | $([System.Text.RegularExpressions.Regex]::Match($(_PatchLevelContent), `define\s+PY_MICRO_VERSION\s+(\d+)`).Groups[1].Value) 137 | <_ReleaseLevel>$([System.Text.RegularExpressions.Regex]::Match($(_PatchLevelContent), `define\s+PY_RELEASE_LEVEL\s+PY_RELEASE_LEVEL_(\w+)`).Groups[1].Value) 138 | $([System.Text.RegularExpressions.Regex]::Match($(_PatchLevelContent), `define\s+PY_RELEASE_SERIAL\s+(\d+)`).Groups[1].Value) 139 | 15 140 | 10 141 | 11 142 | 12 143 | a$(ReleaseSerial) 144 | b$(ReleaseSerial) 145 | rc$(ReleaseSerial) 146 | 147 | 148 | 149 | 166 | $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[1].Value) 167 | $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[2].Value) 168 | $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[3].Value) 169 | $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[4].Value) 170 | <_ReleaseLevel>$([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[5].Value) 171 | $([System.Text.RegularExpressions.Regex]::Match($(OverrideVersion), `(\d+)\.(\d+)\.(\d+)((a|b|rc)(\d))?`).Groups[6].Value) 172 | 0 173 | 15 174 | 10 175 | 11 176 | 12 177 | 178 | 179 | 180 | $(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber) 181 | $(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)$(ReleaseLevelName) 182 | $([msbuild]::BitwiseOr( 183 | $([msbuild]::Multiply($(MajorVersionNumber), 16777216)), 184 | $([msbuild]::BitwiseOr( 185 | $([msbuild]::Multiply($(MinorVersionNumber), 65536)), 186 | $([msbuild]::BitwiseOr( 187 | $([msbuild]::Multiply($(MicroVersionNumber), 256)), 188 | $([msbuild]::BitwiseOr( 189 | $([msbuild]::Multiply($(ReleaseLevelNumber), 16)), 190 | $(ReleaseSerial) 191 | )) 192 | )) 193 | )) 194 | )) 195 | $([msbuild]::Add( 196 | $(ReleaseSerial), 197 | $([msbuild]::Add( 198 | $([msbuild]::Multiply($(ReleaseLevelNumber), 10)), 199 | $([msbuild]::Multiply($(MicroVersionNumber), 1000)) 200 | )) 201 | )) 202 | $([msbuild]::Add($(Field3Value), 9000)) 203 | 204 | 205 | python$(MajorVersionNumber)$(MinorVersionNumber)$(PyDebugExt) 206 | 207 | 208 | .cp$(MajorVersionNumber)$(MinorVersionNumber)-win32 209 | .cp$(MajorVersionNumber)$(MinorVersionNumber)-win_arm32 210 | .cp$(MajorVersionNumber)$(MinorVersionNumber)-win_arm64 211 | .cp$(MajorVersionNumber)$(MinorVersionNumber)-win_amd64 212 | 213 | 214 | $(MajorVersionNumber).$(MinorVersionNumber)$(PyArchExt)$(PyTestExt) 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /cba/settings/pythoncore.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | ARM64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | Debug 18 | x64 19 | 20 | 21 | PGInstrument 22 | ARM 23 | 24 | 25 | PGInstrument 26 | ARM64 27 | 28 | 29 | PGInstrument 30 | Win32 31 | 32 | 33 | PGInstrument 34 | x64 35 | 36 | 37 | PGUpdate 38 | ARM 39 | 40 | 41 | PGUpdate 42 | ARM64 43 | 44 | 45 | PGUpdate 46 | Win32 47 | 48 | 49 | PGUpdate 50 | x64 51 | 52 | 53 | Release 54 | ARM 55 | 56 | 57 | Release 58 | ARM64 59 | 60 | 61 | Release 62 | Win32 63 | 64 | 65 | Release 66 | x64 67 | 68 | 69 | 70 | {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} 71 | pythoncore 72 | 73 | 74 | 75 | 76 | DynamicLibrary 77 | false 78 | 79 | 80 | 81 | 82 | 83 | true 84 | true 85 | true 86 | false 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | <_ProjectFileVersion>10.0.30319.1 95 | $(PyDllName) 96 | 97 | 98 | Link 99 | 100 | 101 | 102 | /Zm200 %(AdditionalOptions) 103 | $(PySourcePath)Python;%(AdditionalIncludeDirectories) 104 | $(zlibDir);%(AdditionalIncludeDirectories) 105 | _USRDLL;Py_BUILD_CORE;Py_BUILD_CORE_BUILTIN;Py_ENABLE_SHARED;MS_DLL_ID="$(SysWinVer)";%(PreprocessorDefinitions) 106 | _Py_HAVE_ZLIB;%(PreprocessorDefinitions) 107 | 108 | 109 | version.lib;shlwapi.lib;ws2_32.lib;%(AdditionalDependencies) 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | true 424 | true 425 | true 426 | true 427 | 428 | 429 | true 430 | true 431 | true 432 | true 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | git 516 | <_GIT>$(GIT) 517 | <_GIT Condition="$(GIT.Contains(` `))">"$(GIT)" 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | $([System.IO.File]::ReadAllText('$(IntDir)gitbranch.txt').Trim()) 526 | $([System.IO.File]::ReadAllText('$(IntDir)gitversion.txt').Trim()) 527 | $([System.IO.File]::ReadAllText('$(IntDir)gittag.txt').Trim()) 528 | 529 | 530 | 531 | 532 | GITVERSION="$(GitVersion)";GITTAG="$(GitTag)";GITBRANCH="$(GitBranch)";%(PreprocessorDefinitions) 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | $(VCInstallDir)\Redist\MSVC\$(VCToolsRedistVersion)\ 544 | $(VCRedistDir)x86\ 545 | $(VCRedistDir)$(Platform)\ 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | -------------------------------------------------------------------------------- /cba/settings/sqlite3.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | ARM64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | Debug 18 | x64 19 | 20 | 21 | PGInstrument 22 | ARM 23 | 24 | 25 | PGInstrument 26 | ARM64 27 | 28 | 29 | PGInstrument 30 | Win32 31 | 32 | 33 | PGInstrument 34 | x64 35 | 36 | 37 | PGUpdate 38 | ARM 39 | 40 | 41 | PGUpdate 42 | ARM64 43 | 44 | 45 | PGUpdate 46 | Win32 47 | 48 | 49 | PGUpdate 50 | x64 51 | 52 | 53 | Release 54 | ARM 55 | 56 | 57 | Release 58 | ARM64 59 | 60 | 61 | Release 62 | Win32 63 | 64 | 65 | Release 66 | x64 67 | 68 | 69 | 70 | {A1A295E5-463C-437F-81CA-1F32367685DA} 71 | sqlite3 72 | .pyd 73 | false 74 | $(DefaultWindowsSDKVersion) 75 | 76 | 77 | 78 | 79 | StaticLibrary 80 | NotSet 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | <_ProjectFileVersion>10.0.30319.1 92 | <_SqliteVersion>$([System.Text.RegularExpressions.Regex]::Match(`$(sqlite3Dir)`, `((\d+)\.(\d+)\.(\d+)\.(\d+))\\?$`).Groups) 93 | $(_SqliteVersion.Split(`;`)[1]) 94 | $(_SqliteVersion.Split(`;`)[2]) 95 | $(_SqliteVersion.Split(`;`)[3]) 96 | $(_SqliteVersion.Split(`;`)[4]) 97 | $(_SqliteVersion.Split(`;`)[5]) 98 | 99 | 100 | 101 | $(sqlite3Dir);%(AdditionalIncludeDirectories) 102 | SQLITE_ENABLE_FTS4;SQLITE_ENABLE_FTS5;SQLITE_API=__declspec(dllexport);%(PreprocessorDefinitions) 103 | Level1 104 | 105 | 106 | SQLITE_VERSION=$(SqliteVersion);SQLITE_MAJOR_VERSION=$(SqliteMajorVersion);SQLITE_MINOR_VERSION=$(SqliteMinorVersion);SQLITE_MICRO_VERSION=$(SqliteMicroVersion);SQLITE_PATCH_VERSION=$(SqlitePatchVersion);%(PreprocessorDefinitions) 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /libffi_code/libffi.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farfella/in-memory-cpython/cf414bff256561f029553b3018d9609f36992223/libffi_code/libffi.zip -------------------------------------------------------------------------------- /openssl-1.1.1g.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farfella/in-memory-cpython/cf414bff256561f029553b3018d9609f36992223/openssl-1.1.1g.tar.gz -------------------------------------------------------------------------------- /scripts/untar.py: -------------------------------------------------------------------------------- 1 | import tarfile 2 | import sys 3 | 4 | if __name__ == "__main__": 5 | if len(sys.argv) < 2: 6 | print("Usage: untar path") 7 | else: 8 | fname = sys.argv[1] 9 | if fname.endswith("tar.gz") or fname.endswith("tgz"): 10 | tar = tarfile.open(fname, "r:gz") 11 | tar.extractall() 12 | tar.close() -------------------------------------------------------------------------------- /scripts/xxd.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from functools import partial 3 | 4 | def xxd(variable, file_path): 5 | """ 6 | Convert binary file into a C-array 7 | 8 | :param str variable: 9 | :param str file_path: 10 | :return None: 11 | 12 | """ 13 | print("/* Auto-generated by scripts/xxd.py */") 14 | print("const unsigned char _CBA_%s[] = {" % variable) 15 | n = 0 16 | with open(file_path, "rb") as in_file: 17 | for c in iter(partial(in_file.read, 1), b''): 18 | print("0x%02X," % ord(c), end='') 19 | n += 1 20 | if n % 16 == 0: 21 | print("") 22 | print("};") 23 | print("const unsigned int _CBA_%s_size = %d;" % (variable, n)) 24 | 25 | if __name__ == "__main__": 26 | if len(sys.argv) < 3: 27 | sys.exit('Usage: %s variable file' % sys.argv[0]) 28 | else: 29 | xxd(sys.argv[1], sys.argv[2]) -------------------------------------------------------------------------------- /scripts/zip_folder.py: -------------------------------------------------------------------------------- 1 | import zipfile 2 | import sys 3 | import os 4 | 5 | def zipdir(path, ziph): 6 | # ziph is zipfile handle 7 | curdir = os.curdir 8 | os.chdir(os.path.join(curdir, path)) 9 | print(curdir) 10 | print(os.curdir) 11 | for root, dirs, files in os.walk(os.curdir): 12 | for file in files: 13 | ziph.write(os.path.join(root, file)) 14 | os.chdir(curdir) 15 | 16 | if __name__ == '__main__': 17 | if len(sys.argv) < 3: 18 | print("Usage: %s achivePath folderToArchive") 19 | else: 20 | zipf = zipfile.ZipFile(sys.argv[2], 'w', zipfile.ZIP_DEFLATED) 21 | zipdir(sys.argv[1], zipf) 22 | zipf.close() -------------------------------------------------------------------------------- /zlib-1.2.11.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/farfella/in-memory-cpython/cf414bff256561f029553b3018d9609f36992223/zlib-1.2.11.tar.gz -------------------------------------------------------------------------------- /zlib-patch/zlibstat.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Itanium 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | ReleaseWithoutAsm 18 | Itanium 19 | 20 | 21 | ReleaseWithoutAsm 22 | Win32 23 | 24 | 25 | ReleaseWithoutAsm 26 | x64 27 | 28 | 29 | Release 30 | Itanium 31 | 32 | 33 | Release 34 | Win32 35 | 36 | 37 | Release 38 | x64 39 | 40 | 41 | 42 | {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8} 43 | 44 | 45 | 46 | StaticLibrary 47 | false 48 | v142 49 | 50 | 51 | StaticLibrary 52 | false 53 | v142 54 | 55 | 56 | StaticLibrary 57 | false 58 | v142 59 | Unicode 60 | 61 | 62 | StaticLibrary 63 | false 64 | v142 65 | 66 | 67 | StaticLibrary 68 | false 69 | v142 70 | 71 | 72 | StaticLibrary 73 | false 74 | v142 75 | 76 | 77 | StaticLibrary 78 | false 79 | v142 80 | 81 | 82 | StaticLibrary 83 | false 84 | v142 85 | 86 | 87 | StaticLibrary 88 | false 89 | v142 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | <_ProjectFileVersion>10.0.30128.1 124 | x86\ZlibStat$(Configuration)\ 125 | x86\ZlibStat$(Configuration)\Tmp\ 126 | x86\ZlibStat$(Configuration)\ 127 | x86\ZlibStat$(Configuration)\Tmp\ 128 | x86\ZlibStat$(Configuration)\ 129 | x86\ZlibStat$(Configuration)\Tmp\ 130 | x64\ZlibStat$(Configuration)\ 131 | x64\ZlibStat$(Configuration)\Tmp\ 132 | ia64\ZlibStat$(Configuration)\ 133 | ia64\ZlibStat$(Configuration)\Tmp\ 134 | x64\ZlibStat$(Configuration)\ 135 | x64\ZlibStat$(Configuration)\Tmp\ 136 | ia64\ZlibStat$(Configuration)\ 137 | ia64\ZlibStat$(Configuration)\Tmp\ 138 | x64\ZlibStat$(Configuration)\ 139 | x64\ZlibStat$(Configuration)\Tmp\ 140 | ia64\ZlibStat$(Configuration)\ 141 | ia64\ZlibStat$(Configuration)\Tmp\ 142 | AllRules.ruleset 143 | 144 | 145 | AllRules.ruleset 146 | 147 | 148 | AllRules.ruleset 149 | 150 | 151 | AllRules.ruleset 152 | 153 | 154 | AllRules.ruleset 155 | 156 | 157 | AllRules.ruleset 158 | 159 | 160 | AllRules.ruleset 161 | 162 | 163 | AllRules.ruleset 164 | 165 | 166 | AllRules.ruleset 167 | 168 | 169 | 170 | 171 | 172 | Disabled 173 | ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) 174 | WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) 175 | 176 | 177 | MultiThreadedDebugDLL 178 | false 179 | $(IntDir)zlibstat.pch 180 | $(IntDir) 181 | $(IntDir) 182 | $(OutDir) 183 | Level3 184 | true 185 | OldStyle 186 | 187 | 188 | 0x040c 189 | 190 | 191 | /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) 192 | $(OutDir)zlibstat.lib 193 | true 194 | 195 | 196 | 197 | 198 | OnlyExplicitInline 199 | ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) 200 | WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;%(PreprocessorDefinitions) 201 | true 202 | 203 | 204 | MultiThreaded 205 | false 206 | true 207 | $(IntDir)zlibstat.pch 208 | $(IntDir) 209 | $(IntDir) 210 | $(OutDir) 211 | Level3 212 | true 213 | 214 | 215 | 0x040c 216 | 217 | 218 | /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) 219 | ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) 220 | $(OutDir)zlibstat.lib 221 | true 222 | 223 | 224 | 225 | 226 | OnlyExplicitInline 227 | ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) 228 | WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) 229 | true 230 | 231 | 232 | MultiThreaded 233 | false 234 | true 235 | $(IntDir)zlibstat.pch 236 | $(IntDir) 237 | $(IntDir) 238 | $(OutDir) 239 | Level3 240 | true 241 | 242 | 243 | 0x040c 244 | 245 | 246 | /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) 247 | $(OutDir)zlibstat.lib 248 | true 249 | 250 | 251 | 252 | 253 | X64 254 | 255 | 256 | Disabled 257 | ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) 258 | ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) 259 | 260 | 261 | MultiThreadedDebugDLL 262 | false 263 | $(IntDir)zlibstat.pch 264 | $(IntDir) 265 | $(IntDir) 266 | $(OutDir) 267 | Level3 268 | true 269 | OldStyle 270 | 271 | 272 | 0x040c 273 | 274 | 275 | /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) 276 | $(OutDir)zlibstat.lib 277 | true 278 | 279 | 280 | 281 | 282 | Itanium 283 | 284 | 285 | Disabled 286 | ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) 287 | ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) 288 | 289 | 290 | MultiThreadedDebugDLL 291 | false 292 | $(IntDir)zlibstat.pch 293 | $(IntDir) 294 | $(IntDir) 295 | $(OutDir) 296 | Level3 297 | true 298 | OldStyle 299 | 300 | 301 | 0x040c 302 | 303 | 304 | /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) 305 | $(OutDir)zlibstat.lib 306 | true 307 | 308 | 309 | 310 | 311 | X64 312 | 313 | 314 | OnlyExplicitInline 315 | ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) 316 | ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) 317 | true 318 | 319 | 320 | MultiThreadedDLL 321 | false 322 | true 323 | $(IntDir)zlibstat.pch 324 | $(IntDir) 325 | $(IntDir) 326 | $(OutDir) 327 | Level3 328 | true 329 | 330 | 331 | 0x040c 332 | 333 | 334 | /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) 335 | ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) 336 | $(OutDir)zlibstat.lib 337 | true 338 | 339 | 340 | 341 | 342 | Itanium 343 | 344 | 345 | OnlyExplicitInline 346 | ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) 347 | ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) 348 | true 349 | 350 | 351 | MultiThreadedDLL 352 | false 353 | true 354 | $(IntDir)zlibstat.pch 355 | $(IntDir) 356 | $(IntDir) 357 | $(OutDir) 358 | Level3 359 | true 360 | 361 | 362 | 0x040c 363 | 364 | 365 | /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) 366 | $(OutDir)zlibstat.lib 367 | true 368 | 369 | 370 | 371 | 372 | X64 373 | 374 | 375 | OnlyExplicitInline 376 | ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) 377 | ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) 378 | true 379 | 380 | 381 | MultiThreadedDLL 382 | false 383 | true 384 | $(IntDir)zlibstat.pch 385 | $(IntDir) 386 | $(IntDir) 387 | $(OutDir) 388 | Level3 389 | true 390 | 391 | 392 | 0x040c 393 | 394 | 395 | /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) 396 | $(OutDir)zlibstat.lib 397 | true 398 | 399 | 400 | 401 | 402 | Itanium 403 | 404 | 405 | OnlyExplicitInline 406 | ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) 407 | ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) 408 | true 409 | 410 | 411 | MultiThreadedDLL 412 | false 413 | true 414 | $(IntDir)zlibstat.pch 415 | $(IntDir) 416 | $(IntDir) 417 | $(OutDir) 418 | Level3 419 | true 420 | 421 | 422 | 0x040c 423 | 424 | 425 | /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) 426 | $(OutDir)zlibstat.lib 427 | true 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | true 442 | true 443 | true 444 | true 445 | true 446 | true 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | --------------------------------------------------------------------------------