From 660249a5cc4e0d8a5f2b128486bde6aeca63d36c Mon Sep 17 00:00:00 2001 From: Mitchell Stokes Date: Tue, 10 Sep 2019 16:37:01 +0200 Subject: [PATCH] Remove p3d/AppRunner/plugin system Co-authored-by: rdb Closes #734 --- direct/src/directscripts/DetectPanda3D.js | 99 - direct/src/directscripts/RunPanda3D.js | 132 - direct/src/dist/commands.py | 2 +- direct/src/dist/icon.py | 269 + direct/src/p3d/AppRunner.py | 1245 ---- direct/src/p3d/DWBPackageInstaller.py | 96 - direct/src/p3d/DeploymentTools.py | 1496 ---- direct/src/p3d/FileSpec.py | 246 - direct/src/p3d/HostInfo.py | 751 -- direct/src/p3d/InstalledHostData.py | 24 - direct/src/p3d/InstalledPackageData.py | 30 - direct/src/p3d/JavaScript.py | 298 - direct/src/p3d/PackageInfo.py | 1237 ---- direct/src/p3d/PackageInstaller.py | 640 -- direct/src/p3d/PackageMerger.py | 306 - direct/src/p3d/Packager.py | 3962 ----------- direct/src/p3d/PatchMaker.py | 814 --- direct/src/p3d/ScanDirectoryNode.py | 95 - direct/src/p3d/SeqValue.py | 90 - direct/src/p3d/__init__.py | 4 - direct/src/p3d/coreapi.pdef | 124 - direct/src/p3d/p3dWrapper.c | 127 - direct/src/p3d/packp3d.py | 241 - direct/src/p3d/panda3d.pdef | 518 -- direct/src/p3d/pdeploy.py | 359 - direct/src/p3d/pmerge.py | 106 - direct/src/p3d/ppackage.py | 267 - direct/src/p3d/ppatcher.py | 101 - direct/src/p3d/runp3d.py | 79 - direct/src/p3d/thirdparty.pdef | 167 - direct/src/plugin/binaryXml.cxx | 351 - direct/src/plugin/binaryXml.h | 29 - direct/src/plugin/failed.pgm | Bin 2304 -> 0 bytes direct/src/plugin/failed.xcf | Bin 450078 -> 0 bytes direct/src/plugin/fhandle.h | 31 - direct/src/plugin/fileSpec.I | 102 - direct/src/plugin/fileSpec.cxx | 486 -- direct/src/plugin/fileSpec.h | 78 - direct/src/plugin/find_root_dir.cxx | 311 - direct/src/plugin/find_root_dir.h | 26 - direct/src/plugin/find_root_dir_assist.mm | 87 - direct/src/plugin/get_tinyxml.h | 27 - direct/src/plugin/get_twirl_data.cxx | 963 --- direct/src/plugin/get_twirl_data.h | 27 - direct/src/plugin/handleStream.I | 88 - direct/src/plugin/handleStream.cxx | 14 - direct/src/plugin/handleStream.h | 43 - direct/src/plugin/handleStreamBuf.I | 31 - direct/src/plugin/handleStreamBuf.cxx | 342 - direct/src/plugin/handleStreamBuf.h | 60 - direct/src/plugin/is_pathsep.I | 29 - direct/src/plugin/is_pathsep.h | 22 - direct/src/plugin/load_plugin.cxx | 476 -- direct/src/plugin/load_plugin.h | 81 - direct/src/plugin/mkdir_complete.cxx | 224 - direct/src/plugin/mkdir_complete.h | 28 - direct/src/plugin/p3dAuthSession.I | 12 - direct/src/plugin/p3dAuthSession.cxx | 456 -- direct/src/plugin/p3dAuthSession.h | 82 - direct/src/plugin/p3dBoolObject.cxx | 68 - direct/src/plugin/p3dBoolObject.h | 38 - direct/src/plugin/p3dCInstance.I | 20 - direct/src/plugin/p3dCInstance.cxx | 32 - direct/src/plugin/p3dCInstance.h | 50 - direct/src/plugin/p3dCert.cxx | 742 -- direct/src/plugin/p3dCert.h | 117 - direct/src/plugin/p3dCert_strings.cxx | 567 -- direct/src/plugin/p3dCert_strings.h | 44 - direct/src/plugin/p3dCert_wx.cxx | 618 -- direct/src/plugin/p3dCert_wx.h | 119 - direct/src/plugin/p3dConcreteSequence.cxx | 213 - direct/src/plugin/p3dConcreteSequence.h | 56 - direct/src/plugin/p3dConcreteStruct.cxx | 178 - direct/src/plugin/p3dConcreteStruct.h | 51 - direct/src/plugin/p3dConditionVar.I | 12 - direct/src/plugin/p3dConditionVar.cxx | 171 - direct/src/plugin/p3dConditionVar.h | 48 - direct/src/plugin/p3dDownload.I | 126 - direct/src/plugin/p3dDownload.cxx | 192 - direct/src/plugin/p3dDownload.h | 87 - direct/src/plugin/p3dFileDownload.I | 20 - direct/src/plugin/p3dFileDownload.cxx | 107 - direct/src/plugin/p3dFileDownload.h | 50 - direct/src/plugin/p3dFileParams.I | 63 - direct/src/plugin/p3dFileParams.cxx | 193 - direct/src/plugin/p3dFileParams.h | 68 - direct/src/plugin/p3dFloatObject.cxx | 74 - direct/src/plugin/p3dFloatObject.h | 39 - direct/src/plugin/p3dHost.I | 106 - direct/src/plugin/p3dHost.cxx | 1056 --- direct/src/plugin/p3dHost.h | 115 - direct/src/plugin/p3dInstance.I | 147 - direct/src/plugin/p3dInstance.cxx | 3936 ---------- direct/src/plugin/p3dInstance.h | 385 - direct/src/plugin/p3dInstanceManager.I | 322 - direct/src/plugin/p3dInstanceManager.cxx | 1519 ---- direct/src/plugin/p3dInstanceManager.h | 244 - direct/src/plugin/p3dIntObject.cxx | 66 - direct/src/plugin/p3dIntObject.h | 38 - direct/src/plugin/p3dMainObject.cxx | 707 -- direct/src/plugin/p3dMainObject.h | 92 - direct/src/plugin/p3dMultifileReader.I | 79 - direct/src/plugin/p3dMultifileReader.cxx | 487 -- direct/src/plugin/p3dMultifileReader.h | 104 - direct/src/plugin/p3dNoneObject.cxx | 46 - direct/src/plugin/p3dNoneObject.h | 34 - direct/src/plugin/p3dObject.I | 33 - direct/src/plugin/p3dObject.cxx | 459 -- direct/src/plugin/p3dObject.h | 91 - direct/src/plugin/p3dOsxSplashWindow.I | 32 - direct/src/plugin/p3dOsxSplashWindow.cxx | 827 --- direct/src/plugin/p3dOsxSplashWindow.h | 101 - direct/src/plugin/p3dPackage.I | 179 - direct/src/plugin/p3dPackage.cxx | 2015 ------ direct/src/plugin/p3dPackage.h | 310 - direct/src/plugin/p3dPatchFinder.I | 12 - direct/src/plugin/p3dPatchFinder.cxx | 399 -- direct/src/plugin/p3dPatchFinder.h | 179 - direct/src/plugin/p3dPatchfileReader.I | 72 - direct/src/plugin/p3dPatchfileReader.cxx | 280 - direct/src/plugin/p3dPatchfileReader.h | 72 - direct/src/plugin/p3dPythonMain.cxx | 153 - direct/src/plugin/p3dPythonObject.cxx | 341 - direct/src/plugin/p3dPythonObject.h | 67 - direct/src/plugin/p3dPythonRun.I | 12 - direct/src/plugin/p3dPythonRun.cxx | 1930 ----- direct/src/plugin/p3dPythonRun.h | 207 - direct/src/plugin/p3dReferenceCount.I | 68 - direct/src/plugin/p3dReferenceCount.cxx | 14 - direct/src/plugin/p3dReferenceCount.h | 42 - direct/src/plugin/p3dSession.I | 49 - direct/src/plugin/p3dSession.cxx | 1791 ----- direct/src/plugin/p3dSession.h | 166 - direct/src/plugin/p3dSplashWindow.I | 47 - direct/src/plugin/p3dSplashWindow.cxx | 522 -- direct/src/plugin/p3dSplashWindow.h | 156 - direct/src/plugin/p3dStringObject.cxx | 109 - direct/src/plugin/p3dStringObject.h | 42 - direct/src/plugin/p3dTemporaryFile.I | 20 - direct/src/plugin/p3dTemporaryFile.cxx | 33 - direct/src/plugin/p3dTemporaryFile.h | 44 - direct/src/plugin/p3dUndefinedObject.cxx | 46 - direct/src/plugin/p3dUndefinedObject.h | 35 - direct/src/plugin/p3dWinSplashWindow.I | 29 - direct/src/plugin/p3dWinSplashWindow.cxx | 926 --- direct/src/plugin/p3dWinSplashWindow.h | 122 - direct/src/plugin/p3dWindowParams.I | 69 - direct/src/plugin/p3dWindowParams.cxx | 109 - direct/src/plugin/p3dWindowParams.h | 55 - direct/src/plugin/p3dX11SplashWindow.I | 27 - direct/src/plugin/p3dX11SplashWindow.cxx | 1394 ---- direct/src/plugin/p3dX11SplashWindow.h | 144 - direct/src/plugin/p3d_lock.h | 123 - direct/src/plugin/p3d_plugin.cxx | 622 -- direct/src/plugin/p3d_plugin.h | 1127 --- direct/src/plugin/p3d_plugin_common.h | 56 - direct/src/plugin/p3d_plugin_composite1.cxx | 33 - direct/src/plugin/p3dcert.plist | 34 - direct/src/plugin/p3dpython.plist | 34 - direct/src/plugin/p3dpython_composite1.cxx | 6 - direct/src/plugin/parse_color.cxx | 73 - direct/src/plugin/parse_color.h | 21 - .../src/plugin/plugin_common_composite1.cxx | 4 - direct/src/plugin/plugin_get_x11.h | 38 - direct/src/plugin/run_p3dpython.cxx | 33 - direct/src/plugin/run_p3dpython.h | 38 - direct/src/plugin/stb_image.h | 6326 ----------------- direct/src/plugin/twirl.xcf | Bin 151445 -> 0 bytes direct/src/plugin/wstring_encode.cxx | 70 - direct/src/plugin/wstring_encode.h | 38 - direct/src/plugin/xml_helpers.cxx | 40 - direct/src/plugin/xml_helpers.h | 22 - direct/src/plugin_activex/P3DActiveX.cpp | 265 - direct/src/plugin_activex/P3DActiveX.def | 9 - direct/src/plugin_activex/P3DActiveX.h | 36 - direct/src/plugin_activex/P3DActiveX.idl | 51 - direct/src/plugin_activex/P3DActiveX.inf | 34 - direct/src/plugin_activex/P3DActiveX.sln | 21 - direct/src/plugin_activex/P3DActiveX.vcproj | 275 - direct/src/plugin_activex/P3DActiveXCtrl.bmp | Bin 238 -> 0 bytes direct/src/plugin_activex/P3DActiveXCtrl.cpp | 617 -- direct/src/plugin_activex/P3DActiveXCtrl.h | 116 - .../src/plugin_activex/P3DActiveXPropPage.cpp | 77 - .../src/plugin_activex/P3DActiveXPropPage.h | 41 - direct/src/plugin_activex/PPBrowserObject.cpp | 206 - direct/src/plugin_activex/PPBrowserObject.h | 47 - .../src/plugin_activex/PPDownloadCallback.cpp | 243 - .../src/plugin_activex/PPDownloadCallback.h | 67 - .../src/plugin_activex/PPDownloadRequest.cpp | 103 - direct/src/plugin_activex/PPDownloadRequest.h | 73 - direct/src/plugin_activex/PPInstance.cpp | 995 --- direct/src/plugin_activex/PPInstance.h | 120 - direct/src/plugin_activex/PPInterface.cpp | 595 -- direct/src/plugin_activex/PPInterface.h | 47 - direct/src/plugin_activex/PPLogger.cpp | 90 - direct/src/plugin_activex/PPLogger.h | 36 - direct/src/plugin_activex/PPPandaObject.cpp | 209 - direct/src/plugin_activex/PPPandaObject.h | 69 - direct/src/plugin_activex/ReadMe.txt | 79 - .../plugin_activex/p3dactivex_composite1.cxx | 10 - direct/src/plugin_activex/resource.h | 27 - direct/src/plugin_activex/stdafx.cpp | 5 - direct/src/plugin_activex/stdafx.h | 41 - .../src/plugin_installer/FileAssociation.nsh | 190 - direct/src/plugin_installer/VersionInfo.vbs | 4 - direct/src/plugin_installer/make_installer.py | 601 -- direct/src/plugin_installer/make_xpi.py | 202 - direct/src/plugin_installer/p3d_installer.nsi | 300 - direct/src/plugin_npapi/make_osx_bundle.py | 97 - direct/src/plugin_npapi/npapi.h | 928 --- direct/src/plugin_npapi/npfunctions.h | 329 - direct/src/plugin_npapi/nppanda3d.def | 9 - direct/src/plugin_npapi/nppanda3d.plist | 36 - direct/src/plugin_npapi/nppanda3d.r | 19 - direct/src/plugin_npapi/nppanda3d_common.h | 118 - .../src/plugin_npapi/nppanda3d_composite1.cxx | 8 - direct/src/plugin_npapi/npruntime.h | 393 - direct/src/plugin_npapi/nptypes.h | 121 - direct/src/plugin_npapi/ppBrowserObject.I | 12 - direct/src/plugin_npapi/ppBrowserObject.cxx | 257 - direct/src/plugin_npapi/ppBrowserObject.h | 56 - direct/src/plugin_npapi/ppDownloadRequest.I | 23 - direct/src/plugin_npapi/ppDownloadRequest.cxx | 14 - direct/src/plugin_npapi/ppDownloadRequest.h | 45 - direct/src/plugin_npapi/ppInstance.I | 31 - direct/src/plugin_npapi/ppInstance.cxx | 3129 -------- direct/src/plugin_npapi/ppInstance.h | 302 - direct/src/plugin_npapi/ppPandaObject.I | 25 - direct/src/plugin_npapi/ppPandaObject.cxx | 428 -- direct/src/plugin_npapi/ppPandaObject.h | 91 - direct/src/plugin_npapi/ppToplevelObject.I | 12 - direct/src/plugin_npapi/ppToplevelObject.cxx | 232 - direct/src/plugin_npapi/ppToplevelObject.h | 76 - direct/src/plugin_npapi/startup.cxx | 590 -- direct/src/plugin_npapi/startup.h | 45 - .../src/plugin_standalone/make_osx_bundle.py | 97 - direct/src/plugin_standalone/p3dEmbed.cxx | 261 - direct/src/plugin_standalone/p3dEmbed.h | 43 - direct/src/plugin_standalone/p3dEmbedMain.cxx | 35 - direct/src/plugin_standalone/panda3d.I | 12 - direct/src/plugin_standalone/panda3d.cxx | 942 --- direct/src/plugin_standalone/panda3d.h | 67 - direct/src/plugin_standalone/panda3d.ico | Bin 147323 -> 0 bytes direct/src/plugin_standalone/panda3dBase.I | 29 - direct/src/plugin_standalone/panda3dBase.cxx | 766 -- direct/src/plugin_standalone/panda3dBase.h | 126 - direct/src/plugin_standalone/panda3dMac.I | 12 - direct/src/plugin_standalone/panda3dMac.cxx | 107 - direct/src/plugin_standalone/panda3dMac.h | 33 - direct/src/plugin_standalone/panda3dMain.cxx | 21 - .../src/plugin_standalone/panda3dWinMain.cxx | 76 - .../src/plugin_standalone/panda3d_mac.plist | 55 - direct/src/showbase/AppRunnerGlobal.py | 3 + direct/src/showbase/ShowBase.py | 3 +- dtool/PandaVersion.pp | 28 - dtool/src/dtoolutil/pandaSystem.cxx | 27 +- makepanda/getversion.py | 7 +- makepanda/installpanda.py | 55 +- makepanda/makepackage.py | 296 +- makepanda/makepanda.py | 1898 ++--- makepanda/makepanda.vcproj | 190 - makepanda/makepandacore.py | 27 - panda/src/display/subprocessWindowBuffer.h | 3 +- tests/test_imports.py | 18 +- 264 files changed, 987 insertions(+), 72222 deletions(-) delete mode 100644 direct/src/directscripts/DetectPanda3D.js delete mode 100644 direct/src/directscripts/RunPanda3D.js create mode 100644 direct/src/dist/icon.py delete mode 100644 direct/src/p3d/AppRunner.py delete mode 100644 direct/src/p3d/DWBPackageInstaller.py delete mode 100644 direct/src/p3d/DeploymentTools.py delete mode 100644 direct/src/p3d/FileSpec.py delete mode 100644 direct/src/p3d/HostInfo.py delete mode 100644 direct/src/p3d/InstalledHostData.py delete mode 100644 direct/src/p3d/InstalledPackageData.py delete mode 100644 direct/src/p3d/JavaScript.py delete mode 100644 direct/src/p3d/PackageInfo.py delete mode 100644 direct/src/p3d/PackageInstaller.py delete mode 100644 direct/src/p3d/PackageMerger.py delete mode 100644 direct/src/p3d/Packager.py delete mode 100644 direct/src/p3d/PatchMaker.py delete mode 100644 direct/src/p3d/ScanDirectoryNode.py delete mode 100644 direct/src/p3d/SeqValue.py delete mode 100644 direct/src/p3d/__init__.py delete mode 100644 direct/src/p3d/coreapi.pdef delete mode 100644 direct/src/p3d/p3dWrapper.c delete mode 100755 direct/src/p3d/packp3d.py delete mode 100644 direct/src/p3d/panda3d.pdef delete mode 100644 direct/src/p3d/pdeploy.py delete mode 100755 direct/src/p3d/pmerge.py delete mode 100755 direct/src/p3d/ppackage.py delete mode 100755 direct/src/p3d/ppatcher.py delete mode 100644 direct/src/p3d/runp3d.py delete mode 100644 direct/src/p3d/thirdparty.pdef delete mode 100644 direct/src/plugin/binaryXml.cxx delete mode 100644 direct/src/plugin/binaryXml.h delete mode 100644 direct/src/plugin/failed.pgm delete mode 100644 direct/src/plugin/failed.xcf delete mode 100644 direct/src/plugin/fhandle.h delete mode 100644 direct/src/plugin/fileSpec.I delete mode 100644 direct/src/plugin/fileSpec.cxx delete mode 100644 direct/src/plugin/fileSpec.h delete mode 100644 direct/src/plugin/find_root_dir.cxx delete mode 100644 direct/src/plugin/find_root_dir.h delete mode 100644 direct/src/plugin/find_root_dir_assist.mm delete mode 100644 direct/src/plugin/get_tinyxml.h delete mode 100644 direct/src/plugin/get_twirl_data.cxx delete mode 100644 direct/src/plugin/get_twirl_data.h delete mode 100644 direct/src/plugin/handleStream.I delete mode 100644 direct/src/plugin/handleStream.cxx delete mode 100644 direct/src/plugin/handleStream.h delete mode 100644 direct/src/plugin/handleStreamBuf.I delete mode 100644 direct/src/plugin/handleStreamBuf.cxx delete mode 100644 direct/src/plugin/handleStreamBuf.h delete mode 100644 direct/src/plugin/is_pathsep.I delete mode 100644 direct/src/plugin/is_pathsep.h delete mode 100644 direct/src/plugin/load_plugin.cxx delete mode 100644 direct/src/plugin/load_plugin.h delete mode 100644 direct/src/plugin/mkdir_complete.cxx delete mode 100644 direct/src/plugin/mkdir_complete.h delete mode 100644 direct/src/plugin/p3dAuthSession.I delete mode 100644 direct/src/plugin/p3dAuthSession.cxx delete mode 100644 direct/src/plugin/p3dAuthSession.h delete mode 100644 direct/src/plugin/p3dBoolObject.cxx delete mode 100644 direct/src/plugin/p3dBoolObject.h delete mode 100644 direct/src/plugin/p3dCInstance.I delete mode 100644 direct/src/plugin/p3dCInstance.cxx delete mode 100644 direct/src/plugin/p3dCInstance.h delete mode 100644 direct/src/plugin/p3dCert.cxx delete mode 100644 direct/src/plugin/p3dCert.h delete mode 100644 direct/src/plugin/p3dCert_strings.cxx delete mode 100644 direct/src/plugin/p3dCert_strings.h delete mode 100644 direct/src/plugin/p3dCert_wx.cxx delete mode 100644 direct/src/plugin/p3dCert_wx.h delete mode 100644 direct/src/plugin/p3dConcreteSequence.cxx delete mode 100644 direct/src/plugin/p3dConcreteSequence.h delete mode 100644 direct/src/plugin/p3dConcreteStruct.cxx delete mode 100644 direct/src/plugin/p3dConcreteStruct.h delete mode 100644 direct/src/plugin/p3dConditionVar.I delete mode 100644 direct/src/plugin/p3dConditionVar.cxx delete mode 100644 direct/src/plugin/p3dConditionVar.h delete mode 100644 direct/src/plugin/p3dDownload.I delete mode 100644 direct/src/plugin/p3dDownload.cxx delete mode 100644 direct/src/plugin/p3dDownload.h delete mode 100644 direct/src/plugin/p3dFileDownload.I delete mode 100644 direct/src/plugin/p3dFileDownload.cxx delete mode 100644 direct/src/plugin/p3dFileDownload.h delete mode 100644 direct/src/plugin/p3dFileParams.I delete mode 100644 direct/src/plugin/p3dFileParams.cxx delete mode 100644 direct/src/plugin/p3dFileParams.h delete mode 100644 direct/src/plugin/p3dFloatObject.cxx delete mode 100644 direct/src/plugin/p3dFloatObject.h delete mode 100644 direct/src/plugin/p3dHost.I delete mode 100644 direct/src/plugin/p3dHost.cxx delete mode 100644 direct/src/plugin/p3dHost.h delete mode 100644 direct/src/plugin/p3dInstance.I delete mode 100644 direct/src/plugin/p3dInstance.cxx delete mode 100644 direct/src/plugin/p3dInstance.h delete mode 100644 direct/src/plugin/p3dInstanceManager.I delete mode 100644 direct/src/plugin/p3dInstanceManager.cxx delete mode 100644 direct/src/plugin/p3dInstanceManager.h delete mode 100644 direct/src/plugin/p3dIntObject.cxx delete mode 100644 direct/src/plugin/p3dIntObject.h delete mode 100644 direct/src/plugin/p3dMainObject.cxx delete mode 100644 direct/src/plugin/p3dMainObject.h delete mode 100644 direct/src/plugin/p3dMultifileReader.I delete mode 100644 direct/src/plugin/p3dMultifileReader.cxx delete mode 100644 direct/src/plugin/p3dMultifileReader.h delete mode 100644 direct/src/plugin/p3dNoneObject.cxx delete mode 100644 direct/src/plugin/p3dNoneObject.h delete mode 100644 direct/src/plugin/p3dObject.I delete mode 100644 direct/src/plugin/p3dObject.cxx delete mode 100644 direct/src/plugin/p3dObject.h delete mode 100644 direct/src/plugin/p3dOsxSplashWindow.I delete mode 100644 direct/src/plugin/p3dOsxSplashWindow.cxx delete mode 100644 direct/src/plugin/p3dOsxSplashWindow.h delete mode 100644 direct/src/plugin/p3dPackage.I delete mode 100644 direct/src/plugin/p3dPackage.cxx delete mode 100644 direct/src/plugin/p3dPackage.h delete mode 100644 direct/src/plugin/p3dPatchFinder.I delete mode 100644 direct/src/plugin/p3dPatchFinder.cxx delete mode 100644 direct/src/plugin/p3dPatchFinder.h delete mode 100644 direct/src/plugin/p3dPatchfileReader.I delete mode 100644 direct/src/plugin/p3dPatchfileReader.cxx delete mode 100644 direct/src/plugin/p3dPatchfileReader.h delete mode 100644 direct/src/plugin/p3dPythonMain.cxx delete mode 100644 direct/src/plugin/p3dPythonObject.cxx delete mode 100644 direct/src/plugin/p3dPythonObject.h delete mode 100644 direct/src/plugin/p3dPythonRun.I delete mode 100644 direct/src/plugin/p3dPythonRun.cxx delete mode 100644 direct/src/plugin/p3dPythonRun.h delete mode 100644 direct/src/plugin/p3dReferenceCount.I delete mode 100644 direct/src/plugin/p3dReferenceCount.cxx delete mode 100644 direct/src/plugin/p3dReferenceCount.h delete mode 100644 direct/src/plugin/p3dSession.I delete mode 100644 direct/src/plugin/p3dSession.cxx delete mode 100644 direct/src/plugin/p3dSession.h delete mode 100644 direct/src/plugin/p3dSplashWindow.I delete mode 100644 direct/src/plugin/p3dSplashWindow.cxx delete mode 100644 direct/src/plugin/p3dSplashWindow.h delete mode 100644 direct/src/plugin/p3dStringObject.cxx delete mode 100644 direct/src/plugin/p3dStringObject.h delete mode 100644 direct/src/plugin/p3dTemporaryFile.I delete mode 100644 direct/src/plugin/p3dTemporaryFile.cxx delete mode 100644 direct/src/plugin/p3dTemporaryFile.h delete mode 100644 direct/src/plugin/p3dUndefinedObject.cxx delete mode 100644 direct/src/plugin/p3dUndefinedObject.h delete mode 100644 direct/src/plugin/p3dWinSplashWindow.I delete mode 100644 direct/src/plugin/p3dWinSplashWindow.cxx delete mode 100644 direct/src/plugin/p3dWinSplashWindow.h delete mode 100644 direct/src/plugin/p3dWindowParams.I delete mode 100644 direct/src/plugin/p3dWindowParams.cxx delete mode 100644 direct/src/plugin/p3dWindowParams.h delete mode 100644 direct/src/plugin/p3dX11SplashWindow.I delete mode 100644 direct/src/plugin/p3dX11SplashWindow.cxx delete mode 100644 direct/src/plugin/p3dX11SplashWindow.h delete mode 100644 direct/src/plugin/p3d_lock.h delete mode 100644 direct/src/plugin/p3d_plugin.cxx delete mode 100644 direct/src/plugin/p3d_plugin.h delete mode 100644 direct/src/plugin/p3d_plugin_common.h delete mode 100644 direct/src/plugin/p3d_plugin_composite1.cxx delete mode 100644 direct/src/plugin/p3dcert.plist delete mode 100644 direct/src/plugin/p3dpython.plist delete mode 100644 direct/src/plugin/p3dpython_composite1.cxx delete mode 100644 direct/src/plugin/parse_color.cxx delete mode 100644 direct/src/plugin/parse_color.h delete mode 100644 direct/src/plugin/plugin_common_composite1.cxx delete mode 100644 direct/src/plugin/plugin_get_x11.h delete mode 100644 direct/src/plugin/run_p3dpython.cxx delete mode 100644 direct/src/plugin/run_p3dpython.h delete mode 100644 direct/src/plugin/stb_image.h delete mode 100644 direct/src/plugin/twirl.xcf delete mode 100644 direct/src/plugin/wstring_encode.cxx delete mode 100644 direct/src/plugin/wstring_encode.h delete mode 100644 direct/src/plugin/xml_helpers.cxx delete mode 100644 direct/src/plugin/xml_helpers.h delete mode 100644 direct/src/plugin_activex/P3DActiveX.cpp delete mode 100644 direct/src/plugin_activex/P3DActiveX.def delete mode 100644 direct/src/plugin_activex/P3DActiveX.h delete mode 100644 direct/src/plugin_activex/P3DActiveX.idl delete mode 100644 direct/src/plugin_activex/P3DActiveX.inf delete mode 100644 direct/src/plugin_activex/P3DActiveX.sln delete mode 100644 direct/src/plugin_activex/P3DActiveX.vcproj delete mode 100644 direct/src/plugin_activex/P3DActiveXCtrl.bmp delete mode 100644 direct/src/plugin_activex/P3DActiveXCtrl.cpp delete mode 100644 direct/src/plugin_activex/P3DActiveXCtrl.h delete mode 100644 direct/src/plugin_activex/P3DActiveXPropPage.cpp delete mode 100644 direct/src/plugin_activex/P3DActiveXPropPage.h delete mode 100644 direct/src/plugin_activex/PPBrowserObject.cpp delete mode 100644 direct/src/plugin_activex/PPBrowserObject.h delete mode 100644 direct/src/plugin_activex/PPDownloadCallback.cpp delete mode 100644 direct/src/plugin_activex/PPDownloadCallback.h delete mode 100644 direct/src/plugin_activex/PPDownloadRequest.cpp delete mode 100644 direct/src/plugin_activex/PPDownloadRequest.h delete mode 100644 direct/src/plugin_activex/PPInstance.cpp delete mode 100644 direct/src/plugin_activex/PPInstance.h delete mode 100644 direct/src/plugin_activex/PPInterface.cpp delete mode 100644 direct/src/plugin_activex/PPInterface.h delete mode 100644 direct/src/plugin_activex/PPLogger.cpp delete mode 100644 direct/src/plugin_activex/PPLogger.h delete mode 100644 direct/src/plugin_activex/PPPandaObject.cpp delete mode 100644 direct/src/plugin_activex/PPPandaObject.h delete mode 100644 direct/src/plugin_activex/ReadMe.txt delete mode 100644 direct/src/plugin_activex/p3dactivex_composite1.cxx delete mode 100644 direct/src/plugin_activex/resource.h delete mode 100644 direct/src/plugin_activex/stdafx.cpp delete mode 100644 direct/src/plugin_activex/stdafx.h delete mode 100644 direct/src/plugin_installer/FileAssociation.nsh delete mode 100644 direct/src/plugin_installer/VersionInfo.vbs delete mode 100755 direct/src/plugin_installer/make_installer.py delete mode 100755 direct/src/plugin_installer/make_xpi.py delete mode 100644 direct/src/plugin_installer/p3d_installer.nsi delete mode 100755 direct/src/plugin_npapi/make_osx_bundle.py delete mode 100644 direct/src/plugin_npapi/npapi.h delete mode 100644 direct/src/plugin_npapi/npfunctions.h delete mode 100644 direct/src/plugin_npapi/nppanda3d.def delete mode 100644 direct/src/plugin_npapi/nppanda3d.plist delete mode 100644 direct/src/plugin_npapi/nppanda3d.r delete mode 100644 direct/src/plugin_npapi/nppanda3d_common.h delete mode 100644 direct/src/plugin_npapi/nppanda3d_composite1.cxx delete mode 100644 direct/src/plugin_npapi/npruntime.h delete mode 100644 direct/src/plugin_npapi/nptypes.h delete mode 100644 direct/src/plugin_npapi/ppBrowserObject.I delete mode 100644 direct/src/plugin_npapi/ppBrowserObject.cxx delete mode 100644 direct/src/plugin_npapi/ppBrowserObject.h delete mode 100644 direct/src/plugin_npapi/ppDownloadRequest.I delete mode 100644 direct/src/plugin_npapi/ppDownloadRequest.cxx delete mode 100644 direct/src/plugin_npapi/ppDownloadRequest.h delete mode 100644 direct/src/plugin_npapi/ppInstance.I delete mode 100644 direct/src/plugin_npapi/ppInstance.cxx delete mode 100644 direct/src/plugin_npapi/ppInstance.h delete mode 100644 direct/src/plugin_npapi/ppPandaObject.I delete mode 100644 direct/src/plugin_npapi/ppPandaObject.cxx delete mode 100644 direct/src/plugin_npapi/ppPandaObject.h delete mode 100644 direct/src/plugin_npapi/ppToplevelObject.I delete mode 100644 direct/src/plugin_npapi/ppToplevelObject.cxx delete mode 100644 direct/src/plugin_npapi/ppToplevelObject.h delete mode 100644 direct/src/plugin_npapi/startup.cxx delete mode 100644 direct/src/plugin_npapi/startup.h delete mode 100755 direct/src/plugin_standalone/make_osx_bundle.py delete mode 100644 direct/src/plugin_standalone/p3dEmbed.cxx delete mode 100644 direct/src/plugin_standalone/p3dEmbed.h delete mode 100644 direct/src/plugin_standalone/p3dEmbedMain.cxx delete mode 100644 direct/src/plugin_standalone/panda3d.I delete mode 100644 direct/src/plugin_standalone/panda3d.cxx delete mode 100644 direct/src/plugin_standalone/panda3d.h delete mode 100644 direct/src/plugin_standalone/panda3d.ico delete mode 100644 direct/src/plugin_standalone/panda3dBase.I delete mode 100644 direct/src/plugin_standalone/panda3dBase.cxx delete mode 100644 direct/src/plugin_standalone/panda3dBase.h delete mode 100644 direct/src/plugin_standalone/panda3dMac.I delete mode 100644 direct/src/plugin_standalone/panda3dMac.cxx delete mode 100644 direct/src/plugin_standalone/panda3dMac.h delete mode 100644 direct/src/plugin_standalone/panda3dMain.cxx delete mode 100644 direct/src/plugin_standalone/panda3dWinMain.cxx delete mode 100644 direct/src/plugin_standalone/panda3d_mac.plist diff --git a/direct/src/directscripts/DetectPanda3D.js b/direct/src/directscripts/DetectPanda3D.js deleted file mode 100644 index 52c57cc034..0000000000 --- a/direct/src/directscripts/DetectPanda3D.js +++ /dev/null @@ -1,99 +0,0 @@ -// Based on Apple sample code at -// http://developer.apple.com/internet/webcontent/examples/detectplugins_source.html - - -// initialize global variables -var detectableWithVB = false; -var pluginFound = false; - -function goURL(daURL) { - // Assume we have Javascript 1.1 functionality. - window.location.replace(daURL); - return; -} - -function redirectCheck(pluginFound, redirectURL, redirectIfFound) { - // check for redirection - if( redirectURL && ((pluginFound && redirectIfFound) || - (!pluginFound && !redirectIfFound)) ) { - // go away - goURL(redirectURL); - return pluginFound; - } else { - // stay here and return result of plugin detection - return pluginFound; - } -} - -function canDetectPlugins() { - if( detectableWithVB || (navigator.plugins && navigator.plugins.length > 0) ) { - return true; - } else { - return false; - } -} - -function detectPanda3D(redirectURL, redirectIfFound) { - pluginFound = detectPlugin('Panda3D'); - // if not found, try to detect with VisualBasic - if(!pluginFound && detectableWithVB) { - pluginFound = detectActiveXControl('P3DACTIVEX.P3DActiveXCtrl.1'); - } - // check for redirection - return redirectCheck(pluginFound, redirectURL, redirectIfFound); -} - -function detectPlugin() { - // allow for multiple checks in a single pass - var daPlugins = detectPlugin.arguments; - // consider pluginFound to be false until proven true - var pluginFound = false; - // if plugins array is there and not fake - if (navigator.plugins && navigator.plugins.length > 0) { - var pluginsArrayLength = navigator.plugins.length; - // for each plugin... - for (pluginsArrayCounter=0; pluginsArrayCounter < pluginsArrayLength; pluginsArrayCounter++ ) { - // loop through all desired names and check each against the current plugin name - var numFound = 0; - for(namesCounter=0; namesCounter < daPlugins.length; namesCounter++) { - // if desired plugin name is found in either plugin name or description - if( (navigator.plugins[pluginsArrayCounter].name.indexOf(daPlugins[namesCounter]) >= 0) || - (navigator.plugins[pluginsArrayCounter].description.indexOf(daPlugins[namesCounter]) >= 0) ) { - // this name was found - numFound++; - } - } - // now that we have checked all the required names against this one plugin, - // if the number we found matches the total number provided then we were successful - if(numFound == daPlugins.length) { - pluginFound = true; - // if we've found the plugin, we can stop looking through at the rest of the plugins - break; - } - } - } - return pluginFound; -} // detectPlugin - - -// Here we write out the VBScript block for MSIE Windows -if ((navigator.userAgent.indexOf('MSIE') != -1) && (navigator.userAgent.indexOf('Win') != -1)) { - document.writeln(''); -} diff --git a/direct/src/directscripts/RunPanda3D.js b/direct/src/directscripts/RunPanda3D.js deleted file mode 100644 index b26d3b99c3..0000000000 --- a/direct/src/directscripts/RunPanda3D.js +++ /dev/null @@ -1,132 +0,0 @@ -// This script injects the appropriate syntax into the document to -// embed Panda3D, either for the ActiveX or Mozilla-based plugin. - -// It is also possible to write browser-independent code by nesting -// tags, but this causes problems when you need to reference -// the particular object that is actually running (which object is -// it?) for scripting purposes. - -// This script writes only a single tag, and it can be -// assigned the id you specify, avoiding this ambiguity. - -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - - -function P3D_Generateobj(objAttrs, params, embedAttrs, imageAttrs) -{ - var str = ''; - - if (isIE && isWin && !isOpera) - { - str += ' '; - } - } - else - { - str += ''; - } - str += ' required_size: + break + + if from_size > required_size: + Icon.notify.warning("Generating %dx%d icon by scaling down %dx%d image" % (required_size, required_size, from_size, from_size)) + + image = PNMImage(required_size, required_size) + if self.images[from_size].hasAlpha(): + image.addAlpha() + image.quickFilterFrom(self.images[from_size]) + self.images[required_size] = image + else: + Icon.notify.warning("Cannot generate %dx%d icon; no higher resolution image available" % (required_size, required_size)) + + def _write_bitmap(self, fp, image, size, bpp): + """ Writes the bitmap header and data of an .ico file. """ + + fp.write(struct.pack('= 256: + # Find closest pixel instead. + index = closest_indices[index - 256] + fp.write(struct.pack('> 3) & 3) + for y in xrange(size): + mask = 0 + num_bits = 7 + for x in xrange(size): + a = image.get_alpha_val(x, size - y - 1) + if a <= 1: + mask |= (1 << num_bits) + num_bits -= 1 + if num_bits < 0: + fp.write(struct.pack('> 3 + if andsize % 4 != 0: + andsize += 4 - (andsize % 4) + fp.write(b'\x00' * (andsize * size)) + + def makeICO(self, fn): + """ Writes the images to a Windows ICO file. Returns True on success. """ + + if not isinstance(fn, Filename): + fn = Filename.fromOsSpecific(fn) + fn.setBinary() + + # ICO files only support resolutions up to 256x256. + count = 0 + for size in self.images.keys(): + if size < 256: + count += 1 + if size <= 256: + count += 1 + dataoffs = 6 + count * 16 + + ico = open(fn, 'wb') + ico.write(struct.pack('= 256: + continue + ico.write(struct.pack('> 3 + if andsize % 4 != 0: + andsize += 4 - (andsize % 4) + datasize = 40 + 256 * 4 + (xorsize + andsize) * size + + ico.write(struct.pack(' 256: + continue + elif size == 256: + ico.write(b'\0\0') + else: + ico.write(struct.pack('> 3 + if andsize % 4 != 0: + andsize += 4 - (andsize % 4) + datasize = 40 + (xorsize + andsize) * size + + ico.write(struct.pack('I', len(pngdata))) + icns.write(pngdata) + + elif size in icon_types: + # If it has an alpha channel, we write out a mask too. + if image.hasAlpha(): + icns.write(mask_types[size]) + icns.write(struct.pack('>I', size * size + 8)) + + for y in xrange(size): + for x in xrange(size): + icns.write(struct.pack('I', size * size * 4 + 8)) + + for y in xrange(size): + for x in xrange(size): + r, g, b = image.getXel(x, y) + icns.write(struct.pack('>BBBB', 0, int(r * 255), int(g * 255), int(b * 255))) + + length = icns.tell() + icns.seek(4) + icns.write(struct.pack('>I', length)) + icns.close() + + return True + + diff --git a/direct/src/p3d/AppRunner.py b/direct/src/p3d/AppRunner.py deleted file mode 100644 index aae03754e6..0000000000 --- a/direct/src/p3d/AppRunner.py +++ /dev/null @@ -1,1245 +0,0 @@ -""" -This module is intended to be compiled into the Panda3D runtime -distributable, to execute a packaged p3d application, but it can also -be run directly via the Python interpreter (if the current Panda3D and -Python versions match the version expected by the application). See -runp3d.py for a command-line tool to invoke this module. - -The global AppRunner instance may be imported as follows:: - - from direct.showbase.AppRunnerGlobal import appRunner - -This will be None if Panda was not run from the runtime environment. -""" - -__all__ = ["AppRunner", "dummyAppRunner", "ArgumentError"] - -import sys -import os - -if sys.version_info >= (3, 0): - import builtins -else: - import __builtin__ as builtins - -from direct.showbase import VFSImporter -from direct.showbase.DirectObject import DirectObject -from panda3d.core import VirtualFileSystem, Filename, Multifile, loadPrcFileData, unloadPrcFile, getModelPath, WindowProperties, ExecutionEnvironment, PandaSystem, Notify, StreamWriter, ConfigVariableString, ConfigPageManager -from panda3d.direct import init_app_for_gui -from panda3d import core -from direct.stdpy import file, glob -from direct.task.TaskManagerGlobal import taskMgr -from direct.showbase.MessengerGlobal import messenger -from direct.showbase import AppRunnerGlobal -from direct.directnotify.DirectNotifyGlobal import directNotify -from direct.p3d.HostInfo import HostInfo -from direct.p3d.ScanDirectoryNode import ScanDirectoryNode -from direct.p3d.InstalledHostData import InstalledHostData -from direct.p3d.InstalledPackageData import InstalledPackageData - -# These imports are read by the C++ wrapper in p3dPythonRun.cxx. -from direct.p3d.JavaScript import Undefined, ConcreteStruct - -class ArgumentError(AttributeError): - pass - -class ScriptAttributes: - """ This dummy class serves as the root object for the scripting - interface. The Python code can store objects and functions here - for direct inspection by the browser's JavaScript code. """ - pass - -class AppRunner(DirectObject): - - """ This class is intended to be compiled into the Panda3D runtime - distributable, to execute a packaged p3d application. It also - provides some useful runtime services while running in that - packaged environment. - - It does not usually exist while running Python directly, but you - can use dummyAppRunner() to create one at startup for testing or - development purposes. """ - - notify = directNotify.newCategory("AppRunner") - - ConfigBasename = 'config.xml' - - # Default values for parameters that are absent from the config file: - maxDiskUsage = 2048 * 1048576 # 2 GB - - # Values for verifyContents, from p3d_plugin.h - P3DVCNone = 0 - P3DVCNormal = 1 - P3DVCForce = 2 - P3DVCNever = 3 - - # Also from p3d_plugin.h - P3D_CONTENTS_DEFAULT_MAX_AGE = 5 - - def __init__(self): - DirectObject.__init__(self) - - # We direct both our stdout and stderr objects onto Panda's - # Notify stream. This ensures that unadorned print statements - # made within Python will get routed into the log properly. - stream = StreamWriter(Notify.out(), False) - sys.stdout = stream - sys.stderr = stream - - # This is set true by dummyAppRunner(), below. - self.dummy = False - - # These will be set from the application flags when - # setP3DFilename() is called. - self.allowPythonDev = False - self.guiApp = False - self.interactiveConsole = False - self.initialAppImport = False - self.trueFileIO = False - self.respectPerPlatform = None - - self.verifyContents = self.P3DVCNone - - self.sessionId = 0 - self.packedAppEnvironmentInitialized = False - self.gotWindow = False - self.gotP3DFilename = False - self.p3dFilename = None - self.p3dUrl = None - self.started = False - self.windowOpened = False - self.windowPrc = None - - self.http = None - if hasattr(core, 'HTTPClient'): - self.http = core.HTTPClient.getGlobalPtr() - - self.Undefined = Undefined - self.ConcreteStruct = ConcreteStruct - - # This is per session. - self.nextScriptId = 0 - - # TODO: we need one of these per instance, not per session. - self.instanceId = None - - # The root Panda3D install directory. This is filled in when - # the instance starts up. - self.rootDir = None - - # The log directory. Also filled in when the instance starts. - self.logDirectory = None - - # self.superMirrorUrl, if nonempty, is the "super mirror" URL - # that should be contacted first before trying the actual - # host. This is primarily used for "downloading" from a - # locally-stored Panda3D installation. This is also filled in - # when the instance starts up. - self.superMirrorUrl = None - - # A list of the Panda3D packages that have been loaded. - self.installedPackages = [] - - # A list of the Panda3D packages that in the queue to be - # downloaded. - self.downloadingPackages = [] - - # A dictionary of HostInfo objects for the various download - # hosts we have imported packages from. - self.hosts = {} - - # The altHost string that is in effect from the HTML tokens, - # if any, and the dictionary of URL remapping: orig host url - # -> alt host url. - self.altHost = None - self.altHostMap = {} - - # The URL from which Panda itself should be downloaded. - self.pandaHostUrl = PandaSystem.getPackageHostUrl() - - # Application code can assign a callable object here; if so, - # it will be invoked when an uncaught exception propagates to - # the top of the TaskMgr.run() loop. - self.exceptionHandler = None - - # Managing packages for runtime download. - self.downloadingPackages = [] - self.downloadTask = None - - # The mount point for the multifile. For now, this is always - # the current working directory, for convenience; but when we - # move to multiple-instance sessions, it may have to be - # different for each instance. - self.multifileRoot = str(ExecutionEnvironment.getCwd()) - - # The "main" object will be exposed to the DOM as a property - # of the plugin object; that is, document.pluginobject.main in - # JavaScript will be appRunner.main here. This may be - # replaced with a direct reference to the JavaScript object - # later, in setInstanceInfo(). - self.main = ScriptAttributes() - - # By default, we publish a stop() method so the browser can - # easy stop the plugin. A particular application can remove - # this if it chooses. - self.main.stop = self.stop - - # This will be the browser's toplevel window DOM object; - # e.g. self.dom.document will be the document. - self.dom = None - - # This is the list of expressions we will evaluate when - # self.dom gets assigned. - self.deferredEvals = [] - - # This is the default requestFunc that is installed if we - # never call setRequestFunc(). - def defaultRequestFunc(*args): - if args[1] == 'notify': - # Quietly ignore notifies. - return - self.notify.info("Ignoring request: %s" % (args,)) - self.requestFunc = defaultRequestFunc - - # This will be filled in with the default WindowProperties for - # this instance, e.g. the WindowProperties necessary to - # re-embed a window in the browser frame. - self.windowProperties = None - - # Store our pointer so DirectStart-based apps can find us. - if AppRunnerGlobal.appRunner is None: - AppRunnerGlobal.appRunner = self - - # We use this messenger hook to dispatch this __startIfReady() - # call back to the main thread. - self.accept('AppRunner_startIfReady', self.__startIfReady) - - def getToken(self, tokenName): - """ Returns the value of the indicated web token as a string, - if it was set, or None if it was not. """ - - return self.tokenDict.get(tokenName.lower(), None) - - def getTokenInt(self, tokenName): - """ Returns the value of the indicated web token as an integer - value, if it was set, or None if it was not, or not an - integer. """ - - value = self.getToken(tokenName) - if value is not None: - try: - value = int(value) - except ValueError: - value = None - return value - - def getTokenFloat(self, tokenName): - """ Returns the value of the indicated web token as a - floating-point value value, if it was set, or None if it was - not, or not a number. """ - - value = self.getToken(tokenName) - if value is not None: - try: - value = float(value) - except ValueError: - value = None - return value - - def getTokenBool(self, tokenName): - """ Returns the value of the indicated web token as a boolean - value, if it was set, or None if it was not. """ - - value = self.getTokenInt(tokenName) - if value is not None: - value = bool(value) - return value - - - - def installPackage(self, packageName, version = None, hostUrl = None): - - """ Installs the named package, downloading it first if - necessary. Returns true on success, false on failure. This - method runs synchronously, and will block until it is - finished; see the PackageInstaller class if you want this to - happen asynchronously instead. """ - - host = self.getHostWithAlt(hostUrl) - if not host.downloadContentsFile(self.http): - return False - - # All right, get the package info now. - package = host.getPackage(packageName, version) - if not package: - self.notify.warning("Package %s %s not known on %s" % ( - packageName, version, hostUrl)) - return False - - return self.__rInstallPackage(package, []) - - def __rInstallPackage(self, package, nested): - """ The recursive implementation of installPackage(). The new - parameter, nested, is a list of packages that we are - recursively calling this from, to avoid recursive loops. """ - - package.checkStatus() - if not package.downloadDescFile(self.http): - return False - - # Now that we've downloaded and read the desc file, we can - # install all of the required packages first. - nested = nested[:] + [self] - for packageName, version, host in package.requires: - if host.downloadContentsFile(self.http): - p2 = host.getPackage(packageName, version) - if not p2: - self.notify.warning("Couldn't find %s %s on %s" % (packageName, version, host.hostUrl)) - else: - if p2 not in nested: - self.__rInstallPackage(p2, nested) - - # Now that all of the required packages are installed, carry - # on to download and install this package. - if not package.downloadPackage(self.http): - return False - - if not package.installPackage(self): - return False - - self.notify.info("Package %s %s installed." % ( - package.packageName, package.packageVersion)) - return True - - def getHostWithAlt(self, hostUrl): - """ Returns a suitable HostInfo object for downloading - contents from the indicated URL. This is almost always the - same thing as getHost(), except in the rare case when we have - an alt_host specified in the HTML tokens; in this case, we may - actually want to download the contents from a different URL - than the one given, for instance to download a version in - testing. """ - - if hostUrl is None: - hostUrl = self.pandaHostUrl - - altUrl = self.altHostMap.get(hostUrl, None) - if altUrl: - # We got an alternate host. Use it. - return self.getHost(altUrl) - - # We didn't get an aternate host, use the original. - host = self.getHost(hostUrl) - - # But we might need to consult the host itself to see if *it* - # recommends an altHost. - if self.altHost: - # This means forcing the host to download its contents - # file on the spot, a blocking operation. This is a - # little unfortunate, but since alt_host is so rarely - # used, probably not really a problem. - host.downloadContentsFile(self.http) - altUrl = host.altHosts.get(self.altHost, None) - if altUrl: - return self.getHost(altUrl) - - # No shenanigans, just return the requested host. - return host - - def getHost(self, hostUrl, hostDir = None): - """ Returns a new HostInfo object corresponding to the - indicated host URL. If we have already seen this URL - previously, returns the same object. - - This returns the literal referenced host. To return the - mapped host, which is the one we should actually download - from, see getHostWithAlt(). """ - - if not hostUrl: - hostUrl = self.pandaHostUrl - - host = self.hosts.get(hostUrl, None) - if not host: - host = HostInfo(hostUrl, appRunner = self, hostDir = hostDir) - self.hosts[hostUrl] = host - return host - - def getHostWithDir(self, hostDir): - """ Returns the HostInfo object that corresponds to the - indicated on-disk host directory. This would be used when - reading a host directory from disk, instead of downloading it - from a server. Supply the full path to the host directory, as - a Filename. Returns None if the contents.xml in the indicated - host directory cannot be read or doesn't seem consistent. """ - - host = HostInfo(None, hostDir = hostDir, appRunner = self) - if not host.hasContentsFile: - if not host.readContentsFile(): - # Couldn't read the contents.xml file - return None - - if not host.hostUrl: - # The contents.xml file there didn't seem to indicate the - # same host directory. - return None - - host2 = self.hosts.get(host.hostUrl) - if host2 is None: - # No such host already; store this one. - self.hosts[host.hostUrl] = host - return host - - if host2.hostDir != host.hostDir: - # Hmm, we already have that host somewhere else. - return None - - # We already have that host, and it's consistent. - return host2 - - def deletePackages(self, packages): - """ Removes all of the indicated packages from the disk, - uninstalling them and deleting all of their files. The - packages parameter must be a list of one or more PackageInfo - objects, for instance as returned by getHost().getPackage(). - Returns the list of packages that were NOT found. """ - - for hostUrl, host in self.hosts.items(): - packages = host.deletePackages(packages) - - if not host.packages: - # If that's all of the packages for this host, delete - # the host directory too. - del self.hosts[hostUrl] - self.__deleteHostFiles(host) - - return packages - - def __deleteHostFiles(self, host): - """ Called by deletePackages(), this removes all the files for - the indicated host (for which we have presumably already - removed all of the packages). """ - - self.notify.info("Deleting host %s: %s" % (host.hostUrl, host.hostDir)) - self.rmtree(host.hostDir) - - self.sendRequest('forget_package', host.hostUrl, '', '') - - - def freshenFile(self, host, fileSpec, localPathname): - """ Ensures that the localPathname is the most current version - of the file defined by fileSpec, as offered by host. If not, - it downloads a new version on-the-spot. Returns true on - success, false on failure. """ - - assert self.http - return host.freshenFile(self.http, fileSpec, localPathname) - - def scanInstalledPackages(self): - """ Scans the hosts and packages already installed locally on - the system. Returns a list of InstalledHostData objects, each - of which contains a list of InstalledPackageData objects. """ - - result = [] - hostsFilename = Filename(self.rootDir, 'hosts') - hostsDir = ScanDirectoryNode(hostsFilename) - for dirnode in hostsDir.nested: - host = self.getHostWithDir(dirnode.pathname) - hostData = InstalledHostData(host, dirnode) - - if host: - for package in host.getAllPackages(includeAllPlatforms = True): - packageDir = package.getPackageDir() - if not packageDir.exists(): - continue - - subdir = dirnode.extractSubdir(packageDir) - if not subdir: - # This package, while defined by the host, isn't installed - # locally; ignore it. - continue - - packageData = InstalledPackageData(package, subdir) - hostData.packages.append(packageData) - - # Now that we've examined all of the packages for the host, - # anything left over is junk. - for subdir in dirnode.nested: - packageData = InstalledPackageData(None, subdir) - hostData.packages.append(packageData) - - result.append(hostData) - - return result - - def readConfigXml(self): - """ Reads the config.xml file that may be present in the root - directory. """ - - if not hasattr(core, 'TiXmlDocument'): - return - - filename = Filename(self.rootDir, self.ConfigBasename) - doc = core.TiXmlDocument(filename.toOsSpecific()) - if not doc.LoadFile(): - return - - xconfig = doc.FirstChildElement('config') - if xconfig: - maxDiskUsage = xconfig.Attribute('max_disk_usage') - try: - self.maxDiskUsage = int(maxDiskUsage or '') - except ValueError: - pass - - def writeConfigXml(self): - """ Rewrites the config.xml to the root directory. This isn't - called automatically; an application may call this after - adjusting some parameters (such as self.maxDiskUsage). """ - - from panda3d.core import TiXmlDocument, TiXmlDeclaration, TiXmlElement - - filename = Filename(self.rootDir, self.ConfigBasename) - doc = TiXmlDocument(filename.toOsSpecific()) - decl = TiXmlDeclaration("1.0", "utf-8", "") - doc.InsertEndChild(decl) - - xconfig = TiXmlElement('config') - xconfig.SetAttribute('max_disk_usage', str(self.maxDiskUsage)) - doc.InsertEndChild(xconfig) - - # Write the file to a temporary filename, then atomically move - # it to its actual filename, to avoid race conditions when - # updating this file. - tfile = Filename.temporary(str(self.rootDir), '.xml') - if doc.SaveFile(tfile.toOsSpecific()): - tfile.renameTo(filename) - - - def checkDiskUsage(self): - """ Checks the total disk space used by all packages, and - removes old packages if necessary. """ - - totalSize = 0 - hosts = self.scanInstalledPackages() - for hostData in hosts: - for packageData in hostData.packages: - totalSize += packageData.totalSize - self.notify.info("Total Panda3D disk space used: %s MB" % ( - (totalSize + 524288) // 1048576)) - - if self.verifyContents == self.P3DVCNever: - # We're not allowed to delete anything anyway. - return - - self.notify.info("Configured max usage is: %s MB" % ( - (self.maxDiskUsage + 524288) // 1048576)) - if totalSize <= self.maxDiskUsage: - # Still within budget; no need to clean up anything. - return - - # OK, we're over budget. Now we have to remove old packages. - usedPackages = [] - for hostData in hosts: - for packageData in hostData.packages: - if packageData.package and packageData.package.installed: - # Don't uninstall any packages we're currently using. - continue - - usedPackages.append((packageData.lastUse, packageData)) - - # Sort the packages into oldest-first order. - usedPackages.sort() - - # Delete packages until we free up enough space. - packages = [] - for lastUse, packageData in usedPackages: - if totalSize <= self.maxDiskUsage: - break - totalSize -= packageData.totalSize - - if packageData.package: - packages.append(packageData.package) - else: - # If it's an unknown package, just delete it directly. - print("Deleting unknown package %s" % (packageData.pathname)) - self.rmtree(packageData.pathname) - - packages = self.deletePackages(packages) - if packages: - print("Unable to delete %s packages" % (len(packages))) - - return - - def stop(self): - """ This method can be called by JavaScript to stop the - application. """ - - # We defer the actual exit for a few frames, so we don't raise - # an exception and invalidate the JavaScript call; and also to - # help protect against race conditions as the application - # shuts down. - taskMgr.doMethodLater(0.5, sys.exit, 'exit') - - def run(self): - """ This method calls taskMgr.run(), with an optional - exception handler. This is generally the program's main loop - when running in a p3d environment (except on unusual platforms - like the iPhone, which have to hand the main loop off to the - OS, and don't use this interface). """ - - try: - taskMgr.run() - - except SystemExit as err: - # Presumably the window has already been shut down here, but shut - # it down again for good measure. - if hasattr(builtins, "base"): - base.destroy() - - self.notify.info("Normal exit with status %s." % repr(err.code)) - raise - - except: - # Some unexpected Python exception; pass it to the - # optional handler, if it is defined. - if self.exceptionHandler and not self.interactiveConsole: - self.exceptionHandler() - else: - raise - - def rmtree(self, filename): - """ This is like shutil.rmtree(), but it can remove read-only - files on Windows. It receives a Filename, the root directory - to delete. """ - if filename.isDirectory(): - for child in filename.scanDirectory(): - self.rmtree(Filename(filename, child)) - if not filename.rmdir(): - print("could not remove directory %s" % (filename)) - else: - if not filename.unlink(): - print("could not delete %s" % (filename)) - - def setSessionId(self, sessionId): - """ This message should come in at startup. """ - self.sessionId = sessionId - self.nextScriptId = self.sessionId * 1000 + 10000 - - def initPackedAppEnvironment(self): - """ This function sets up the Python environment suitably for - running a packed app. It should only run once in any given - session (and it includes logic to ensure this). """ - - if self.packedAppEnvironmentInitialized: - return - - self.packedAppEnvironmentInitialized = True - - vfs = VirtualFileSystem.getGlobalPtr() - - # Now set up Python to import this stuff. - VFSImporter.register() - sys.path.append(self.multifileRoot) - - # Make sure that $MAIN_DIR is set to the p3d root before we - # start executing the code in this file. - ExecutionEnvironment.setEnvironmentVariable("MAIN_DIR", Filename(self.multifileRoot).toOsSpecific()) - - # Put our root directory on the model-path, too. - getModelPath().appendDirectory(self.multifileRoot) - - if not self.trueFileIO: - # Replace the builtin open and file symbols so user code will get - # our versions by default, which can open and read files out of - # the multifile. - builtins.open = file.open - if sys.version_info < (3, 0): - builtins.file = file.open - builtins.execfile = file.execfile - os.listdir = file.listdir - os.walk = file.walk - os.path.join = file.join - os.path.isfile = file.isfile - os.path.isdir = file.isdir - os.path.exists = file.exists - os.path.lexists = file.lexists - os.path.getmtime = file.getmtime - os.path.getsize = file.getsize - sys.modules['glob'] = glob - - self.checkDiskUsage() - - def __startIfReady(self): - """ Called internally to start the application. """ - if self.started: - return - - if self.gotWindow and self.gotP3DFilename: - self.started = True - - # Now we can ignore future calls to startIfReady(). - self.ignore('AppRunner_startIfReady') - - # Hang a hook so we know when the window is actually opened. - self.acceptOnce('window-event', self.__windowEvent) - - # Look for the startup Python file. This might be a magic - # filename (like "__main__", or any filename that contains - # invalid module characters), so we can't just import it - # directly; instead, we go through the low-level importer. - - # If there's no p3d_info.xml file, we look for "main". - moduleName = 'main' - if self.p3dPackage: - mainName = self.p3dPackage.Attribute('main_module') - if mainName: - moduleName = mainName - - # Temporarily set this flag while we import the app, so - # that if the app calls run() within its own main.py, it - # will properly get ignored by ShowBase. - self.initialAppImport = True - - # Python won't let us import a module named __main__. So, - # we have to do that manually, via the VFSImporter. - if moduleName == '__main__': - dirName = Filename(self.multifileRoot).toOsSpecific() - importer = VFSImporter.VFSImporter(dirName) - loader = importer.find_module('__main__') - if loader is None: - raise ImportError('No module named __main__') - - mainModule = loader.load_module('__main__') - else: - __import__(moduleName) - mainModule = sys.modules[moduleName] - - # Check if it has a main() function. If so, call it. - if hasattr(mainModule, 'main') and hasattr(mainModule.main, '__call__'): - mainModule.main(self) - - # Now clear this flag. - self.initialAppImport = False - - if self.interactiveConsole: - # At this point, we have successfully loaded the app. - # If the interactive_console flag is enabled, stop the - # main loop now and give the user a Python prompt. - taskMgr.stop() - - def getPandaScriptObject(self): - """ Called by the browser to query the Panda instance's - toplevel scripting object, for querying properties in the - Panda instance. The attributes on this object are mapped to - document.pluginobject.main within the DOM. """ - - return self.main - - def setBrowserScriptObject(self, dom): - """ Called by the browser to supply the browser's toplevel DOM - object, for controlling the JavaScript and the document in the - same page with the Panda3D plugin. """ - - self.dom = dom - - # Now evaluate any deferred expressions. - for expression in self.deferredEvals: - self.scriptRequest('eval', self.dom, value = expression, - needsResponse = False) - self.deferredEvals = [] - - def setInstanceInfo(self, rootDir, logDirectory, superMirrorUrl, - verifyContents, main, respectPerPlatform): - """ Called by the browser to set some global information about - the instance. """ - - # rootDir is the root Panda3D install directory on the local - # machine. - self.rootDir = Filename.fromOsSpecific(rootDir) - - # logDirectory is the directory name where all log files end - # up. - if logDirectory: - self.logDirectory = Filename.fromOsSpecific(logDirectory) - else: - self.logDirectory = Filename(rootDir, 'log') - - # The "super mirror" URL, generally used only by panda3d.exe. - self.superMirrorUrl = superMirrorUrl - - # How anxious should we be about contacting the server for - # the latest code? - self.verifyContents = verifyContents - - # The initial "main" object, if specified. - if main is not None: - self.main = main - - self.respectPerPlatform = respectPerPlatform - #self.notify.info("respectPerPlatform = %s" % (self.respectPerPlatform)) - - # Now that we have rootDir, we can read the config file. - self.readConfigXml() - - - def addPackageInfo(self, name, platform, version, hostUrl, hostDir = None, - recurse = False): - """ Called by the browser for each one of the "required" - packages that were preloaded before starting the application. - If for some reason the package isn't already downloaded, this - will download it on the spot. Raises OSError on failure. """ - - host = self.getHost(hostUrl, hostDir = hostDir) - - if not host.hasContentsFile: - # Always pre-read these hosts' contents.xml files, even if - # we have P3DVCForce in effect, since presumably we've - # already forced them on the plugin side. - host.readContentsFile() - - if not host.downloadContentsFile(self.http): - # Couldn't download? Must have failed to download in the - # plugin as well. But since we launched, we probably have - # a copy already local; let's use it. - message = "Host %s cannot be downloaded, cannot preload %s." % (hostUrl, name) - if not host.hasContentsFile: - # This is weird. How did we launch without having - # this file at all? - raise OSError(message) - - # Just make it a warning and continue. - self.notify.warning(message) - - if name == 'panda3d' and not self.pandaHostUrl: - # A special case: in case we don't have the PackageHostUrl - # compiled in, infer it from the first package we - # installed named "panda3d". - self.pandaHostUrl = hostUrl - - if not platform: - platform = None - package = host.getPackage(name, version, platform = platform) - if not package: - if not recurse: - # Maybe the contents.xml file isn't current. Re-fetch it. - if host.redownloadContentsFile(self.http): - return self.addPackageInfo(name, platform, version, hostUrl, hostDir = hostDir, recurse = True) - - message = "Couldn't find %s %s on %s" % (name, version, hostUrl) - raise OSError(message) - - package.checkStatus() - if not package.downloadDescFile(self.http): - message = "Couldn't get desc file for %s" % (name) - raise OSError(message) - - if not package.downloadPackage(self.http): - message = "Couldn't download %s" % (name) - raise OSError(message) - - if not package.installPackage(self): - message = "Couldn't install %s" % (name) - raise OSError(message) - - if package.guiApp: - self.guiApp = True - init_app_for_gui() - - def setP3DFilename(self, p3dFilename, tokens, argv, instanceId, - interactiveConsole, p3dOffset = 0, p3dUrl = None): - """ Called by the browser to specify the p3d file that - contains the application itself, along with the web tokens - and/or command-line arguments. Once this method has been - called, the application is effectively started. """ - - # One day we will have support for multiple instances within a - # Python session. Against that day, we save the instance ID - # for this instance. - self.instanceId = instanceId - - self.tokens = tokens - self.argv = argv - - # We build up a token dictionary with care, so that if a given - # token appears twice in the token list, we record only the - # first value, not the second or later. This is consistent - # with the internal behavior of the core API. - self.tokenDict = {} - for token, keyword in tokens: - self.tokenDict.setdefault(token, keyword) - - # Also store the arguments on sys, for applications that - # aren't instance-ready. - sys.argv = argv - - # That means we now know the altHost in effect. - self.altHost = self.tokenDict.get('alt_host', None) - - # Tell the browser that Python is up and running, and ready to - # respond to queries. - self.notifyRequest('onpythonload') - - # Now go load the applet. - fname = Filename.fromOsSpecific(p3dFilename) - vfs = VirtualFileSystem.getGlobalPtr() - - if not vfs.exists(fname): - raise ArgumentError("No such file: %s" % (p3dFilename)) - - fname.makeAbsolute() - fname.setBinary() - mf = Multifile() - if p3dOffset == 0: - if not mf.openRead(fname): - raise ArgumentError("Not a Panda3D application: %s" % (p3dFilename)) - else: - if not mf.openRead(fname, p3dOffset): - raise ArgumentError("Not a Panda3D application: %s at offset: %s" % (p3dFilename, p3dOffset)) - - # Now load the p3dInfo file. - self.p3dInfo = None - self.p3dPackage = None - self.p3dConfig = None - self.allowPythonDev = False - - i = mf.findSubfile('p3d_info.xml') - if i >= 0 and hasattr(core, 'readXmlStream'): - stream = mf.openReadSubfile(i) - self.p3dInfo = core.readXmlStream(stream) - mf.closeReadSubfile(stream) - if self.p3dInfo: - self.p3dPackage = self.p3dInfo.FirstChildElement('package') - if self.p3dPackage: - self.p3dConfig = self.p3dPackage.FirstChildElement('config') - - xhost = self.p3dPackage.FirstChildElement('host') - while xhost: - self.__readHostXml(xhost) - xhost = xhost.NextSiblingElement('host') - - if self.p3dConfig: - allowPythonDev = self.p3dConfig.Attribute('allow_python_dev') - if allowPythonDev: - self.allowPythonDev = int(allowPythonDev) - guiApp = self.p3dConfig.Attribute('gui_app') - if guiApp: - self.guiApp = int(guiApp) - - trueFileIO = self.p3dConfig.Attribute('true_file_io') - if trueFileIO: - self.trueFileIO = int(trueFileIO) - - # The interactiveConsole flag can only be set true if the - # application has allow_python_dev set. - if not self.allowPythonDev and interactiveConsole: - raise Exception("Impossible, interactive_console set without allow_python_dev.") - self.interactiveConsole = interactiveConsole - - if self.allowPythonDev: - # Set the fps text to remind the user that - # allow_python_dev is enabled. - ConfigVariableString('frame-rate-meter-text-pattern').setValue('allow_python_dev %0.1f fps') - - if self.guiApp: - init_app_for_gui() - - self.initPackedAppEnvironment() - - # Mount the Multifile under self.multifileRoot. - vfs.mount(mf, self.multifileRoot, vfs.MFReadOnly) - self.p3dMultifile = mf - VFSImporter.reloadSharedPackages() - - self.loadMultifilePrcFiles(mf, self.multifileRoot) - self.gotP3DFilename = True - self.p3dFilename = fname - if p3dUrl: - # The url from which the p3d file was downloaded is - # provided if available. It is only for documentation - # purposes; the actual p3d file has already been - # downloaded to p3dFilename. - self.p3dUrl = core.URLSpec(p3dUrl) - - # Send this call to the main thread; don't call it directly. - messenger.send('AppRunner_startIfReady', taskChain = 'default') - - def __readHostXml(self, xhost): - """ Reads the data in the indicated entry. """ - - url = xhost.Attribute('url') - host = self.getHost(url) - host.readHostXml(xhost) - - # Scan for a matching . If found, it means we - # should use the alternate URL instead of the original URL. - if self.altHost: - xalthost = xhost.FirstChildElement('alt_host') - while xalthost: - keyword = xalthost.Attribute('keyword') - if keyword == self.altHost: - origUrl = xhost.Attribute('url') - newUrl = xalthost.Attribute('url') - self.altHostMap[origUrl] = newUrl - break - - xalthost = xalthost.NextSiblingElement('alt_host') - - def loadMultifilePrcFiles(self, mf, root): - """ Loads any prc files in the root of the indicated - Multifile, which is presumed to have been mounted already - under root. """ - - # We have to load these prc files explicitly, since the - # ConfigPageManager can't directly look inside the vfs. Use - # the Multifile interface to find the prc files, rather than - # vfs.scanDirectory(), so we only pick up the files in this - # particular multifile. - cpMgr = ConfigPageManager.getGlobalPtr() - for f in mf.getSubfileNames(): - fn = Filename(f) - if fn.getDirname() == '' and fn.getExtension() == 'prc': - pathname = '%s/%s' % (root, f) - - alreadyLoaded = False - for cpi in range(cpMgr.getNumImplicitPages()): - if cpMgr.getImplicitPage(cpi).getName() == pathname: - # No need to load this file twice. - alreadyLoaded = True - break - - if not alreadyLoaded: - data = file.open(Filename(pathname), 'r').read() - cp = loadPrcFileData(pathname, data) - # Set it to sort value 20, behind the implicit pages. - cp.setSort(20) - - - def __clearWindowProperties(self): - """ Clears the windowPrc file that was created in a previous - call to setupWindow(), if any. """ - - if self.windowPrc: - unloadPrcFile(self.windowPrc) - self.windowPrc = None - WindowProperties.clearDefault() - - # However, we keep the self.windowProperties object around, in - # case an application wants to return the window to the - # browser frame. - - def setupWindow(self, windowType, x, y, width, height, - parent): - """ Applies the indicated window parameters to the prc - settings, for future windows; or applies them directly to the - main window if the window has already been opened. This is - called by the browser. """ - - if self.started and base.win: - # If we've already got a window, this must be a - # resize/reposition request. - wp = WindowProperties() - if x or y or windowType == 'embedded': - wp.setOrigin(x, y) - if width or height: - wp.setSize(width, height) - if windowType == 'embedded': - wp.setParentWindow(parent) - wp.setFullscreen(False) - base.win.requestProperties(wp) - self.windowProperties = wp - return - - # If we haven't got a window already, start 'er up. Apply the - # requested setting to the prc file, and to the default - # WindowProperties structure. - - self.__clearWindowProperties() - - if windowType == 'hidden': - data = 'window-type none\n' - else: - data = 'window-type onscreen\n' - - wp = WindowProperties.getDefault() - - wp.clearParentWindow() - wp.clearOrigin() - wp.clearSize() - - wp.setFullscreen(False) - if windowType == 'fullscreen': - wp.setFullscreen(True) - - if windowType == 'embedded': - wp.setParentWindow(parent) - - if x or y or windowType == 'embedded': - wp.setOrigin(x, y) - - if width or height: - wp.setSize(width, height) - - self.windowProperties = wp - self.windowPrc = loadPrcFileData("setupWindow", data) - WindowProperties.setDefault(wp) - - self.gotWindow = True - - # Send this call to the main thread; don't call it directly. - messenger.send('AppRunner_startIfReady', taskChain = 'default') - - def setRequestFunc(self, func): - """ This method is called by the browser at startup to supply a - function that can be used to deliver requests upstream, to the - core API, and thereby to the browser. """ - self.requestFunc = func - - def sendRequest(self, request, *args): - """ Delivers a request to the browser via self.requestFunc. - This low-level function is not intended to be called directly - by user code. """ - - assert self.requestFunc - return self.requestFunc(self.instanceId, request, args) - - def __windowEvent(self, win): - """ This method is called when we get a window event. We - listen for this to detect when the window has been - successfully opened. """ - - if not self.windowOpened: - self.windowOpened = True - - # Now that the window is open, we don't need to keep those - # prc settings around any more. - self.__clearWindowProperties() - - # Inform the plugin and browser. - self.notifyRequest('onwindowopen') - - def notifyRequest(self, message): - """ Delivers a notify request to the browser. This is a "this - happened" type notification; it also triggers some JavaScript - code execution, if indicated in the HTML tags, and may also - trigger some internal automatic actions. (For instance, the - plugin takes down the splash window when it sees the - onwindowopen notification. """ - - self.sendRequest('notify', message.lower()) - - def evalScript(self, expression, needsResponse = False): - """ Evaluates an arbitrary JavaScript expression in the global - DOM space. This may be deferred if necessary if needsResponse - is False and self.dom has not yet been assigned. If - needsResponse is true, this waits for the value and returns - it, which means it cannot be deferred. """ - - if not self.dom: - # Defer the expression. - assert not needsResponse - self.deferredEvals.append(expression) - else: - # Evaluate it now. - return self.scriptRequest('eval', self.dom, value = expression, - needsResponse = needsResponse) - - def scriptRequest(self, operation, object, propertyName = '', - value = None, needsResponse = True): - """ Issues a new script request to the browser. This queries - or modifies one of the browser's DOM properties. This is a - low-level method that user code should not call directly; - instead, just operate on the Python wrapper objects that - shadow the DOM objects, beginning with appRunner.dom. - - operation may be one of [ 'get_property', 'set_property', - 'call', 'evaluate' ]. - - object is the browser object to manipulate, or the scope in - which to evaluate the expression. - - propertyName is the name of the property to manipulate, if - relevant (set to None for the default method name). - - value is the new value to assign to the property for - set_property, or the parameter list for call, or the string - expression for evaluate. - - If needsResponse is true, this method will block until the - return value is received from the browser, and then it returns - that value. Otherwise, it returns None immediately, without - waiting for the browser to process the request. - """ - uniqueId = self.nextScriptId - self.nextScriptId = (self.nextScriptId + 1) % 0xffffffff - self.sendRequest('script', operation, object, - propertyName, value, needsResponse, uniqueId) - - if needsResponse: - # Now wait for the response to come in. - result = self.sendRequest('wait_script_response', uniqueId) - return result - - def dropObject(self, objectId): - """ Inform the parent process that we no longer have an - interest in the P3D_object corresponding to the indicated - objectId. Not intended to be called by user code. """ - - self.sendRequest('drop_p3dobj', objectId) - -def dummyAppRunner(tokens = [], argv = None): - """ This function creates a dummy global AppRunner object, which - is useful for testing running in a packaged environment without - actually bothering to package up the application. Call this at - the start of your application to enable it. - - It places the current working directory under /mf, as if it were - mounted from a packed multifile. It doesn't convert egg files to - bam files, of course; and there are other minor differences from - running in an actual packaged environment. But it can be a useful - first-look sanity check. """ - - if AppRunnerGlobal.appRunner: - print("Already have AppRunner, not creating a new one.") - return AppRunnerGlobal.appRunner - - appRunner = AppRunner() - appRunner.dummy = True - AppRunnerGlobal.appRunner = appRunner - - platform = PandaSystem.getPlatform() - version = PandaSystem.getPackageVersionString() - hostUrl = PandaSystem.getPackageHostUrl() - - if platform.startswith('win'): - rootDir = Filename(Filename.getUserAppdataDirectory(), 'Panda3D') - elif platform.startswith('osx'): - rootDir = Filename(Filename.getHomeDirectory(), 'Library/Caches/Panda3D') - else: - rootDir = Filename(Filename.getHomeDirectory(), '.panda3d') - - appRunner.rootDir = rootDir - appRunner.logDirectory = Filename(rootDir, 'log') - - # Of course we will have the panda3d application loaded. - appRunner.addPackageInfo('panda3d', platform, version, hostUrl) - - appRunner.tokens = tokens - appRunner.tokenDict = dict(tokens) - if argv is None: - argv = sys.argv - appRunner.argv = argv - appRunner.altHost = appRunner.tokenDict.get('alt_host', None) - - appRunner.p3dInfo = None - appRunner.p3dPackage = None - - # Mount the current directory under the multifileRoot, as if it - # were coming from a multifile. - cwd = ExecutionEnvironment.getCwd() - vfs = VirtualFileSystem.getGlobalPtr() - vfs.mount(cwd, appRunner.multifileRoot, vfs.MFReadOnly) - - appRunner.initPackedAppEnvironment() - - return appRunner - diff --git a/direct/src/p3d/DWBPackageInstaller.py b/direct/src/p3d/DWBPackageInstaller.py deleted file mode 100644 index c4daa67cb1..0000000000 --- a/direct/src/p3d/DWBPackageInstaller.py +++ /dev/null @@ -1,96 +0,0 @@ -__all__ = ["DWBPackageInstaller"] - -from direct.p3d.PackageInstaller import PackageInstaller -from direct.gui.DirectWaitBar import DirectWaitBar -from direct.gui import DirectGuiGlobals as DGG - -class DWBPackageInstaller(DirectWaitBar, PackageInstaller): - """ This class presents a PackageInstaller that also inherits from - DirectWaitBar, so it updates its own GUI as it downloads. - - Specify perPackage = True to make the progress bar reset for each - package, or False (the default) to show one continuous progress - bar for all packages. - - Specify updateText = True (the default) to update the text label - with the name of the package or False to leave it up to you to set - it. - - You can specify a callback function with finished = func; this - function will be called, with one boolean parameter, when the - download has completed. The parameter will be true on success, or - false on failure. - """ - - def __init__(self, appRunner, parent = None, **kw): - PackageInstaller.__init__(self, appRunner) - - optiondefs = ( - ('borderWidth', (0.01, 0.01), None), - ('relief', DGG.SUNKEN, self.setRelief), - ('range', 1, self.setRange), - ('barBorderWidth', (0.01, 0.01), self.setBarBorderWidth), - ('barColor', (0.424, 0.647, 0.878, 1), self.setBarColor), - ('barRelief', DGG.RAISED, self.setBarRelief), - ('text', 'Starting', self.setText), - ('text_pos', (0, -0.025), None), - ('text_scale', 0.1, None), - ('perPackage', False, None), - ('updateText', True, None), - ('finished', None, None), - ) - self.defineoptions(kw, optiondefs) - DirectWaitBar.__init__(self, parent, **kw) - self.initialiseoptions(DWBPackageInstaller) - self.updateBarStyle() - - # Hidden by default until the download begins. - self.hide() - - def cleanup(self): - PackageInstaller.cleanup(self) - DirectWaitBar.destroy(self) - - def destroy(self): - PackageInstaller.cleanup(self) - DirectWaitBar.destroy(self) - - def packageStarted(self, package): - """ This callback is made for each package between - downloadStarted() and downloadFinished() to indicate the start - of a new package. """ - if self['updateText']: - self['text'] = 'Installing %s' % (package.getFormattedName()) - self.show() - - def packageProgress(self, package, progress): - """ This callback is made repeatedly between packageStarted() - and packageFinished() to update the current progress on the - indicated package only. The progress value ranges from 0 - (beginning) to 1 (complete). """ - - if self['perPackage']: - self['value'] = progress * self['range'] - - def downloadProgress(self, overallProgress): - """ This callback is made repeatedly between downloadStarted() - and downloadFinished() to update the current progress through - all packages. The progress value ranges from 0 (beginning) to - 1 (complete). """ - - if not self['perPackage']: - self['value'] = overallProgress * self['range'] - - def downloadFinished(self, success): - """ This callback is made when all of the packages have been - downloaded and installed (or there has been some failure). If - all packages where successfully installed, success is True. - - If there were no packages that required downloading, this - callback will be made immediately, *without* a corresponding - call to downloadStarted(). """ - - self.hide() - - if self['finished']: - self['finished'](success) diff --git a/direct/src/p3d/DeploymentTools.py b/direct/src/p3d/DeploymentTools.py deleted file mode 100644 index ebc20bfda9..0000000000 --- a/direct/src/p3d/DeploymentTools.py +++ /dev/null @@ -1,1496 +0,0 @@ -""" This module is used to build a graphical installer -or a standalone executable from a p3d file. It will try -to build for as many platforms as possible. """ - -__all__ = ["Standalone", "Installer"] - -import os, sys, subprocess, tarfile, shutil, time, zipfile, socket, getpass, struct -import gzip, plistlib -from direct.directnotify.DirectNotifyGlobal import * -from direct.showbase.AppRunnerGlobal import appRunner -from panda3d.core import PandaSystem, HTTPClient, Filename, VirtualFileSystem, Multifile -from panda3d.core import TiXmlDocument, TiXmlDeclaration, TiXmlElement, readXmlStream -from panda3d.core import PNMImage, PNMFileTypeRegistry, StringStream -from direct.stdpy.file import * -from direct.p3d.HostInfo import HostInfo -# This is important for some reason -import encodings - -try: - import pwd -except ImportError: - pwd = None - -if sys.version_info >= (3, 0): - xrange = range - from io import BytesIO, TextIOWrapper -else: - from io import BytesIO - from StringIO import StringIO - -# Make sure this matches with the magic in p3dEmbedMain.cxx. -P3DEMBED_MAGIC = 0xFF3D3D00 - -# This filter function is used when creating -# an archive that should be owned by root. -def archiveFilter(info): - basename = os.path.basename(info.name) - if basename in [".DS_Store", "Thumbs.db"]: - return None - - info.uid = info.gid = 0 - info.uname = info.gname = "root" - - # All files without an extension get mode 0755, - # all other files are chmodded to 0644. - # Somewhat hacky, but it's the only way - # permissions can work on a Windows box. - if info.type != tarfile.DIRTYPE and '.' in info.name.rsplit('/', 1)[-1]: - info.mode = 0o644 - else: - info.mode = 0o755 - - return info - -# Hack to make all files in a tar file owned by root. -# The tarfile module doesn't have filter functionality until Python 2.7. -# Yay duck typing! -class TarInfoRoot(tarfile.TarInfo): - uid = property(lambda self: 0, lambda self, x: None) - gid = property(lambda self: 0, lambda self, x: None) - uname = property(lambda self: "root", lambda self, x: None) - gname = property(lambda self: "root", lambda self, x: None) - mode = property(lambda self: 0o644 if self.type != tarfile.DIRTYPE and \ - '.' in self.name.rsplit('/', 1)[-1] else 0o755, - lambda self, x: None) - -# On OSX, the root group is named "wheel". -class TarInfoRootOSX(TarInfoRoot): - gname = property(lambda self: "wheel", lambda self, x: None) - - -class Standalone: - """ This class creates a standalone executable from a given .p3d file. """ - notify = directNotify.newCategory("Standalone") - - def __init__(self, p3dfile, tokens = {}): - self.p3dfile = Filename(p3dfile) - self.basename = self.p3dfile.getBasenameWoExtension() - self.tokens = tokens - - self.tempDir = Filename.temporary("", self.basename, "") + "/" - self.tempDir.makeDir() - self.host = HostInfo(PandaSystem.getPackageHostUrl(), appRunner = appRunner, hostDir = self.tempDir, asMirror = False, perPlatform = True) - - self.http = HTTPClient.getGlobalPtr() - if not self.host.hasContentsFile: - if not self.host.readContentsFile(): - if not self.host.downloadContentsFile(self.http): - Standalone.notify.error("couldn't read host") - return - - def __del__(self): - try: - appRunner.rmtree(self.tempDir) - except: - try: shutil.rmtree(self.tempDir.toOsSpecific()) - except: pass - - def buildAll(self, outputDir = "."): - """ Builds standalone executables for every known platform, - into the specified output directory. """ - - platforms = set() - for package in self.host.getPackages(name = "p3dembed"): - platforms.add(package.platform) - if len(platforms) == 0: - Standalone.notify.warning("No platforms found to build for!") - - if 'win32' in platforms and 'win_i386' in platforms: - platforms.remove('win32') - - outputDir = Filename(outputDir + "/") - outputDir.makeDir() - for platform in platforms: - if platform.startswith("win"): - self.build(Filename(outputDir, platform + "/" + self.basename + ".exe"), platform) - else: - self.build(Filename(outputDir, platform + "/" + self.basename), platform) - - def build(self, output, platform = None, extraTokens = {}): - """ Builds a standalone executable and stores it into the path - indicated by the 'output' argument. You can specify to build for - a different platform by altering the 'platform' argument. """ - - if platform == None: - platform = PandaSystem.getPlatform() - - vfs = VirtualFileSystem.getGlobalPtr() - - for package in self.host.getPackages(name = "p3dembed", platform = platform): - if not package.downloadDescFile(self.http): - Standalone.notify.warning(" -> %s failed for platform %s" % (package.packageName, package.platform)) - continue - if not package.downloadPackage(self.http): - Standalone.notify.warning(" -> %s failed for platform %s" % (package.packageName, package.platform)) - continue - - # Figure out where p3dembed might be now. - if package.platform.startswith("win"): - # Use p3dembedw unless console_environment was set. - cEnv = extraTokens.get("console_environment", self.tokens.get("console_environment", 0)) - if cEnv != "" and int(cEnv) != 0: - p3dembed = Filename(self.host.hostDir, "p3dembed/%s/p3dembed.exe" % package.platform) - else: - p3dembed = Filename(self.host.hostDir, "p3dembed/%s/p3dembedw.exe" % package.platform) - # Fallback for older p3dembed versions - if not vfs.exists(p3dembed): - Filename(self.host.hostDir, "p3dembed/%s/p3dembed.exe" % package.platform) - else: - p3dembed = Filename(self.host.hostDir, "p3dembed/%s/p3dembed" % package.platform) - - if not vfs.exists(p3dembed): - Standalone.notify.warning(" -> %s failed for platform %s" % (package.packageName, package.platform)) - continue - - return self.embed(output, p3dembed, extraTokens) - - Standalone.notify.error("Failed to build standalone for platform %s" % platform) - - def embed(self, output, p3dembed, extraTokens = {}): - """ Embeds the p3d file into the provided p3dembed executable. - This function is not really useful - use build() or buildAll() instead. """ - - # Load the p3dembed data into memory - size = p3dembed.getFileSize() - p3dembed_data = VirtualFileSystem.getGlobalPtr().readFile(p3dembed, True) - assert len(p3dembed_data) == size - - # Find the magic size string and replace it with the real size, - # regardless of the endianness of the p3dembed executable. - p3dembed_data = p3dembed_data.replace(struct.pack('>I', P3DEMBED_MAGIC), - struct.pack('>I', size)) - p3dembed_data = p3dembed_data.replace(struct.pack(' %s failed for platform %s" % (package.packageName, package.platform)) - return [] - if not package.downloadPackage(self.http): - Standalone.notify.warning(" -> %s failed for platform %s" % (package.packageName, package.platform)) - return [] - - filenames = [] - vfs = VirtualFileSystem.getGlobalPtr() - for e in package.extracts: - if e.basename not in ["p3dembed", "p3dembed.exe", "p3dembed.exe.manifest", "p3dembedw.exe", "p3dembedw.exe.manifest"]: - filename = Filename(package.getPackageDir(), e.filename) - filename.makeAbsolute() - if vfs.exists(filename): - filenames.append(filename) - else: - Standalone.notify.error("%s mentioned in xml, but does not exist" % e.filename) - - return filenames - - -class PackageTree: - """ A class used internally to build a temporary package - tree for inclusion into an installer. """ - - def __init__(self, platform, hostDir, hostUrl): - self.platform = platform - self.hosts = {} - self.packages = {} - self.hostUrl = hostUrl - self.hostDir = Filename(hostDir) - self.hostDir.makeDir() - self.http = HTTPClient.getGlobalPtr() - - def getHost(self, hostUrl): - if hostUrl in self.hosts: - return self.hosts[hostUrl] - - host = HostInfo(hostUrl, appRunner = appRunner, hostDir = self.hostDir, asMirror = False, perPlatform = True) - if not host.hasContentsFile: - if not host.readContentsFile(): - if not host.downloadContentsFile(self.http): - Installer.notify.error("couldn't read host %s" % host.hostUrl) - return None - self.hosts[hostUrl] = host - return host - - def installPackage(self, name, version, hostUrl = None): - """ Installs the named package into the tree. """ - - if hostUrl is None: - hostUrl = self.hostUrl - - pkgIdent = (name, version) - if pkgIdent in self.packages: - return self.packages[pkgIdent] - - package = None - # Always try the super host first, if any. - if appRunner and appRunner.superMirrorUrl: - superHost = self.getHost(appRunner.superMirrorUrl) - if self.platform: - package = superHost.getPackage(name, version, self.platform) - if not package: - package = superHost.getPackage(name, version) - - if not package: - host = self.getHost(hostUrl) - if self.platform: - package = host.getPackage(name, version, self.platform) - if not package: - package = host.getPackage(name, version) - - if not package: - Installer.notify.error("Package %s %s for %s not known on %s" % ( - name, version, self.platform, hostUrl)) - return - - package.installed = True # Hack not to let it unnecessarily install itself - if not package.downloadDescFile(self.http): - Installer.notify.error(" -> %s failed for platform %s" % (package.packageName, package.platform)) - return - if not package.downloadPackage(self.http): - Installer.notify.error(" -> %s failed for platform %s" % (package.packageName, package.platform)) - return - - self.packages[pkgIdent] = package - - # Check for any dependencies. - for rname, rversion, rhost in package.requires: - self.installPackage(rname, rversion, rhost.hostUrl) - - return package - - -class Icon: - """ This class is used to create an icon for various platforms. """ - notify = directNotify.newCategory("Icon") - - def __init__(self): - self.images = {} - - def addImage(self, image): - """ Adds an image to the icon. Returns False on failure, True on success. - Only one image per size can be loaded, and the image size must be square. """ - - if not isinstance(image, PNMImage): - fn = image - if not isinstance(fn, Filename): - fn = Filename.fromOsSpecific(fn) - - image = PNMImage() - if not image.read(fn): - Icon.notify.warning("Image '%s' could not be read" % fn.getBasename()) - return False - - if image.getXSize() != image.getYSize(): - Icon.notify.warning("Ignoring image without square size") - return False - - self.images[image.getXSize()] = image - - return True - - def generateMissingImages(self): - """ Generates image sizes that should be present but aren't by scaling - from the next higher size. """ - - for required_size in (256, 128, 48, 32, 16): - if required_size in self.images: - continue - - sizes = sorted(self.images.keys()) - if required_size * 2 in sizes: - from_size = required_size * 2 - else: - from_size = 0 - for from_size in sizes: - if from_size > required_size: - break - - if from_size > required_size: - Icon.notify.warning("Generating %dx%d icon by scaling down %dx%d image" % (required_size, required_size, from_size, from_size)) - - image = PNMImage(required_size, required_size) - if self.images[from_size].hasAlpha(): - image.addAlpha() - image.quickFilterFrom(self.images[from_size]) - self.images[required_size] = image - else: - Icon.notify.warning("Cannot generate %dx%d icon; no higher resolution image available" % (required_size, required_size)) - - def _write_bitmap(self, fp, image, size, bpp): - """ Writes the bitmap header and data of an .ico file. """ - - fp.write(struct.pack('= 256: - # Find closest pixel instead. - index = closest_indices[index - 256] - fp.write(struct.pack('> 3) & 3) - for y in xrange(size): - mask = 0 - num_bits = 7 - for x in xrange(size): - a = image.get_alpha_val(x, size - y - 1) - if a <= 1: - mask |= (1 << num_bits) - num_bits -= 1 - if num_bits < 0: - fp.write(struct.pack('> 3 - if andsize % 4 != 0: - andsize += 4 - (andsize % 4) - fp.write(b'\x00' * (andsize * size)) - - def makeICO(self, fn): - """ Writes the images to a Windows ICO file. Returns True on success. """ - - if not isinstance(fn, Filename): - fn = Filename.fromOsSpecific(fn) - fn.setBinary() - - # ICO files only support resolutions up to 256x256. - count = 0 - for size in self.images.keys(): - if size < 256: - count += 1 - if size <= 256: - count += 1 - dataoffs = 6 + count * 16 - - ico = open(fn, 'wb') - ico.write(struct.pack('= 256: - continue - ico.write(struct.pack('> 3 - if andsize % 4 != 0: - andsize += 4 - (andsize % 4) - datasize = 40 + 256 * 4 + (xorsize + andsize) * size - - ico.write(struct.pack(' 256: - continue - elif size == 256: - ico.write(b'\0\0') - else: - ico.write(struct.pack('> 3 - if andsize % 4 != 0: - andsize += 4 - (andsize % 4) - datasize = 40 + (xorsize + andsize) * size - - ico.write(struct.pack('I', len(pngdata))) - icns.write(pngdata) - - elif size in icon_types: - # If it has an alpha channel, we write out a mask too. - if image.hasAlpha(): - icns.write(mask_types[size]) - icns.write(struct.pack('>I', size * size + 8)) - - for y in xrange(size): - for x in xrange(size): - icns.write(struct.pack('I', size * size * 4 + 8)) - - for y in xrange(size): - for x in xrange(size): - r, g, b = image.getXel(x, y) - icns.write(struct.pack('>BBBB', 0, int(r * 255), int(g * 255), int(b * 255))) - - length = icns.tell() - icns.seek(4) - icns.write(struct.pack('>I', length)) - icns.close() - - return True - - -class Installer: - """ This class creates a (graphical) installer from a given .p3d file. """ - notify = directNotify.newCategory("Installer") - - def __init__(self, p3dfile, shortname, fullname, version, tokens = {}): - self.p3dFilename = p3dfile - if not shortname: - shortname = p3dfile.getBasenameWoExtension() - self.shortname = shortname - self.fullname = fullname - self.version = str(version) - self.includeRequires = False - self.offerRun = True - self.offerDesktopShortcut = True - self.licensename = "" - self.licensefile = Filename() - self.authorid = "org.panda3d" - self.authorname = os.environ.get("DEBFULLNAME", "") - self.authoremail = os.environ.get("DEBEMAIL", "") - self.icon = None - - # Try to determine a default author name ourselves. - uname = None - if pwd is not None and hasattr(os, 'getuid'): - uinfo = pwd.getpwuid(os.getuid()) - if uinfo: - uname = uinfo.pw_name - if not self.authorname: - self.authorname = \ - uinfo.pw_gecos.split(',', 1)[0] - - # Fallbacks in case that didn't work or wasn't supported. - if not uname: - uname = getpass.getuser() - if not self.authorname: - self.authorname = uname - if not self.authoremail and ' ' not in uname: - self.authoremail = "%s@%s" % (uname, socket.gethostname()) - - # Load the p3d file to read out the required packages - mf = Multifile() - if not mf.openRead(self.p3dFilename): - Installer.notify.error("Not a Panda3D application: %s" % (p3dfile)) - return - - # Now load the p3dInfo file. - self.hostUrl = None - self.requires = [] - self.extracts = [] - i = mf.findSubfile('p3d_info.xml') - if i >= 0: - stream = mf.openReadSubfile(i) - p3dInfo = readXmlStream(stream) - mf.closeReadSubfile(stream) - if p3dInfo: - p3dPackage = p3dInfo.FirstChildElement('package') - p3dHost = p3dPackage.FirstChildElement('host') - if p3dHost.Attribute('url'): - self.hostUrl = p3dHost.Attribute('url') - p3dRequires = p3dPackage.FirstChildElement('requires') - while p3dRequires: - self.requires.append(( - p3dRequires.Attribute('name'), - p3dRequires.Attribute('version'), - p3dRequires.Attribute('host'))) - p3dRequires = p3dRequires.NextSiblingElement('requires') - - p3dExtract = p3dPackage.FirstChildElement('extract') - while p3dExtract: - filename = p3dExtract.Attribute('filename') - self.extracts.append(filename) - p3dExtract = p3dExtract.NextSiblingElement('extract') - - if not self.fullname: - p3dConfig = p3dPackage.FirstChildElement('config') - if p3dConfig: - self.fullname = p3dConfig.Attribute('display_name') - else: - Installer.notify.warning("No p3d_info.xml was found in .p3d archive.") - - mf.close() - - if not self.hostUrl: - self.hostUrl = PandaSystem.getPackageHostUrl() - if not self.hostUrl: - self.hostUrl = self.standalone.host.hostUrl - Installer.notify.warning("No host URL was specified by .p3d archive. Falling back to %s" % (self.hostUrl)) - - if not self.fullname: - self.fullname = self.shortname - - self.tempDir = Filename.temporary("", self.shortname, "") + "/" - self.tempDir.makeDir() - self.__tempRoots = {} - - if self.extracts: - # Copy .p3d to a temporary file so we can remove the extracts. - p3dfile = Filename(self.tempDir, self.p3dFilename.getBasename()) - shutil.copyfile(self.p3dFilename.toOsSpecific(), p3dfile.toOsSpecific()) - mf = Multifile() - if not mf.openReadWrite(p3dfile): - Installer.notify.error("Failure to open %s for writing." % (p3dfile)) - - # We don't really need this silly thing when embedding, anyway. - mf.setHeaderPrefix("") - - for fn in self.extracts: - if not mf.removeSubfile(fn): - Installer.notify.error("Failure to remove %s from multifile." % (p3dfile)) - - mf.repack() - mf.close() - - self.standalone = Standalone(p3dfile, tokens) - - def __del__(self): - try: - appRunner.rmtree(self.tempDir) - except: - try: shutil.rmtree(self.tempDir.toOsSpecific()) - except: pass - - def installPackagesInto(self, hostDir, platform): - """ Installs the packages required by the .p3d file into - the specified directory, for the given platform. """ - - if not self.includeRequires: - return - - # Write out the extracts from the original .p3d. - if self.extracts: - mf = Multifile() - if not mf.openRead(self.p3dFilename): - Installer.notify.error("Failed to open .p3d archive: %s" % (filename)) - - for filename in self.extracts: - i = mf.findSubfile(filename) - if i < 0: - Installer.notify.error("Cannot find extract in .p3d archive: %s" % (filename)) - continue - - if not mf.extractSubfile(i, Filename(hostDir, filename)): - Installer.notify.error("Failed to extract file from .p3d archive: %s" % (filename)) - mf.close() - - pkgTree = PackageTree(platform, hostDir, self.hostUrl) - pkgTree.installPackage("images", None, self.standalone.host.hostUrl) - - for name, version, hostUrl in self.requires: - pkgTree.installPackage(name, version, hostUrl) - - # Remove the extracted files from the compressed archive, to save space. - vfs = VirtualFileSystem.getGlobalPtr() - for package in pkgTree.packages.values(): - if package.uncompressedArchive: - archive = Filename(package.getPackageDir(), package.uncompressedArchive.filename) - if not archive.exists(): - continue - - mf = Multifile() - # Make sure that it isn't mounted before altering it, just to be safe - vfs.unmount(archive) - os.chmod(archive.toOsSpecific(), 0o644) - if not mf.openReadWrite(archive): - Installer.notify.warning("Failed to open archive %s" % (archive)) - continue - - # We don't iterate over getNumSubfiles because we're - # removing subfiles while we're iterating over them. - subfiles = mf.getSubfileNames() - for subfile in subfiles: - # We do *NOT* call vfs.exists here in case the package is mounted. - if Filename(package.getPackageDir(), subfile).exists(): - Installer.notify.debug("Removing already-extracted %s from multifile" % (subfile)) - mf.removeSubfile(subfile) - - # This seems essential for mf.close() not to crash later. - mf.repack() - - # If we have no subfiles left, we can just remove the multifile. - #XXX rdb: it seems that removing it causes trouble, so let's not. - #if mf.getNumSubfiles() == 0: - # Installer.notify.info("Removing empty archive %s" % (package.uncompressedArchive.filename)) - # mf.close() - # archive.unlink() - #else: - mf.close() - try: os.chmod(archive.toOsSpecific(), 0o444) - except: pass - - # Write out our own contents.xml file. - doc = TiXmlDocument() - decl = TiXmlDeclaration("1.0", "utf-8", "") - doc.InsertEndChild(decl) - - xcontents = TiXmlElement("contents") - for package in pkgTree.packages.values(): - xpackage = TiXmlElement('package') - xpackage.SetAttribute('name', package.packageName) - - filename = package.packageName + "/" - - if package.packageVersion: - xpackage.SetAttribute('version', package.packageVersion) - filename += package.packageVersion + "/" - - if package.platform: - xpackage.SetAttribute('platform', package.platform) - filename += package.platform + "/" - assert package.platform == platform - - xpackage.SetAttribute('per_platform', '1') - - filename += package.descFileBasename - xpackage.SetAttribute('filename', filename) - xcontents.InsertEndChild(xpackage) - - doc.InsertEndChild(xcontents) - doc.SaveFile(Filename(hostDir, "contents.xml").toOsSpecific()) - - def buildAll(self, outputDir = "."): - """ Creates a (graphical) installer for every known platform. - Call this after you have set the desired parameters. """ - - platforms = set() - for package in self.standalone.host.getPackages(name = "p3dembed"): - platforms.add(package.platform) - if len(platforms) == 0: - Installer.notify.warning("No platforms found to build for!") - - if 'win32' in platforms and 'win_i386' in platforms: - platforms.remove('win32') - - outputDir = Filename(outputDir + "/") - outputDir.makeDir() - for platform in platforms: - output = Filename(outputDir, platform + "/") - output.makeDir() - self.build(output, platform) - - def build(self, output, platform = None): - """ Builds (graphical) installers and stores it into the path - indicated by the 'output' argument. You can specify to build for - a different platform by altering the 'platform' argument. - If 'output' is a directory, the installer will be stored in it. """ - - if platform == None: - platform = PandaSystem.getPlatform() - - if platform.startswith("win"): - self.buildNSIS(output, platform) - return - elif "_" in platform: - osname, arch = platform.split("_", 1) - if osname == "linux": - self.buildDEB(output, platform) - self.buildArch(output, platform) - return - elif osname == "osx": - self.buildPKG(output, platform) - return - Installer.notify.info("Ignoring unknown platform " + platform) - - def __buildTempLinux(self, platform): - """ Builds a filesystem for Linux. Used so that buildDEB, - buildRPM and buildArch can share the same temp directory. """ - - if platform in self.__tempRoots: - return self.__tempRoots[platform] - - tempdir = Filename(self.tempDir, platform) - tempdir.makeDir() - - Filename(tempdir, "usr/bin/").makeDir() - if self.includeRequires: - extraTokens = {"host_dir" : "/usr/lib/" + self.shortname.lower(), - "start_dir" : "/usr/lib/" + self.shortname.lower()} - else: - extraTokens = {} - self.standalone.build(Filename(tempdir, "usr/bin/" + self.shortname.lower()), platform, extraTokens) - if not self.licensefile.empty(): - Filename(tempdir, "usr/share/doc/%s/" % self.shortname.lower()).makeDir() - shutil.copyfile(self.licensefile.toOsSpecific(), Filename(tempdir, "usr/share/doc/%s/copyright" % self.shortname.lower()).toOsSpecific()) - shutil.copyfile(self.licensefile.toOsSpecific(), Filename(tempdir, "usr/share/doc/%s/LICENSE" % self.shortname.lower()).toOsSpecific()) - - # Add an image file to /usr/share/pixmaps/ - iconFile = None - if self.icon is not None: - iconImage = None - if 48 in self.icon.images: - iconImage = self.icon.images[48] - elif 64 in self.icon.images: - iconImage = self.icon.images[64] - elif 32 in self.icon.images: - iconImage = self.icon.images[32] - else: - Installer.notify.warning("No suitable icon image for Linux provided, should preferably be 48x48 in size") - - if iconImage is not None: - iconFile = Filename(tempdir, "usr/share/pixmaps/%s.png" % self.shortname) - iconFile.setBinary() - iconFile.makeDir() - if not iconImage.write(iconFile): - Installer.notify.warning("Failed to write icon file for Linux") - iconFile.unlink() - iconFile = None - - # Write a .desktop file to /usr/share/applications/ - desktopFile = Filename(tempdir, "usr/share/applications/%s.desktop" % self.shortname.lower()) - desktopFile.setText() - desktopFile.makeDir() - desktop = open(desktopFile.toOsSpecific(), 'w') - desktop.write("[Desktop Entry]\n") - desktop.write("Name=%s\n" % self.fullname) - desktop.write("Exec=%s\n" % self.shortname.lower()) - if iconFile is not None: - desktop.write("Icon=%s\n" % iconFile.getBasename()) - - # Set the "Terminal" option based on whether or not a console env is requested - cEnv = self.standalone.tokens.get("console_environment", "") - if cEnv == "" or int(cEnv) == 0: - desktop.write("Terminal=false\n") - else: - desktop.write("Terminal=true\n") - - desktop.write("Type=Application\n") - desktop.close() - - if self.includeRequires or self.extracts: - hostDir = Filename(tempdir, "usr/lib/%s/" % self.shortname.lower()) - hostDir.makeDir() - self.installPackagesInto(hostDir, platform) - - totsize = 0 - for root, dirs, files in self.os_walk(tempdir.toOsSpecific()): - for name in files: - totsize += os.path.getsize(os.path.join(root, name)) - - self.__tempRoots[platform] = (tempdir, totsize) - return self.__tempRoots[platform] - - def buildDEB(self, output, platform): - """ Builds a .deb archive and stores it in the path indicated - by the 'output' argument. It will be built for the architecture - specified by the 'arch' argument. - If 'output' is a directory, the deb file will be stored in it. """ - - arch = platform.rsplit("_", 1)[-1] - output = Filename(output) - if output.isDirectory(): - output = Filename(output, "%s_%s_%s.deb" % (self.shortname.lower(), self.version, arch)) - Installer.notify.info("Creating %s..." % output) - modtime = int(time.time()) - - # Create a temporary directory and write the launcher and dependencies to it. - tempdir, totsize = self.__buildTempLinux(platform) - - # Create a control file in memory. - controlfile = BytesIO() - if sys.version_info >= (3, 0): - cout = TextIOWrapper(controlfile, encoding='utf-8', newline='') - else: - cout = StringIO() - - cout.write("Package: %s\n" % self.shortname.lower()) - cout.write("Version: %s\n" % self.version) - cout.write("Maintainer: %s <%s>\n" % (self.authorname, self.authoremail)) - cout.write("Section: games\n") - cout.write("Priority: optional\n") - cout.write("Architecture: %s\n" % arch) - cout.write("Installed-Size: %d\n" % -(-totsize // 1024)) - cout.write("Description: %s\n" % self.fullname) - cout.write("Depends: libc6, libgcc1, libstdc++6, libx11-6\n") - cout.flush() - if sys.version_info < (3, 0): - controlfile.write(cout.getvalue().encode('utf-8')) - - controlinfo = TarInfoRoot("control") - controlinfo.mtime = modtime - controlinfo.size = controlfile.tell() - controlfile.seek(0) - - # Open the deb file and write to it. It's actually - # just an AR file, which is very easy to make. - if output.exists(): - output.unlink() - debfile = open(output.toOsSpecific(), "wb") - debfile.write(b"!\x0A") - pad_mtime = str(modtime).encode().ljust(12, b' ') - - # The first entry is a special file that marks it a .deb. - debfile.write(b"debian-binary ") - debfile.write(pad_mtime) - debfile.write(b"0 0 100644 4 \x60\x0A") - debfile.write(b"2.0\x0A") - - # Write the control.tar.gz to the archive. We'll leave the - # size 0 for now, and go back and fill it in later. - debfile.write(b"control.tar.gz ") - debfile.write(pad_mtime) - debfile.write(b"0 0 100644 0 \x60\x0A") - ctaroffs = debfile.tell() - ctarfile = tarfile.open("control.tar.gz", "w:gz", debfile, tarinfo = TarInfoRoot) - ctarfile.addfile(controlinfo, controlfile) - ctarfile.close() - ctarsize = debfile.tell() - ctaroffs - if (ctarsize & 1): debfile.write(b"\x0A") - - # Write the data.tar.gz to the archive. Again, leave size 0. - debfile.write(b"data.tar.gz ") - debfile.write(pad_mtime) - debfile.write(b"0 0 100644 0 \x60\x0A") - dtaroffs = debfile.tell() - dtarfile = tarfile.open("data.tar.gz", "w:gz", debfile, tarinfo = TarInfoRoot) - dtarfile.add(Filename(tempdir, "usr").toOsSpecific(), "/usr") - dtarfile.close() - dtarsize = debfile.tell() - dtaroffs - if (dtarsize & 1): debfile.write(b"\x0A") - - # Write the correct sizes of the archives. - debfile.seek(ctaroffs - 12) - debfile.write(str(ctarsize).encode().ljust(10, b' ')) - debfile.seek(dtaroffs - 12) - debfile.write(str(dtarsize).encode().ljust(10, b' ')) - - debfile.close() - - return output - - def buildArch(self, output, platform): - """ Builds an ArchLinux package and stores it in the path - indicated by the 'output' argument. It will be built for the - architecture specified by the 'arch' argument. - If 'output' is a directory, the deb file will be stored in it. """ - - arch = platform.rsplit("_", 1)[-1] - assert arch in ("i386", "amd64") - arch = {"i386" : "i686", "amd64" : "x86_64"}[arch] - pkgver = self.version + "-1" - - output = Filename(output) - if output.isDirectory(): - output = Filename(output, "%s-%s-%s.pkg.tar.gz" % (self.shortname.lower(), pkgver, arch)) - Installer.notify.info("Creating %s..." % output) - modtime = int(time.time()) - - # Create a temporary directory and write the launcher and dependencies to it. - tempdir, totsize = self.__buildTempLinux(platform) - - # Create a pkginfo file in memory. - pkginfo = BytesIO() - if sys.version_info >= (3, 0): - pout = TextIOWrapper(pkginfo, encoding='utf-8', newline='') - else: - pout = StringIO() - - pout.write("# Generated using pdeploy\n") - pout.write("# %s\n" % time.ctime(modtime)) - pout.write("pkgname = %s\n" % self.shortname.lower()) - pout.write("pkgver = %s\n" % pkgver) - pout.write("pkgdesc = %s\n" % self.fullname) - pout.write("builddate = %s\n" % modtime) - pout.write("packager = %s <%s>\n" % (self.authorname, self.authoremail)) - pout.write("size = %d\n" % totsize) - pout.write("arch = %s\n" % arch) - if self.licensename != "": - pout.write("license = %s\n" % self.licensename) - pout.flush() - if sys.version_info < (3, 0): - pkginfo.write(pout.getvalue().encode('utf-8')) - - pkginfoinfo = TarInfoRoot(".PKGINFO") - pkginfoinfo.mtime = modtime - pkginfoinfo.size = pkginfo.tell() - pkginfo.seek(0) - - # Create the actual package now. - pkgfile = tarfile.open(output.toOsSpecific(), "w:gz", tarinfo = TarInfoRoot) - pkgfile.addfile(pkginfoinfo, pkginfo) - pkgfile.add(tempdir.toOsSpecific(), "/") - if not self.licensefile.empty(): - pkgfile.add(self.licensefile.toOsSpecific(), "/usr/share/licenses/%s/LICENSE" % self.shortname.lower()) - pkgfile.close() - - return output - - def buildAPP(self, output, platform): - - output = Filename(output) - if output.isDirectory() and output.getExtension() != 'app': - output = Filename(output, "%s.app" % self.fullname) - Installer.notify.info("Creating %s..." % output) - - # Create the executable for the application bundle - exefile = Filename(output, "Contents/MacOS/" + self.shortname) - exefile.makeDir() - if self.includeRequires: - extraTokens = {"host_dir": "../Resources", "start_dir": "../Resources"} - else: - extraTokens = {} - self.standalone.build(exefile, platform, extraTokens) - hostDir = Filename(output, "Contents/Resources/") - hostDir.makeDir() - self.installPackagesInto(hostDir, platform) - - hasIcon = False - if self.icon is not None: - Installer.notify.info("Generating %s.icns..." % self.shortname) - hasIcon = self.icon.makeICNS(Filename(hostDir, "%s.icns" % self.shortname)) - - # Create the application plist file using Python's plistlib module. - plist = { - 'CFBundleDevelopmentRegion': 'English', - 'CFBundleDisplayName': self.fullname, - 'CFBundleExecutable': exefile.getBasename(), - 'CFBundleIdentifier': '%s.%s' % (self.author, self.shortname), - 'CFBundleInfoDictionaryVersion': '6.0', - 'CFBundleName': self.shortname, - 'CFBundlePackageType': 'APPL', - 'CFBundleShortVersionString': self.version, - 'CFBundleVersion': self.version, - 'LSHasLocalizedDisplayName': False, - 'NSAppleScriptEnabled': False, - 'NSPrincipalClass': 'NSApplication', - } - if hasIcon: - plist['CFBundleIconFile'] = self.shortname + '.icns' - - plistlib.writePlist(plist, Filename(output, "Contents/Info.plist").toOsSpecific()) - return output - - def buildPKG(self, output, platform): - appfn = self.buildAPP(output, platform) - appname = "/Applications/" + appfn.getBasename() - output = Filename(output) - if output.isDirectory(): - output = Filename(output, "%s %s.pkg" % (self.fullname, self.version)) - Installer.notify.info("Creating %s..." % output) - - Filename(output, "Contents/Resources/en.lproj/").makeDir() - if self.licensefile: - shutil.copyfile(self.licensefile.toOsSpecific(), Filename(output, "Contents/Resources/License.txt").toOsSpecific()) - pkginfo = open(Filename(output, "Contents/PkgInfo").toOsSpecific(), "w") - pkginfo.write("pmkrpkg1") - pkginfo.close() - pkginfo = open(Filename(output, "Contents/Resources/package_version").toOsSpecific(), "w") - pkginfo.write("major: 1\nminor: 9") - pkginfo.close() - - # Although it might make more sense to use Python's plistlib here, - # it is not available on non-OSX systems before Python 2.6. - plist = open(Filename(output, "Contents/Info.plist").toOsSpecific(), "w") - plist.write('\n') - plist.write('\n') - plist.write('\n') - plist.write('\n') - plist.write('\tCFBundleIdentifier\n') - plist.write('\t%s.pkg.%s\n' % (self.authorid, self.shortname)) - plist.write('\tCFBundleShortVersionString\n') - plist.write('\t%s\n' % self.version) - plist.write('\tIFMajorVersion\n') - plist.write('\t1\n') - plist.write('\tIFMinorVersion\n') - plist.write('\t9\n') - plist.write('\tIFPkgFlagAllowBackRev\n') - plist.write('\t\n') - plist.write('\tIFPkgFlagAuthorizationAction\n') - plist.write('\tRootAuthorization\n') - plist.write('\tIFPkgFlagDefaultLocation\n') - plist.write('\t/\n') - plist.write('\tIFPkgFlagFollowLinks\n') - plist.write('\t\n') - plist.write('\tIFPkgFlagIsRequired\n') - plist.write('\t\n') - plist.write('\tIFPkgFlagOverwritePermissions\n') - plist.write('\t\n') - plist.write('\tIFPkgFlagRelocatable\n') - plist.write('\t\n') - plist.write('\tIFPkgFlagRestartAction\n') - plist.write('\tNone\n') - plist.write('\tIFPkgFlagRootVolumeOnly\n') - plist.write('\t\n') - plist.write('\tIFPkgFlagUpdateInstalledLanguages\n') - plist.write('\t\n') - plist.write('\tIFPkgFormatVersion\n') - plist.write('\t0.10000000149011612\n') - plist.write('\tIFPkgPathMappings\n') - plist.write('\t\n') - plist.write('\t\t%s\n' % appname) - plist.write('\t\t{pkmk-token-2}\n') - plist.write('\t\n') - plist.write('\n') - plist.write('\n') - plist.close() - - plist = open(Filename(output, "Contents/Resources/TokenDefinitions.plist").toOsSpecific(), "w") - plist.write('\n') - plist.write('\n') - plist.write('\n') - plist.write('\n') - plist.write('\tpkmk-token-2\n') - plist.write('\t\n') - plist.write('\t\t\n') - plist.write('\t\t\tidentifier\n') - plist.write('\t\t\t%s.%s\n' % (self.authorid, self.shortname)) - plist.write('\t\t\tpath\n') - plist.write('\t\t\t%s\n' % appname) - plist.write('\t\t\tsearchPlugin\n') - plist.write('\t\t\tCommonAppSearch\n') - plist.write('\t\t\n') - plist.write('\t\n') - plist.write('\n') - plist.write('\n') - plist.close() - - plist = open(Filename(output, "Contents/Resources/en.lproj/Description.plist").toOsSpecific(), "w") - plist.write('\n') - plist.write('\n') - plist.write('\n') - plist.write('\n') - plist.write('\tIFPkgDescriptionDescription\n') - plist.write('\t\n') - plist.write('\tIFPkgDescriptionTitle\n') - plist.write('\t%s\n' % self.fullname) - plist.write('\n') - plist.write('\n') - plist.close() - - # OS X El Capitan no longer accepts .pax archives - it must be a CPIO archive named .pax. - archive = gzip.open(Filename(output, "Contents/Archive.pax.gz").toOsSpecific(), 'wb') - self.__ino = 0 - self.__writeCPIO(archive, appfn, appname) - archive.write(b"0707070000000000000000000000000000000000010000000000000000000001300000000000TRAILER!!!\0") - archive.close() - - # Put the .pkg into a zipfile - zip_fn = Filename(output.getDirname(), "%s %s.pkg.zip" % (self.fullname, self.version)) - dir = Filename(output.getDirname()) - dir.makeAbsolute() - zip = zipfile.ZipFile(zip_fn.toOsSpecific(), 'w') - for root, dirs, files in self.os_walk(output.toOsSpecific()): - for name in files: - file = Filename.fromOsSpecific(os.path.join(root, name)) - file.makeAbsolute() - file.makeRelativeTo(dir) - zip.write(os.path.join(root, name), str(file)) - zip.close() - - return output - - def __writeCPIO(self, archive, fn, name): - """ Adds the given fn under the given name to the CPIO archive. """ - - st = os.lstat(fn.toOsSpecific()) - - archive.write(b"070707") # magic - archive.write(b"000000") # dev - - # Synthesize an inode number, different for each entry. - self.__ino += 1 - archive.write("%06o" % (self.__ino)) - - # Determine based on the type which mode to write. - if os.path.islink(fn.toOsSpecific()): - archive.write("%06o" % (st.st_mode)) - target = os.path.readlink(fn.toOsSpecific()).encode('utf-8') - size = len(target) - elif os.path.isdir(fn.toOsSpecific()): - archive.write(b"040755") - size = 0 - elif not fn.getExtension(): # Binary file? - archive.write(b"100755") - size = st.st_size - else: - archive.write(b"100644") - size = st.st_size - - archive.write("000000") # uid (root) - archive.write("000000") # gid (wheel) - archive.write("%06o" % (st.st_nlink)) - archive.write("000000") # rdev - archive.write("%011o" % (st.st_mtime)) - archive.write("%06o" % (len(name) + 1)) - archive.write("%011o" % (size)) - - # Write the filename, plus terminating NUL byte. - archive.write(name.encode('utf-8')) - archive.write(b"\0") - - # Copy the file data to the archive. - if os.path.islink(fn.toOsSpecific()): - archive.write(target) - elif size: - handle = open(fn.toOsSpecific(), 'rb') - data = handle.read(1024 * 1024) - while data: - archive.write(data) - data = handle.read(1024 * 1024) - handle.close() - - # If this is a directory, recurse. - if os.path.isdir(fn.toOsSpecific()): - for child in os.listdir(fn.toOsSpecific()): - self.__writeCPIO(archive, Filename(fn, child), name + "/" + child) - - def buildNSIS(self, output, platform): - # Check if we have makensis first - makensis = None - if (sys.platform.startswith("win")): - syspath = os.defpath.split(";") + os.environ["PATH"].split(";") - for p in set(syspath): - p1 = os.path.join(p, "makensis.exe") - p2 = os.path.join(os.path.dirname(p), "nsis", "makensis.exe") - if os.path.isfile(p1): - makensis = p1 - break - elif os.path.isfile(p2): - makensis = p2 - break - if not makensis: - import pandac - makensis = os.path.dirname(os.path.dirname(pandac.__file__)) - makensis = os.path.join(makensis, "nsis", "makensis.exe") - if not os.path.isfile(makensis): makensis = None - else: - for p in os.defpath.split(":") + os.environ["PATH"].split(":"): - if os.path.isfile(os.path.join(p, "makensis")): - makensis = os.path.join(p, "makensis") - - if makensis == None: - Installer.notify.warning("Makensis utility not found, no Windows installer will be built!") - return None - - output = Filename(output) - if output.isDirectory(): - output = Filename(output, "%s %s.exe" % (self.fullname, self.version)) - Installer.notify.info("Creating %s..." % output) - output.makeAbsolute() - extrafiles = self.standalone.getExtraFiles(platform) - - exefile = Filename(Filename.getTempDirectory(), self.shortname + ".exe") - exefile.unlink() - if self.includeRequires: - extraTokens = {"host_dir": ".", "start_dir": "."} - else: - extraTokens = {} - self.standalone.build(exefile, platform, extraTokens) - - # Temporary directory to store the hostdir in - hostDir = Filename(self.tempDir, platform + "/") - if not hostDir.exists(): - hostDir.makeDir() - self.installPackagesInto(hostDir, platform) - - # See if we can generate an icon - icofile = None - if self.icon is not None: - icofile = Filename(Filename.getTempDirectory(), self.shortname + ".ico") - icofile.unlink() - Installer.notify.info("Generating %s.ico..." % self.shortname) - if not self.icon.makeICO(icofile): - icofile = None - - # Create the .nsi installer script - nsifile = Filename(Filename.getTempDirectory(), self.shortname + ".nsi") - nsifile.unlink() - nsi = open(nsifile.toOsSpecific(), "w") - - # Some global info - nsi.write('Name "%s"\n' % self.fullname) - nsi.write('OutFile "%s"\n' % output.toOsSpecific()) - if platform == 'win_amd64': - nsi.write('InstallDir "$PROGRAMFILES64\\%s"\n' % self.fullname) - else: - nsi.write('InstallDir "$PROGRAMFILES\\%s"\n' % self.fullname) - nsi.write('SetCompress auto\n') - nsi.write('SetCompressor lzma\n') - nsi.write('ShowInstDetails nevershow\n') - nsi.write('ShowUninstDetails nevershow\n') - nsi.write('InstType "Typical"\n') - - # Tell Vista that we require admin rights - nsi.write('RequestExecutionLevel admin\n') - nsi.write('\n') - if self.offerRun: - nsi.write('Function launch\n') - nsi.write(' ExecShell "open" "$INSTDIR\\%s.exe"\n' % self.shortname) - nsi.write('FunctionEnd\n') - nsi.write('\n') - - if self.offerDesktopShortcut: - nsi.write('Function desktopshortcut\n') - if icofile is None: - nsi.write(' CreateShortcut "$DESKTOP\\%s.lnk" "$INSTDIR\\%s.exe"\n' % (self.fullname, self.shortname)) - else: - nsi.write(' CreateShortcut "$DESKTOP\\%s.lnk" "$INSTDIR\\%s.exe" "" "$INSTDIR\\%s.ico"\n' % (self.fullname, self.shortname, self.shortname)) - nsi.write('FunctionEnd\n') - nsi.write('\n') - - nsi.write('!include "MUI2.nsh"\n') - nsi.write('!define MUI_ABORTWARNING\n') - if self.offerRun: - nsi.write('!define MUI_FINISHPAGE_RUN\n') - nsi.write('!define MUI_FINISHPAGE_RUN_NOTCHECKED\n') - nsi.write('!define MUI_FINISHPAGE_RUN_FUNCTION launch\n') - nsi.write('!define MUI_FINISHPAGE_RUN_TEXT "Run %s"\n' % self.fullname) - if self.offerDesktopShortcut: - nsi.write('!define MUI_FINISHPAGE_SHOWREADME ""\n') - nsi.write('!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED\n') - nsi.write('!define MUI_FINISHPAGE_SHOWREADME_TEXT "Create Desktop Shortcut"\n') - nsi.write('!define MUI_FINISHPAGE_SHOWREADME_FUNCTION desktopshortcut\n') - nsi.write('\n') - nsi.write('Var StartMenuFolder\n') - nsi.write('!insertmacro MUI_PAGE_WELCOME\n') - if not self.licensefile.empty(): - abs = Filename(self.licensefile) - abs.makeAbsolute() - nsi.write('!insertmacro MUI_PAGE_LICENSE "%s"\n' % abs.toOsSpecific()) - nsi.write('!insertmacro MUI_PAGE_DIRECTORY\n') - nsi.write('!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder\n') - nsi.write('!insertmacro MUI_PAGE_INSTFILES\n') - nsi.write('!insertmacro MUI_PAGE_FINISH\n') - nsi.write('!insertmacro MUI_UNPAGE_WELCOME\n') - nsi.write('!insertmacro MUI_UNPAGE_CONFIRM\n') - nsi.write('!insertmacro MUI_UNPAGE_INSTFILES\n') - nsi.write('!insertmacro MUI_UNPAGE_FINISH\n') - nsi.write('!insertmacro MUI_LANGUAGE "English"\n') - - # This section defines the installer. - nsi.write('Section "" SecCore\n') - nsi.write(' SetOutPath "$INSTDIR"\n') - nsi.write(' File "%s"\n' % exefile.toOsSpecific()) - if icofile is not None: - nsi.write(' File "%s"\n' % icofile.toOsSpecific()) - for f in extrafiles: - nsi.write(' File "%s"\n' % f.toOsSpecific()) - curdir = "" - for root, dirs, files in self.os_walk(hostDir.toOsSpecific()): - for name in files: - basefile = Filename.fromOsSpecific(os.path.join(root, name)) - file = Filename(basefile) - file.makeAbsolute() - file.makeRelativeTo(hostDir) - outdir = file.getDirname().replace('/', '\\') - if curdir != outdir: - nsi.write(' SetOutPath "$INSTDIR\\%s"\n' % outdir) - curdir = outdir - nsi.write(' File "%s"\n' % (basefile.toOsSpecific())) - nsi.write(' SetOutPath "$INSTDIR"\n') - nsi.write(' WriteUninstaller "$INSTDIR\\Uninstall.exe"\n') - nsi.write(' ; Start menu items\n') - nsi.write(' !insertmacro MUI_STARTMENU_WRITE_BEGIN Application\n') - nsi.write(' CreateDirectory "$SMPROGRAMS\\$StartMenuFolder"\n') - if icofile is None: - nsi.write(' CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\%s.lnk" "$INSTDIR\\%s.exe"\n' % (self.fullname, self.shortname)) - else: - nsi.write(' CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\%s.lnk" "$INSTDIR\\%s.exe" "" "$INSTDIR\\%s.ico"\n' % (self.fullname, self.shortname, self.shortname)) - nsi.write(' CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk" "$INSTDIR\\Uninstall.exe"\n') - nsi.write(' !insertmacro MUI_STARTMENU_WRITE_END\n') - nsi.write('SectionEnd\n') - - # This section defines the uninstaller. - nsi.write('Section Uninstall\n') - nsi.write(' Delete "$INSTDIR\\%s.exe"\n' % self.shortname) - if icofile is not None: - nsi.write(' Delete "$INSTDIR\\%s.ico"\n' % self.shortname) - for f in extrafiles: - nsi.write(' Delete "%s"\n' % f.getBasename()) - nsi.write(' Delete "$INSTDIR\\Uninstall.exe"\n') - nsi.write(' RMDir /r "$INSTDIR"\n') - nsi.write(' ; Desktop icon\n') - nsi.write(' Delete "$DESKTOP\\%s.lnk"\n' % self.fullname) - nsi.write(' ; Start menu items\n') - nsi.write(' !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder\n') - nsi.write(' Delete "$SMPROGRAMS\\$StartMenuFolder\\%s.lnk"\n' % self.fullname) - nsi.write(' Delete "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk"\n') - nsi.write(' RMDir "$SMPROGRAMS\\$StartMenuFolder"\n') - nsi.write('SectionEnd\n') - nsi.close() - - cmd = [makensis] - for o in ["V2"]: - if sys.platform.startswith("win"): - cmd.append("/" + o) - else: - cmd.append("-" + o) - cmd.append(nsifile.toOsSpecific()) - print(cmd) - try: - retcode = subprocess.call(cmd, shell = False) - if retcode != 0: - self.notify.warning("Failure invoking NSIS command.") - else: - nsifile.unlink() - except OSError: - self.notify.warning("Unable to invoke NSIS command.") - - if icofile is not None: - icofile.unlink() - - return output - - def os_walk(self, top): - """ Re-implements os.walk(). For some reason the built-in - definition is failing on Windows when this is run within a p3d - environment!? """ - - dirnames = [] - filenames = [] - - dirlist = os.listdir(top) - if dirlist: - for file in dirlist: - path = os.path.join(top, file) - if os.path.isdir(path): - dirnames.append(file) - else: - filenames.append(file) - - yield (top, dirnames, filenames) - - for dir in dirnames: - next = os.path.join(top, dir) - for tuple in self.os_walk(next): - yield tuple diff --git a/direct/src/p3d/FileSpec.py b/direct/src/p3d/FileSpec.py deleted file mode 100644 index ddd1dafd6e..0000000000 --- a/direct/src/p3d/FileSpec.py +++ /dev/null @@ -1,246 +0,0 @@ -__all__ = ["FileSpec"] - -import os -import time -from panda3d.core import Filename, HashVal, VirtualFileSystem - -class FileSpec: - """ This class represents a disk file whose hash and size - etc. were read from an xml file. This class provides methods to - verify whether the file on disk matches the version demanded by - the xml. """ - - def __init__(self): - self.actualFile = None - self.filename = None - self.size = 0 - self.timestamp = 0 - self.hash = None - - def fromFile(self, packageDir, filename, pathname = None, st = None): - """ Reads the file information from the indicated file. If st - is supplied, it is the result of os.stat on the filename. """ - - vfs = VirtualFileSystem.getGlobalPtr() - - filename = Filename(filename) - if pathname is None: - pathname = Filename(packageDir, filename) - - self.filename = str(filename) - self.basename = filename.getBasename() - - if st is None: - st = os.stat(pathname.toOsSpecific()) - self.size = st.st_size - self.timestamp = int(st.st_mtime) - - self.readHash(pathname) - - def readHash(self, pathname): - """ Reads the hash only from the indicated pathname. """ - - hv = HashVal() - hv.hashFile(pathname) - self.hash = hv.asHex() - - - def loadXml(self, xelement): - """ Reads the file information from the indicated XML - element. """ - - self.filename = xelement.Attribute('filename') - self.basename = None - if self.filename: - self.basename = Filename(self.filename).getBasename() - - size = xelement.Attribute('size') - try: - self.size = int(size) - except: - self.size = 0 - - timestamp = xelement.Attribute('timestamp') - try: - self.timestamp = int(timestamp) - except: - self.timestamp = 0 - - self.hash = xelement.Attribute('hash') - - def storeXml(self, xelement): - """ Adds the file information to the indicated XML - element. """ - - if self.filename: - xelement.SetAttribute('filename', self.filename) - if self.size: - xelement.SetAttribute('size', str(self.size)) - if self.timestamp: - xelement.SetAttribute('timestamp', str(int(self.timestamp))) - if self.hash: - xelement.SetAttribute('hash', self.hash) - - def storeMiniXml(self, xelement): - """ Adds the just the "mini" file information--size and - hash--to the indicated XML element. """ - - if self.size: - xelement.SetAttribute('size', str(self.size)) - if self.hash: - xelement.SetAttribute('hash', self.hash) - - def quickVerify(self, packageDir = None, pathname = None, - notify = None, correctSelf = False): - """ Performs a quick test to ensure the file has not been - modified. This test is vulnerable to people maliciously - attempting to fool the program (by setting datestamps etc.). - - if correctSelf is True, then any discrepency is corrected by - updating the appropriate fields internally, making the - assumption that the file on disk is the authoritative version. - - Returns true if it is intact, false if it is incorrect. If - correctSelf is true, raises OSError if the self-update is - impossible (for instance, because the file does not exist).""" - - if not pathname: - pathname = Filename(packageDir, self.filename) - try: - st = os.stat(pathname.toOsSpecific()) - except OSError: - # If the file is missing, the file fails. - if notify: - notify.debug("file not found: %s" % (pathname)) - if correctSelf: - raise - return False - - if st.st_size != self.size: - # If the size is wrong, the file fails. - if notify: - notify.debug("size wrong: %s" % (pathname)) - if correctSelf: - self.__correctHash(packageDir, pathname, st, notify) - return False - - if int(st.st_mtime) == self.timestamp: - # If the size is right and the timestamp is right, the - # file passes. - if notify: - notify.debug("file ok: %s" % (pathname)) - return True - - if notify: - notify.debug("modification time wrong: %s" % (pathname)) - - # If the size is right but the timestamp is wrong, the file - # soft-fails. We follow this up with a hash check. - if not self.checkHash(packageDir, pathname, st): - # Hard fail, the hash is wrong. - if notify: - notify.debug("hash check wrong: %s" % (pathname)) - notify.debug(" found %s, expected %s" % (self.actualFile.hash, self.hash)) - if correctSelf: - self.__correctHash(packageDir, pathname, st, notify) - return False - - if notify: - notify.debug("hash check ok: %s" % (pathname)) - - # The hash is OK after all. Change the file's timestamp back - # to what we expect it to be, so we can quick-verify it - # successfully next time. - if correctSelf: - # Or update our own timestamp. - self.__correctTimestamp(pathname, st, notify) - return False - else: - self.__updateTimestamp(pathname, st) - - return True - - - def fullVerify(self, packageDir = None, pathname = None, notify = None): - """ Performs a more thorough test to ensure the file has not - been modified. This test is less vulnerable to malicious - attacks, since it reads and verifies the entire file. - - Returns true if it is intact, false if it needs to be - redownloaded. """ - - if not pathname: - pathname = Filename(packageDir, self.filename) - try: - st = os.stat(pathname.toOsSpecific()) - except OSError: - # If the file is missing, the file fails. - if notify: - notify.debug("file not found: %s" % (pathname)) - return False - - if st.st_size != self.size: - # If the size is wrong, the file fails; - if notify: - notify.debug("size wrong: %s" % (pathname)) - return False - - if not self.checkHash(packageDir, pathname, st): - # Hard fail, the hash is wrong. - if notify: - notify.debug("hash check wrong: %s" % (pathname)) - notify.debug(" found %s, expected %s" % (self.actualFile.hash, self.hash)) - return False - - if notify: - notify.debug("hash check ok: %s" % (pathname)) - - # The hash is OK. If the timestamp is wrong, change it back - # to what we expect it to be, so we can quick-verify it - # successfully next time. - if int(st.st_mtime) != self.timestamp: - self.__updateTimestamp(pathname, st) - - return True - - def __updateTimestamp(self, pathname, st): - # On Windows, we have to change the file to read-write before - # we can successfully update its timestamp. - try: - os.chmod(pathname.toOsSpecific(), 0o755) - os.utime(pathname.toOsSpecific(), (st.st_atime, self.timestamp)) - os.chmod(pathname.toOsSpecific(), 0o555) - except OSError: - pass - - def __correctTimestamp(self, pathname, st, notify): - """ Corrects the internal timestamp to match the one on - disk. """ - if notify: - notify.info("Correcting timestamp of %s to %d (%s)" % ( - self.filename, st.st_mtime, time.asctime(time.localtime(st.st_mtime)))) - self.timestamp = int(st.st_mtime) - - def checkHash(self, packageDir, pathname, st): - """ Returns true if the file has the expected md5 hash, false - otherwise. As a side effect, stores a FileSpec corresponding - to the on-disk file in self.actualFile. """ - - fileSpec = FileSpec() - fileSpec.fromFile(packageDir, self.filename, - pathname = pathname, st = st) - self.actualFile = fileSpec - - return (fileSpec.hash == self.hash) - - def __correctHash(self, packageDir, pathname, st, notify): - """ Corrects the internal hash to match the one on disk. """ - if not self.actualFile: - self.checkHash(packageDir, pathname, st) - - if notify: - notify.info("Correcting hash %s to %s" % ( - self.filename, self.actualFile.hash)) - self.hash = self.actualFile.hash - self.size = self.actualFile.size - self.timestamp = self.actualFile.timestamp diff --git a/direct/src/p3d/HostInfo.py b/direct/src/p3d/HostInfo.py deleted file mode 100644 index 4e5efdcd3e..0000000000 --- a/direct/src/p3d/HostInfo.py +++ /dev/null @@ -1,751 +0,0 @@ -__all__ = ["HostInfo"] - -from panda3d.core import HashVal, Filename, PandaSystem, DocumentSpec, Ramfile -from panda3d.core import HTTPChannel, ConfigVariableInt -from panda3d import core -from direct.p3d.PackageInfo import PackageInfo -from direct.p3d.FileSpec import FileSpec -from direct.directnotify.DirectNotifyGlobal import directNotify -import time - -class HostInfo: - """ This class represents a particular download host serving up - Panda3D packages. It is the Python equivalent of the P3DHost - class in the core API. """ - - notify = directNotify.newCategory("HostInfo") - - def __init__(self, hostUrl, appRunner = None, hostDir = None, - rootDir = None, asMirror = False, perPlatform = None): - - """ You must specify either an appRunner or a hostDir to the - HostInfo constructor. - - If you pass asMirror = True, it means that this HostInfo - object is to be used to populate a "mirror" folder, a - duplicate (or subset) of the contents hosted by a server. - This means when you use this HostInfo to download packages, it - will only download the compressed archive file and leave it - there. At the moment, mirror folders do not download old - patch files from the server. - - If you pass perPlatform = True, then files are unpacked into a - platform-specific directory, which is appropriate when you - might be downloading multiple platforms. The default is - perPlatform = False, which means all files are unpacked into - the host directory directly, without an intervening - platform-specific directory name. If asMirror is True, then - the default is perPlatform = True. - - Note that perPlatform is also restricted by the individual - package's specification. """ - - self.__setHostUrl(hostUrl) - self.appRunner = appRunner - self.rootDir = rootDir - if rootDir is None and appRunner: - self.rootDir = appRunner.rootDir - - if hostDir and not isinstance(hostDir, Filename): - hostDir = Filename.fromOsSpecific(hostDir) - - self.hostDir = hostDir - self.asMirror = asMirror - self.perPlatform = perPlatform - if perPlatform is None: - self.perPlatform = asMirror - - # Initially false, this is set true when the contents file is - # successfully read. - self.hasContentsFile = False - - # This is the time value at which the current contents file is - # no longer valid. - self.contentsExpiration = 0 - - # Contains the md5 hash of the original contents.xml file. - self.contentsSpec = FileSpec() - - # descriptiveName will be filled in later, when the - # contents file is read. - self.descriptiveName = None - - # A list of known mirrors for this host, all URL's guaranteed - # to end with a slash. - self.mirrors = [] - - # A map of keyword -> altHost URL's. An altHost is different - # than a mirror; an altHost is an alternate URL to download a - # different (e.g. testing) version of this host's contents. - # It is rarely used. - self.altHosts = {} - - # This is a dictionary of packages by (name, version). It - # will be filled in when the contents file is read. - self.packages = {} - - if self.appRunner and self.appRunner.verifyContents != self.appRunner.P3DVCForce: - # Attempt to pre-read the existing contents.xml; maybe it - # will be current enough for our purposes. - self.readContentsFile() - - def __setHostUrl(self, hostUrl): - """ Assigns self.hostUrl, and related values. """ - self.hostUrl = hostUrl - - if not self.hostUrl: - # A special case: the URL will be set later. - self.hostUrlPrefix = None - self.downloadUrlPrefix = None - else: - # hostUrlPrefix is the host URL, but it is guaranteed to end - # with a slash. - self.hostUrlPrefix = hostUrl - if self.hostUrlPrefix[-1] != '/': - self.hostUrlPrefix += '/' - - # downloadUrlPrefix is the URL prefix that should be used for - # everything other than the contents.xml file. It might be - # the same as hostUrlPrefix, but in the case of an - # https-protected hostUrl, it will be the cleartext channel. - self.downloadUrlPrefix = self.hostUrlPrefix - - def freshenFile(self, http, fileSpec, localPathname): - """ Ensures that the localPathname is the most current version - of the file defined by fileSpec, as offered by host. If not, - it downloads a new version on-the-spot. Returns true on - success, false on failure. """ - - if fileSpec.quickVerify(pathname = localPathname): - # It's good, keep it. - return True - - # It's stale, get a new one. - doc = None - if self.appRunner and self.appRunner.superMirrorUrl: - # Use the "super mirror" first. - url = core.URLSpec(self.appRunner.superMirrorUrl + fileSpec.filename) - self.notify.info("Freshening %s" % (url)) - doc = http.getDocument(url) - - if not doc or not doc.isValid(): - # Failing the super mirror, contact the actual host. - url = core.URLSpec(self.hostUrlPrefix + fileSpec.filename) - self.notify.info("Freshening %s" % (url)) - doc = http.getDocument(url) - if not doc.isValid(): - return False - - file = Filename.temporary('', 'p3d_') - if not doc.downloadToFile(file): - # Failed to download. - file.unlink() - return False - - # Successfully downloaded! - localPathname.makeDir() - if not file.renameTo(localPathname): - # Couldn't move it into place. - file.unlink() - return False - - if not fileSpec.fullVerify(pathname = localPathname, notify = self.notify): - # No good after download. - self.notify.info("%s is still no good after downloading." % (url)) - return False - - return True - - def downloadContentsFile(self, http, redownload = False, - hashVal = None): - """ Downloads the contents.xml file for this particular host, - synchronously, and then reads it. Returns true on success, - false on failure. If hashVal is not None, it should be a - HashVal object, which will be filled with the hash from the - new contents.xml file.""" - - if self.hasCurrentContentsFile(): - # We've already got one. - return True - - if self.appRunner and self.appRunner.verifyContents == self.appRunner.P3DVCNever: - # Not allowed to. - return False - - rf = None - if http: - if not redownload and self.appRunner and self.appRunner.superMirrorUrl: - # We start with the "super mirror", if it's defined. - url = self.appRunner.superMirrorUrl + 'contents.xml' - request = DocumentSpec(url) - self.notify.info("Downloading contents file %s" % (request)) - - rf = Ramfile() - channel = http.makeChannel(False) - channel.getDocument(request) - if not channel.downloadToRam(rf): - self.notify.warning("Unable to download %s" % (url)) - rf = None - - if not rf: - # Then go to the main host, if our super mirror let us - # down. - - url = self.hostUrlPrefix + 'contents.xml' - # Append a uniquifying query string to the URL to force the - # download to go all the way through any caches. We use the - # time in seconds; that's unique enough. - url += '?' + str(int(time.time())) - - # We might as well explicitly request the cache to be disabled - # too, since we have an interface for that via HTTPChannel. - request = DocumentSpec(url) - request.setCacheControl(DocumentSpec.CCNoCache) - - self.notify.info("Downloading contents file %s" % (request)) - statusCode = None - statusString = '' - for attempt in range(int(ConfigVariableInt('contents-xml-dl-attempts', 3))): - if attempt > 0: - self.notify.info("Retrying (%s)..."%(attempt,)) - rf = Ramfile() - channel = http.makeChannel(False) - channel.getDocument(request) - if channel.downloadToRam(rf): - self.notify.info("Successfully downloaded %s" % (url,)) - break - else: - rf = None - statusCode = channel.getStatusCode() - statusString = channel.getStatusString() - self.notify.warning("Could not contact download server at %s" % (url,)) - self.notify.warning("Status code = %s %s" % (statusCode, statusString)) - - if not rf: - self.notify.warning("Unable to download %s" % (url,)) - try: - # Something screwed up. - if statusCode == HTTPChannel.SCDownloadOpenError or \ - statusCode == HTTPChannel.SCDownloadWriteError: - launcher.setPandaErrorCode(2) - elif statusCode == 404: - # 404 not found - launcher.setPandaErrorCode(5) - elif statusCode < 100: - # statusCode < 100 implies the connection attempt itself - # failed. This is usually due to firewall software - # interfering. Apparently some firewall software might - # allow the first connection and disallow subsequent - # connections; how strange. - launcher.setPandaErrorCode(4) - else: - # There are other kinds of failures, but these will - # generally have been caught already by the first test; so - # if we get here there may be some bigger problem. Just - # give the generic "big problem" message. - launcher.setPandaErrorCode(6) - except NameError as e: - # no launcher - pass - except AttributeError as e: - self.notify.warning("%s" % (str(e),)) - pass - return False - - tempFilename = Filename.temporary('', 'p3d_', '.xml') - if rf: - f = open(tempFilename.toOsSpecific(), 'wb') - f.write(rf.getData()) - f.close() - if hashVal: - hashVal.hashString(rf.getData()) - - if not self.readContentsFile(tempFilename, freshDownload = True): - self.notify.warning("Failure reading %s" % (url)) - tempFilename.unlink() - return False - - tempFilename.unlink() - return True - - # Couldn't download the file. Maybe we should look for a - # previously-downloaded copy already on disk? - return False - - def redownloadContentsFile(self, http): - """ Downloads a new contents.xml file in case it has changed. - Returns true if the file has indeed changed, false if it has - not. """ - assert self.hasContentsFile - - if self.appRunner and self.appRunner.verifyContents == self.appRunner.P3DVCNever: - # Not allowed to. - return False - - url = self.hostUrlPrefix + 'contents.xml' - self.notify.info("Redownloading %s" % (url)) - - # Get the hash of the original file. - assert self.hostDir - hv1 = HashVal() - if self.contentsSpec.hash: - hv1.setFromHex(self.contentsSpec.hash) - else: - filename = Filename(self.hostDir, 'contents.xml') - hv1.hashFile(filename) - - # Now download it again. - self.hasContentsFile = False - hv2 = HashVal() - if not self.downloadContentsFile(http, redownload = True, - hashVal = hv2): - return False - - if hv2 == HashVal(): - self.notify.info("%s didn't actually redownload." % (url)) - return False - elif hv1 != hv2: - self.notify.info("%s has changed." % (url)) - return True - else: - self.notify.info("%s has not changed." % (url)) - return False - - def hasCurrentContentsFile(self): - """ Returns true if a contents.xml file has been successfully - read for this host and is still current, false otherwise. """ - if not self.appRunner \ - or self.appRunner.verifyContents == self.appRunner.P3DVCNone \ - or self.appRunner.verifyContents == self.appRunner.P3DVCNever: - # If we're not asking to verify contents, then - # contents.xml files never expires. - return self.hasContentsFile - - now = int(time.time()) - return now < self.contentsExpiration and self.hasContentsFile - - def readContentsFile(self, tempFilename = None, freshDownload = False): - """ Reads the contents.xml file for this particular host, once - it has been downloaded into the indicated temporary file. - Returns true on success, false if the contents file is not - already on disk or is unreadable. - - If tempFilename is specified, it is the filename read, and it - is copied the file into the standard location if it's not - there already. If tempFilename is not specified, the standard - filename is read if it is known. """ - - if not hasattr(core, 'TiXmlDocument'): - return False - - if not tempFilename: - if self.hostDir: - # If the filename is not specified, we can infer it - # if we already know our hostDir - hostDir = self.hostDir - else: - # Otherwise, we have to guess the hostDir. - hostDir = self.__determineHostDir(None, self.hostUrl) - - tempFilename = Filename(hostDir, 'contents.xml') - - doc = core.TiXmlDocument(tempFilename.toOsSpecific()) - if not doc.LoadFile(): - return False - - xcontents = doc.FirstChildElement('contents') - if not xcontents: - return False - - maxAge = xcontents.Attribute('max_age') - if maxAge: - try: - maxAge = int(maxAge) - except: - maxAge = None - if maxAge is None: - # Default max_age if unspecified (see p3d_plugin.h). - from direct.p3d.AppRunner import AppRunner - maxAge = AppRunner.P3D_CONTENTS_DEFAULT_MAX_AGE - - # Get the latest possible expiration time, based on the max_age - # indication. Any expiration time later than this is in error. - now = int(time.time()) - self.contentsExpiration = now + maxAge - - if freshDownload: - self.contentsSpec.readHash(tempFilename) - - # Update the XML with the new download information. - xorig = xcontents.FirstChildElement('orig') - while xorig: - xcontents.RemoveChild(xorig) - xorig = xcontents.FirstChildElement('orig') - - xorig = core.TiXmlElement('orig') - self.contentsSpec.storeXml(xorig) - xorig.SetAttribute('expiration', str(self.contentsExpiration)) - - xcontents.InsertEndChild(xorig) - - else: - # Read the download hash and expiration time from the XML. - expiration = None - xorig = xcontents.FirstChildElement('orig') - if xorig: - self.contentsSpec.loadXml(xorig) - expiration = xorig.Attribute('expiration') - if expiration: - try: - expiration = int(expiration) - except: - expiration = None - if not self.contentsSpec.hash: - self.contentsSpec.readHash(tempFilename) - - if expiration is not None: - self.contentsExpiration = min(self.contentsExpiration, expiration) - - # Look for our own entry in the hosts table. - if self.hostUrl: - self.__findHostXml(xcontents) - else: - assert self.hostDir - self.__findHostXmlForHostDir(xcontents) - - if self.rootDir and not self.hostDir: - self.hostDir = self.__determineHostDir(None, self.hostUrl) - - # Get the list of packages available for download and/or import. - xpackage = xcontents.FirstChildElement('package') - while xpackage: - name = xpackage.Attribute('name') - platform = xpackage.Attribute('platform') - version = xpackage.Attribute('version') - try: - solo = int(xpackage.Attribute('solo') or '') - except ValueError: - solo = False - try: - perPlatform = int(xpackage.Attribute('per_platform') or '') - except ValueError: - perPlatform = False - - package = self.__makePackage(name, platform, version, solo, perPlatform) - package.descFile = FileSpec() - package.descFile.loadXml(xpackage) - package.setupFilenames() - - package.importDescFile = None - ximport = xpackage.FirstChildElement('import') - if ximport: - package.importDescFile = FileSpec() - package.importDescFile.loadXml(ximport) - - xpackage = xpackage.NextSiblingElement('package') - - self.hasContentsFile = True - - # Now save the contents.xml file into the standard location. - if self.appRunner and self.appRunner.verifyContents != self.appRunner.P3DVCNever: - assert self.hostDir - filename = Filename(self.hostDir, 'contents.xml') - filename.makeDir() - if freshDownload: - doc.SaveFile(filename.toOsSpecific()) - else: - if filename != tempFilename: - tempFilename.copyTo(filename) - - return True - - def __findHostXml(self, xcontents): - """ Looks for the or entry in the - contents.xml that corresponds to the URL that we actually - downloaded from. """ - - xhost = xcontents.FirstChildElement('host') - while xhost: - url = xhost.Attribute('url') - if url == self.hostUrl: - self.readHostXml(xhost) - return - - xalthost = xhost.FirstChildElement('alt_host') - while xalthost: - url = xalthost.Attribute('url') - if url == self.hostUrl: - self.readHostXml(xalthost) - return - xalthost = xalthost.NextSiblingElement('alt_host') - - xhost = xhost.NextSiblingElement('host') - - def __findHostXmlForHostDir(self, xcontents): - """ Looks for the or entry in the - contents.xml that corresponds to the host dir that we read the - contents.xml from. This is used when reading a contents.xml - file found on disk, as opposed to downloading it from a - site. """ - - xhost = xcontents.FirstChildElement('host') - while xhost: - url = xhost.Attribute('url') - hostDirBasename = xhost.Attribute('host_dir') - hostDir = self.__determineHostDir(hostDirBasename, url) - if hostDir == self.hostDir: - self.__setHostUrl(url) - self.readHostXml(xhost) - return - - xalthost = xhost.FirstChildElement('alt_host') - while xalthost: - url = xalthost.Attribute('url') - hostDirBasename = xalthost.Attribute('host_dir') - hostDir = self.__determineHostDir(hostDirBasename, url) - if hostDir == self.hostDir: - self.__setHostUrl(url) - self.readHostXml(xalthost) - return - xalthost = xalthost.NextSiblingElement('alt_host') - - xhost = xhost.NextSiblingElement('host') - - def readHostXml(self, xhost): - """ Reads a or entry and applies the data to - this object. """ - - descriptiveName = xhost.Attribute('descriptive_name') - if descriptiveName and not self.descriptiveName: - self.descriptiveName = descriptiveName - - hostDirBasename = xhost.Attribute('host_dir') - if self.rootDir and not self.hostDir: - self.hostDir = self.__determineHostDir(hostDirBasename, self.hostUrl) - - # Get the "download" URL, which is the source from which we - # download everything other than the contents.xml file. - downloadUrl = xhost.Attribute('download_url') - if downloadUrl: - self.downloadUrlPrefix = downloadUrl - if self.downloadUrlPrefix[-1] != '/': - self.downloadUrlPrefix += '/' - else: - self.downloadUrlPrefix = self.hostUrlPrefix - - xmirror = xhost.FirstChildElement('mirror') - while xmirror: - url = xmirror.Attribute('url') - if url: - if url[-1] != '/': - url += '/' - if url not in self.mirrors: - self.mirrors.append(url) - xmirror = xmirror.NextSiblingElement('mirror') - - xalthost = xhost.FirstChildElement('alt_host') - while xalthost: - keyword = xalthost.Attribute('keyword') - url = xalthost.Attribute('url') - if url and keyword: - self.altHosts[keyword] = url - xalthost = xalthost.NextSiblingElement('alt_host') - - def __makePackage(self, name, platform, version, solo, perPlatform): - """ Creates a new PackageInfo entry for the given name, - version, and platform. If there is already a matching - PackageInfo, returns it. """ - - if not platform: - platform = None - - platforms = self.packages.setdefault((name, version or ""), {}) - package = platforms.get("", None) - if not package: - package = PackageInfo(self, name, version, platform = platform, - solo = solo, asMirror = self.asMirror, - perPlatform = perPlatform) - platforms[platform or ""] = package - - return package - - def getPackage(self, name, version, platform = None): - """ Returns a PackageInfo that matches the indicated name and - version and the indicated platform or the current runtime - platform, if one is provided by this host, or None if not. """ - - assert self.hasContentsFile - platforms = self.packages.get((name, version or ""), {}) - - if platform: - # In this case, we are looking for a specific platform - # only. - return platforms.get(platform, None) - - # We are looking for one matching the current runtime - # platform. First, look for a package matching the current - # platform exactly. - package = platforms.get(PandaSystem.getPlatform(), None) - - # If not found, look for one matching no particular platform. - if not package: - package = platforms.get("", None) - - return package - - def getPackages(self, name = None, platform = None): - """ Returns a list of PackageInfo objects that match the - indicated name and/or platform, with no particular regards to - version. If name is None, all packages are returned. """ - - assert self.hasContentsFile - - packages = [] - for (pn, version), platforms in self.packages.items(): - if name and pn != name: - continue - - if not platform: - for p2 in platforms: - package = self.getPackage(pn, version, platform = p2) - if package: - packages.append(package) - else: - package = self.getPackage(pn, version, platform = platform) - if package: - packages.append(package) - - return packages - - def getAllPackages(self, includeAllPlatforms = False): - """ Returns a list of all available packages provided by this - host. """ - - result = [] - - items = sorted(self.packages.items()) - for key, platforms in items: - if self.perPlatform or includeAllPlatforms: - # If we maintain a different answer per platform, - # return all of them. - pitems = sorted(platforms.items()) - for pkey, package in pitems: - result.append(package) - else: - # If we maintain a host for the current platform - # only (e.g. a client copy), then return only the - # current platform, or no particular platform. - package = platforms.get(PandaSystem.getPlatform(), None) - if not package: - package = platforms.get("", None) - - if package: - result.append(package) - - return result - - def deletePackages(self, packages): - """ Removes all of the indicated packages from the disk, - uninstalling them and deleting all of their files. The - packages parameter must be a list of one or more PackageInfo - objects, for instance as returned by getPackage(). Returns - the list of packages that were NOT found. """ - - packages = packages[:] - - for key, platforms in list(self.packages.items()): - for platform, package in list(platforms.items()): - if package in packages: - self.__deletePackageFiles(package) - del platforms[platform] - packages.remove(package) - - if not platforms: - # If we've removed all the platforms for a given - # package, remove the key from the toplevel map. - del self.packages[key] - - return packages - - def __deletePackageFiles(self, package): - """ Called by deletePackage(), this actually removes the files - for the indicated package. """ - - if self.appRunner: - self.notify.info("Deleting package %s: %s" % (package.packageName, package.getPackageDir())) - self.appRunner.rmtree(package.getPackageDir()) - - self.appRunner.sendRequest('forget_package', self.hostUrl, package.packageName, package.packageVersion or '') - - def __determineHostDir(self, hostDirBasename, hostUrl): - """ Hashes the host URL into a (mostly) unique directory - string, which will be the root of the host's install tree. - Returns the resulting path, as a Filename. - - This code is duplicated in C++, in - P3DHost::determine_host_dir(). """ - - if hostDirBasename: - # If the contents.xml specified a host_dir parameter, use - # it. - hostDir = str(self.rootDir) + '/hosts' - for component in hostDirBasename.split('/'): - if component: - if component[0] == '.': - # Forbid ".foo" or "..". - component = 'x' + component - hostDir += '/' - hostDir += component - return Filename(hostDir) - - hostDir = 'hosts/' - - # Look for a server name in the URL. Including this string in the - # directory name makes it friendlier for people browsing the - # directory. - - # We could use URLSpec, but we do it by hand instead, to make - # it more likely that our hash code will exactly match the - # similar logic in P3DHost. - p = hostUrl.find('://') - hostname = '' - if p != -1: - start = p + 3 - end = hostUrl.find('/', start) - # Now start .. end is something like "username@host:port". - - at = hostUrl.find('@', start) - if at != -1 and at < end: - start = at + 1 - - colon = hostUrl.find(':', start) - if colon != -1 and colon < end: - end = colon - - # Now start .. end is just the hostname. - hostname = hostUrl[start : end] - - # Now build a hash string of the whole URL. We'll use MD5 to - # get a pretty good hash, with a minimum chance of collision. - # Even if there is a hash collision, though, it's not the end - # of the world; it just means that both hosts will dump their - # packages into the same directory, and they'll fight over the - # toplevel contents.xml file. Assuming they use different - # version numbers (which should be safe since they have the - # same hostname), there will be minimal redownloading. - - hashSize = 16 - keepHash = hashSize - if hostname: - hostDir += hostname + '_' - - # If we successfully got a hostname, we don't really need the - # full hash. We'll keep half of it. - keepHash = keepHash // 2 - - md = HashVal() - md.hashString(hostUrl) - hostDir += md.asHex()[:keepHash * 2] - - hostDir = Filename(self.rootDir, hostDir) - return hostDir diff --git a/direct/src/p3d/InstalledHostData.py b/direct/src/p3d/InstalledHostData.py deleted file mode 100644 index d98abb6d18..0000000000 --- a/direct/src/p3d/InstalledHostData.py +++ /dev/null @@ -1,24 +0,0 @@ -__all__ = ["InstalledHostData"] - -from panda3d.core import URLSpec - -class InstalledHostData: - """ A list of instances of this class is returned by - AppRunner.scanInstalledPackages(). Each of these corresponds to a - particular host that has provided packages that have been - installed on the local client. """ - - def __init__(self, host, dirnode): - self.host = host - self.pathname = dirnode.pathname - self.totalSize = dirnode.getTotalSize() - self.packages = [] - - if self.host: - self.hostUrl = self.host.hostUrl - self.descriptiveName = self.host.descriptiveName - if not self.descriptiveName: - self.descriptiveName = URLSpec(self.hostUrl).getServer() - else: - self.hostUrl = 'unknown' - self.descriptiveName = 'unknown' diff --git a/direct/src/p3d/InstalledPackageData.py b/direct/src/p3d/InstalledPackageData.py deleted file mode 100644 index 09ee81cda6..0000000000 --- a/direct/src/p3d/InstalledPackageData.py +++ /dev/null @@ -1,30 +0,0 @@ -__all__ = ["InstalledPackageData"] - -class InstalledPackageData: - """ A list of instances of this class is maintained by - InstalledHostData (which is in turn returned by - AppRunner.scanInstalledPackages()). Each of these corresponds to - a particular package that has been installed on the local - client. """ - - def __init__(self, package, dirnode): - self.package = package - self.pathname = dirnode.pathname - self.totalSize = dirnode.getTotalSize() - self.lastUse = None - - if self.package: - self.displayName = self.package.getFormattedName() - xusage = self.package.getUsage() - - if xusage: - lastUse = xusage.Attribute('last_use') - try: - lastUse = int(lastUse or '') - except ValueError: - lastUse = None - self.lastUse = lastUse - - else: - self.displayName = dirnode.pathname.getBasename() - diff --git a/direct/src/p3d/JavaScript.py b/direct/src/p3d/JavaScript.py deleted file mode 100644 index b59deb1aa2..0000000000 --- a/direct/src/p3d/JavaScript.py +++ /dev/null @@ -1,298 +0,0 @@ -""" This module defines some simple classes and instances which are -useful when writing code that integrates with JavaScript, especially -code that runs in a browser via the web plugin. """ - -__all__ = ["UndefinedObject", "Undefined", "ConcreteStruct", "BrowserObject", "MethodWrapper"] - -class UndefinedObject: - """ This is a special object that is returned by the browser to - represent an "undefined" or "void" value, typically the value for - an uninitialized variable or undefined property. It has no - attributes, similar to None, but it is a slightly different - concept in JavaScript. """ - - def __bool__(self): - return False - - __nonzero__ = __bool__ # Python 2 - - def __str__(self): - return "Undefined" - -# In fact, we normally always return this precise instance of the -# UndefinedObject. -Undefined = UndefinedObject() - -class ConcreteStruct: - """ Python objects that inherit from this class are passed to - JavaScript as a concrete struct: a mapping from string -> value, - with no methods, passed by value. This can be more optimal than - traditional Python objects which are passed by reference, - especially for small objects which might be repeatedly referenced - on the JavaScript side. """ - - def __init__(self): - pass - - def getConcreteProperties(self): - """ Returns a list of 2-tuples of the (key, value) pairs that - are to be passed to the concrete instance. By default, this - returns all properties of the object. You can override this - to restrict the set of properties that are uploaded. """ - - return list(self.__dict__.items()) - -class BrowserObject: - """ This class provides the Python wrapper around some object that - actually exists in the plugin host's namespace, e.g. a JavaScript - or DOM object. """ - - def __init__(self, runner, objectId): - self.__dict__['_BrowserObject__runner'] = runner - self.__dict__['_BrowserObject__objectId'] = objectId - - # This element is filled in by __getattr__; it connects - # the object to its parent. - self.__dict__['_BrowserObject__childObject'] = (None, None) - - # This is a cache of method names to MethodWrapper objects in - # the parent object. - self.__dict__['_BrowserObject__methods'] = {} - - def __del__(self): - # When the BrowserObject destructs, tell the parent process it - # doesn't need to keep around its corresponding P3D_object any - # more. - self.__runner.dropObject(self.__objectId) - - def __cacheMethod(self, methodName): - """ Stores a pointer to the named method on this object, so - that the next time __getattr__ is called, it can retrieve the - method wrapper without having to query the browser. This - cache assumes that callable methods don't generally come and - go on and object. - - The return value is the MethodWrapper object. """ - - method = self.__methods.get(methodName, None) - if method is None: - method = MethodWrapper(self.__runner, self, methodName) - self.__methods[methodName] = method - return method - - def __str__(self): - return self.toString() - - def __bool__(self): - return True - - __nonzero__ = __bool__ # Python 2 - - def __call__(self, *args, **kw): - needsResponse = True - if 'needsResponse' in kw: - needsResponse = kw['needsResponse'] - del kw['needsResponse'] - if kw: - raise ArgumentError('Keyword arguments not supported') - - try: - parentObj, attribName = self.__childObject - if parentObj: - # Call it as a method. - if parentObj is self.__runner.dom and attribName == 'alert': - # As a special hack, we don't wait for the return - # value from the alert() call, since this is a - # blocking call, and waiting for this could cause - # problems. - needsResponse = False - - if parentObj is self.__runner.dom and attribName == 'eval' and len(args) == 1 and isinstance(args[0], str): - # As another special hack, we make dom.eval() a - # special case, and map it directly into an eval() - # call. If the string begins with 'void ', we further - # assume we're not waiting for a response. - if args[0].startswith('void '): - needsResponse = False - result = self.__runner.scriptRequest('eval', parentObj, value = args[0], needsResponse = needsResponse) - else: - # This is a normal method call. - try: - result = self.__runner.scriptRequest('call', parentObj, propertyName = attribName, value = args, needsResponse = needsResponse) - except EnvironmentError: - # Problem on the call. Maybe no such method? - raise AttributeError - - # Hey, the method call appears to have succeeded. - # Cache the method object on the parent so we won't - # have to look up the method wrapper again next time. - parentObj.__cacheMethod(attribName) - - else: - # Call it as a plain function. - result = self.__runner.scriptRequest('call', self, value = args, needsResponse = needsResponse) - except EnvironmentError: - # Some odd problem on the call. - raise TypeError - - return result - - def __getattr__(self, name): - """ Remaps attempts to query an attribute, as in obj.attr, - into the appropriate calls to query the actual browser object - under the hood. """ - - # First check to see if there's a cached method wrapper from a - # previous call. - method = self.__methods.get(name, None) - if method: - return method - - # No cache. Go query the browser for the desired value. - try: - value = self.__runner.scriptRequest('get_property', self, - propertyName = name) - except EnvironmentError: - # Failed to retrieve the attribute. But maybe there's a - # method instead? - if self.__runner.scriptRequest('has_method', self, propertyName = name): - # Yes, so create a method wrapper for it. - return self.__cacheMethod(name) - - raise AttributeError(name) - - if isinstance(value, BrowserObject): - # Fill in the parent object association, so __call__ can - # properly call a method. (Javascript needs to know the - # method container at the time of the call, and doesn't - # store it on the function object.) - value.__dict__['_BrowserObject__childObject'] = (self, name) - - return value - - def __setattr__(self, name, value): - if name in self.__dict__: - self.__dict__[name] = value - return - - result = self.__runner.scriptRequest('set_property', self, - propertyName = name, - value = value) - if not result: - raise AttributeError(name) - - def __delattr__(self, name): - if name in self.__dict__: - del self.__dict__[name] - return - - result = self.__runner.scriptRequest('del_property', self, - propertyName = name) - if not result: - raise AttributeError(name) - - def __getitem__(self, key): - """ Remaps attempts to query an attribute, as in obj['attr'], - into the appropriate calls to query the actual browser object - under the hood. Following the JavaScript convention, we treat - obj['attr'] almost the same as obj.attr. """ - - try: - value = self.__runner.scriptRequest('get_property', self, - propertyName = str(key)) - except EnvironmentError: - # Failed to retrieve the property. We return IndexError - # for numeric keys so we can properly support Python's - # iterators, but we return KeyError for string keys to - # emulate mapping objects. - if isinstance(key, str): - raise KeyError(key) - else: - raise IndexError(key) - - return value - - def __setitem__(self, key, value): - result = self.__runner.scriptRequest('set_property', self, - propertyName = str(key), - value = value) - if not result: - if isinstance(key, str): - raise KeyError(key) - else: - raise IndexError(key) - - def __delitem__(self, key): - result = self.__runner.scriptRequest('del_property', self, - propertyName = str(key)) - if not result: - if isinstance(key, str): - raise KeyError(key) - else: - raise IndexError(key) - -class MethodWrapper: - """ This is a Python wrapper around a property of a BrowserObject - that doesn't appear to be a first-class object in the Python - sense, but is nonetheless a callable method. """ - - def __init__(self, runner, parentObj, objectId): - self.__dict__['_MethodWrapper__runner'] = runner - self.__dict__['_MethodWrapper__childObject'] = (parentObj, objectId) - - def __str__(self): - parentObj, attribName = self.__childObject - return "%s.%s" % (parentObj, attribName) - - def __bool__(self): - return True - - __nonzero__ = __bool__ # Python 2 - - def __call__(self, *args, **kw): - needsResponse = True - if 'needsResponse' in kw: - needsResponse = kw['needsResponse'] - del kw['needsResponse'] - if kw: - raise ArgumentError('Keyword arguments not supported') - - try: - parentObj, attribName = self.__childObject - # Call it as a method. - if parentObj is self.__runner.dom and attribName == 'alert': - # As a special hack, we don't wait for the return - # value from the alert() call, since this is a - # blocking call, and waiting for this could cause - # problems. - needsResponse = False - - if parentObj is self.__runner.dom and attribName == 'eval' and len(args) == 1 and isinstance(args[0], str): - # As another special hack, we make dom.eval() a - # special case, and map it directly into an eval() - # call. If the string begins with 'void ', we further - # assume we're not waiting for a response. - if args[0].startswith('void '): - needsResponse = False - result = self.__runner.scriptRequest('eval', parentObj, value = args[0], needsResponse = needsResponse) - else: - # This is a normal method call. - try: - result = self.__runner.scriptRequest('call', parentObj, propertyName = attribName, value = args, needsResponse = needsResponse) - except EnvironmentError: - # Problem on the call. Maybe no such method? - raise AttributeError - - except EnvironmentError: - # Some odd problem on the call. - raise TypeError - - return result - - def __setattr__(self, name, value): - """ setattr will generally fail on method objects. """ - raise AttributeError(name) - - def __delattr__(self, name): - """ delattr will generally fail on method objects. """ - raise AttributeError(name) diff --git a/direct/src/p3d/PackageInfo.py b/direct/src/p3d/PackageInfo.py deleted file mode 100644 index 08a73365b8..0000000000 --- a/direct/src/p3d/PackageInfo.py +++ /dev/null @@ -1,1237 +0,0 @@ -__all__ = ["PackageInfo"] - -from panda3d.core import Filename, DocumentSpec, Multifile, Decompressor, EUOk, EUSuccess, VirtualFileSystem, Thread, getModelPath, ExecutionEnvironment, PStatCollector, TiXmlDocument, TiXmlDeclaration, TiXmlElement -import panda3d.core as core -from direct.p3d.FileSpec import FileSpec -from direct.p3d.ScanDirectoryNode import ScanDirectoryNode -from direct.showbase import VFSImporter -from direct.directnotify.DirectNotifyGlobal import directNotify -from direct.task.TaskManagerGlobal import taskMgr -import os -import sys -import random -import time -import copy - -class PackageInfo: - - """ This class represents a downloadable Panda3D package file that - can be (or has been) installed into the current runtime. It is - the Python equivalent of the P3DPackage class in the core API. """ - - notify = directNotify.newCategory("PackageInfo") - - # Weight factors for computing download progress. This - # attempts to reflect the relative time-per-byte of each of - # these operations. - downloadFactor = 1 - uncompressFactor = 0.01 - unpackFactor = 0.01 - patchFactor = 0.01 - - # These tokens are yielded (not returned) by __downloadFile() and - # other InstallStep functions. - stepComplete = 1 - stepFailed = 2 - restartDownload = 3 - stepContinue = 4 - - UsageBasename = 'usage.xml' - - class InstallStep: - """ This class is one step of the installPlan list; it - represents a single atomic piece of the installation step, and - the relative effort of that piece. When the plan is executed, - it will call the saved function pointer here. """ - def __init__(self, func, bytes, factor, stepType): - self.__funcPtr = func - self.bytesNeeded = bytes - self.bytesDone = 0 - self.bytesFactor = factor - self.stepType = stepType - self.pStatCol = PStatCollector(':App:PackageInstaller:%s' % (stepType)) - - def func(self): - """ self.__funcPtr(self) will return a generator of - tokens. This function defines a new generator that yields - each of those tokens, but wraps each call into the nested - generator within a pair of start/stop collector calls. """ - - self.pStatCol.start() - for token in self.__funcPtr(self): - self.pStatCol.stop() - yield token - self.pStatCol.start() - - # Shouldn't ever get here. - self.pStatCol.stop() - raise StopIteration - - def getEffort(self): - """ Returns the relative amount of effort of this step. """ - return self.bytesNeeded * self.bytesFactor - - def getProgress(self): - """ Returns the progress of this step, in the range - 0..1. """ - if self.bytesNeeded == 0: - return 1 - return min(float(self.bytesDone) / float(self.bytesNeeded), 1) - - def __init__(self, host, packageName, packageVersion, platform = None, - solo = False, asMirror = False, perPlatform = False): - self.host = host - self.packageName = packageName - self.packageVersion = packageVersion - self.platform = platform - self.solo = solo - self.asMirror = asMirror - self.perPlatform = perPlatform - - # This will be active while we are in the middle of a download - # cycle. - self.http = None - - # This will be filled in when the host's contents.xml file is - # read. - self.packageDir = None - - # These will be filled in by HostInfo when the package is read - # from contents.xml. - self.descFile = None - self.importDescFile = None - - # These are filled in when the desc file is successfully read. - self.hasDescFile = False - self.patchVersion = None - self.displayName = None - self.guiApp = False - self.uncompressedArchive = None - self.compressedArchive = None - self.extracts = [] - self.requires = [] - self.installPlans = None - - # This is updated during downloadPackage(). It is in the - # range 0..1. - self.downloadProgress = 0 - - # This is set true when the package file has been fully - # downloaded and unpacked. - self.hasPackage = False - - # This is set true when the package has been "installed", - # meaning it's been added to the paths and all. - self.installed = False - - # This is set true when the package has been updated in this - # session, but not yet written to usage.xml. - self.updated = False - self.diskSpace = None - - def getPackageDir(self): - """ Returns the directory in which this package is installed. - This may not be known until the host's contents.xml file has - been downloaded, which informs us of the host's own install - directory. """ - - if not self.packageDir: - if not self.host.hasContentsFile: - if not self.host.readContentsFile(): - self.host.downloadContentsFile(self.http) - - # Derive the packageDir from the hostDir. - self.packageDir = Filename(self.host.hostDir, self.packageName) - if self.packageVersion: - self.packageDir = Filename(self.packageDir, self.packageVersion) - - if self.host.perPlatform: - # If we're running on a special host that wants us to - # include the platform, we include it. - includePlatform = True - elif self.perPlatform and self.host.appRunner.respectPerPlatform: - # Otherwise, if our package spec wants us to include - # the platform (and our plugin knows about this), then - # we also include it. - includePlatform = True - else: - # Otherwise, we must be running legacy code - # somewhere--either an old package or an old - # plugin--and we therefore shouldn't include the - # platform in the directory hierarchy. - includePlatform = False - - if includePlatform and self.platform: - self.packageDir = Filename(self.packageDir, self.platform) - - return self.packageDir - - def getDownloadEffort(self): - """ Returns the relative amount of effort it will take to - download this package. The units are meaningless, except - relative to other packges.""" - - if not self.installPlans: - return 0 - - # Return the size of plan A, assuming it will work. - plan = self.installPlans[0] - size = sum([step.getEffort() for step in plan]) - - return size - - def getPrevDownloadedEffort(self): - """ Returns a rough estimate of this package's total download - effort, even if it is already downloaded. """ - - effort = 0 - if self.compressedArchive: - effort += self.compressedArchive.size * self.downloadFactor - if self.uncompressedArchive: - effort += self.uncompressedArchive.size * self.uncompressFactor - # Don't bother counting unpacking. - - return effort - - def getFormattedName(self): - """ Returns the name of this package, for output to the user. - This will be the "public" name of the package, as formatted - for user consumption; it will include capital letters and - spaces where appropriate. """ - - if self.displayName: - name = self.displayName - else: - name = self.packageName - if self.packageVersion: - name += ' %s' % (self.packageVersion) - - if self.patchVersion: - name += ' rev %s' % (self.patchVersion) - - return name - - - def setupFilenames(self): - """ This is called by the HostInfo when the package is read - from contents.xml, to set up the internal filenames and such - that rely on some of the information from contents.xml. """ - - dirname, basename = self.descFile.filename.rsplit('/', 1) - self.descFileDirname = dirname - self.descFileBasename = basename - - def checkStatus(self): - """ Checks the current status of the desc file and the package - contents on disk. """ - - if self.hasPackage: - return True - - if not self.hasDescFile: - filename = Filename(self.getPackageDir(), self.descFileBasename) - if self.descFile.quickVerify(self.getPackageDir(), pathname = filename, notify = self.notify): - if self.__readDescFile(): - # Successfully read. We don't need to call - # checkArchiveStatus again, since readDescFile() - # has just done it. - return self.hasPackage - - if self.hasDescFile: - if self.__checkArchiveStatus(): - # It's all good. - self.hasPackage = True - - return self.hasPackage - - def hasCurrentDescFile(self): - """ Returns true if a desc file file has been successfully - read for this package and is still current, false - otherwise. """ - - if not self.host.hasCurrentContentsFile(): - return False - - return self.hasDescFile - - def downloadDescFile(self, http): - """ Downloads the desc file for this particular package, - synchronously, and then reads it. Returns true on success, - false on failure. """ - - for token in self.downloadDescFileGenerator(http): - if token != self.stepContinue: - break - Thread.considerYield() - - return (token == self.stepComplete) - - def downloadDescFileGenerator(self, http): - """ A generator function that implements downloadDescFile() - one piece at a time. It yields one of stepComplete, - stepFailed, or stepContinue. """ - - assert self.descFile - - if self.hasDescFile: - # We've already got one. - yield self.stepComplete; return - - if not self.host.appRunner or self.host.appRunner.verifyContents != self.host.appRunner.P3DVCNever: - # We're allowed to download it. - self.http = http - - func = lambda step, self = self: self.__downloadFile( - None, self.descFile, - urlbase = self.descFile.filename, - filename = self.descFileBasename) - step = self.InstallStep(func, self.descFile.size, self.downloadFactor, 'downloadDesc') - - for token in step.func(): - if token == self.stepContinue: - yield token - else: - break - - while token == self.restartDownload: - # Try again. - func = lambda step, self = self: self.__downloadFile( - None, self.descFile, - urlbase = self.descFile.filename, - filename = self.descFileBasename) - step = self.InstallStep(func, self.descFile.size, self.downloadFactor, 'downloadDesc') - for token in step.func(): - if token == self.stepContinue: - yield token - else: - break - - if token == self.stepFailed: - # Couldn't download the desc file. - yield self.stepFailed; return - - assert token == self.stepComplete - - filename = Filename(self.getPackageDir(), self.descFileBasename) - # Now that we've written the desc file, make it read-only. - os.chmod(filename.toOsSpecific(), 0o444) - - if not self.__readDescFile(): - # Weird, it passed the hash check, but we still can't read - # it. - filename = Filename(self.getPackageDir(), self.descFileBasename) - self.notify.warning("Failure reading %s" % (filename)) - yield self.stepFailed; return - - yield self.stepComplete; return - - def __readDescFile(self): - """ Reads the desc xml file for this particular package, - assuming it's been already downloaded and verified. Returns - true on success, false on failure. """ - - if self.hasDescFile: - # No need to read it again. - return True - - if self.solo: - # If this is a "solo" package, we don't actually "read" - # the desc file; that's the entire contents of the - # package. - self.hasDescFile = True - self.hasPackage = True - return True - - filename = Filename(self.getPackageDir(), self.descFileBasename) - - if not hasattr(core, 'TiXmlDocument'): - return False - doc = core.TiXmlDocument(filename.toOsSpecific()) - if not doc.LoadFile(): - return False - - xpackage = doc.FirstChildElement('package') - if not xpackage: - return False - - try: - self.patchVersion = int(xpackage.Attribute('patch_version') or '') - except ValueError: - self.patchVersion = None - - try: - perPlatform = int(xpackage.Attribute('per_platform') or '') - except ValueError: - perPlatform = False - if perPlatform != self.perPlatform: - self.notify.warning("per_platform disagreement on package %s" % (self.packageName)) - - self.displayName = None - xconfig = xpackage.FirstChildElement('config') - if xconfig: - # The name for display to an English-speaking user. - self.displayName = xconfig.Attribute('display_name') - - # True if any apps that use this package must be GUI apps. - guiApp = xconfig.Attribute('gui_app') - if guiApp: - self.guiApp = int(guiApp) - - # The uncompressed archive, which will be mounted directly, - # and also used for patching. - xuncompressedArchive = xpackage.FirstChildElement('uncompressed_archive') - if xuncompressedArchive: - self.uncompressedArchive = FileSpec() - self.uncompressedArchive.loadXml(xuncompressedArchive) - - # The compressed archive, which is what is downloaded. - xcompressedArchive = xpackage.FirstChildElement('compressed_archive') - if xcompressedArchive: - self.compressedArchive = FileSpec() - self.compressedArchive.loadXml(xcompressedArchive) - - # The list of files that should be extracted to disk. - self.extracts = [] - xextract = xpackage.FirstChildElement('extract') - while xextract: - file = FileSpec() - file.loadXml(xextract) - self.extracts.append(file) - xextract = xextract.NextSiblingElement('extract') - - # The list of additional packages that must be installed for - # this package to function properly. - self.requires = [] - xrequires = xpackage.FirstChildElement('requires') - while xrequires: - packageName = xrequires.Attribute('name') - version = xrequires.Attribute('version') - hostUrl = xrequires.Attribute('host') - if packageName and hostUrl: - host = self.host.appRunner.getHostWithAlt(hostUrl) - self.requires.append((packageName, version, host)) - xrequires = xrequires.NextSiblingElement('requires') - - self.hasDescFile = True - - # Now that we've read the desc file, go ahead and use it to - # verify the download status. - if self.__checkArchiveStatus(): - # It's all fully downloaded, unpacked, and ready. - self.hasPackage = True - return True - - # Still have to download it. - self.__buildInstallPlans() - return True - - def __buildInstallPlans(self): - """ Sets up self.installPlans, a list of one or more "plans" - to download and install the package. """ - - pc = PStatCollector(':App:PackageInstaller:buildInstallPlans') - pc.start() - - self.hasPackage = False - - if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: - # We're not allowed to download anything. - self.installPlans = [] - pc.stop() - return - - if self.asMirror: - # If we're just downloading a mirror archive, we only need - # to get the compressed archive file. - - # Build a one-item install plan to download the compressed - # archive. - downloadSize = self.compressedArchive.size - func = lambda step, fileSpec = self.compressedArchive: self.__downloadFile(step, fileSpec, allowPartial = True) - - step = self.InstallStep(func, downloadSize, self.downloadFactor, 'download') - installPlan = [step] - self.installPlans = [installPlan] - pc.stop() - return - - # The normal download process. Determine what we will need to - # download, and build a plan (or two) to download it all. - self.installPlans = None - - # We know we will at least need to unpack the archive contents - # at the end. - unpackSize = 0 - for file in self.extracts: - unpackSize += file.size - step = self.InstallStep(self.__unpackArchive, unpackSize, self.unpackFactor, 'unpack') - planA = [step] - - # If the uncompressed archive file is good, that's all we'll - # need to do. - self.uncompressedArchive.actualFile = None - if self.uncompressedArchive.quickVerify(self.getPackageDir(), notify = self.notify): - self.installPlans = [planA] - pc.stop() - return - - # Maybe the compressed archive file is good. - if self.compressedArchive.quickVerify(self.getPackageDir(), notify = self.notify): - uncompressSize = self.uncompressedArchive.size - step = self.InstallStep(self.__uncompressArchive, uncompressSize, self.uncompressFactor, 'uncompress') - planA = [step] + planA - self.installPlans = [planA] - pc.stop() - return - - # Maybe we can download one or more patches. We'll come back - # to that in a minute as plan A. For now, construct plan B, - # which will be to download the whole archive. - planB = planA[:] - - uncompressSize = self.uncompressedArchive.size - step = self.InstallStep(self.__uncompressArchive, uncompressSize, self.uncompressFactor, 'uncompress') - planB = [step] + planB - - downloadSize = self.compressedArchive.size - func = lambda step, fileSpec = self.compressedArchive: self.__downloadFile(step, fileSpec, allowPartial = True) - - step = self.InstallStep(func, downloadSize, self.downloadFactor, 'download') - planB = [step] + planB - - # Now look for patches. Start with the md5 hash from the - # uncompressedArchive file we have on disk, and see if we can - # find a patch chain from this file to our target. - pathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) - fileSpec = self.uncompressedArchive.actualFile - if fileSpec is None and pathname.exists(): - fileSpec = FileSpec() - fileSpec.fromFile(self.getPackageDir(), self.uncompressedArchive.filename) - plan = None - if fileSpec: - plan = self.__findPatchChain(fileSpec) - if plan: - # We can download patches. Great! That means this is - # plan A, and the full download is plan B (in case - # something goes wrong with the patching). - planA = plan + planA - self.installPlans = [planA, planB] - else: - # There are no patches to download, oh well. Stick with - # plan B as the only plan. - self.installPlans = [planB] - - # In case of unexpected failures on the internet, we will retry - # the full download instead of just giving up. - retries = core.ConfigVariableInt('package-full-dl-retries', 1).getValue() - for retry in range(retries): - self.installPlans.append(planB[:]) - - pc.stop() - - def __scanDirectoryRecursively(self, dirname): - """ Generates a list of Filename objects: all of the files - (not directories) within and below the indicated dirname. """ - - contents = [] - for dirpath, dirnames, filenames in os.walk(dirname.toOsSpecific()): - dirpath = Filename.fromOsSpecific(dirpath) - if dirpath == dirname: - dirpath = Filename('') - else: - dirpath.makeRelativeTo(dirname) - for filename in filenames: - contents.append(Filename(dirpath, filename)) - return contents - - def __removeFileFromList(self, contents, filename): - """ Removes the indicated filename from the given list, if it is - present. """ - try: - contents.remove(Filename(filename)) - except ValueError: - pass - - def __checkArchiveStatus(self): - """ Returns true if the archive and all extractable files are - already correct on disk, false otherwise. """ - - if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: - # Assume that everything is just fine. - return True - - # Get a list of all of the files in the directory, so we can - # remove files that don't belong. - contents = self.__scanDirectoryRecursively(self.getPackageDir()) - self.__removeFileFromList(contents, self.descFileBasename) - self.__removeFileFromList(contents, self.compressedArchive.filename) - self.__removeFileFromList(contents, self.UsageBasename) - if not self.asMirror: - self.__removeFileFromList(contents, self.uncompressedArchive.filename) - for file in self.extracts: - self.__removeFileFromList(contents, file.filename) - - # Now, any files that are still in the contents list don't - # belong. It's important to remove these files before we - # start verifying the files that we expect to find here, in - # case there is a problem with ambiguous filenames or - # something (e.g. case insensitivity). - for filename in contents: - self.notify.info("Removing %s" % (filename)) - pathname = Filename(self.getPackageDir(), filename) - pathname.unlink() - self.updated = True - - if self.asMirror: - return self.compressedArchive.quickVerify(self.getPackageDir(), notify = self.notify) - - allExtractsOk = True - if not self.uncompressedArchive.quickVerify(self.getPackageDir(), notify = self.notify): - self.notify.debug("File is incorrect: %s" % (self.uncompressedArchive.filename)) - allExtractsOk = False - - if allExtractsOk: - # OK, the uncompressed archive is good; that means there - # shouldn't be a compressed archive file here. - pathname = Filename(self.getPackageDir(), self.compressedArchive.filename) - pathname.unlink() - - for file in self.extracts: - if not file.quickVerify(self.getPackageDir(), notify = self.notify): - self.notify.debug("File is incorrect: %s" % (file.filename)) - allExtractsOk = False - break - - if allExtractsOk: - self.notify.debug("All %s extracts of %s seem good." % ( - len(self.extracts), self.packageName)) - - return allExtractsOk - - def __updateStepProgress(self, step): - """ This callback is made from within the several step - functions as the download step proceeds. It updates - self.downloadProgress with the current progress, so the caller - can asynchronously query this value. """ - - size = self.totalPlanCompleted + self.currentStepEffort * step.getProgress() - self.downloadProgress = min(float(size) / float(self.totalPlanSize), 1) - - def downloadPackage(self, http): - """ Downloads the package file, synchronously, then - uncompresses and unpacks it. Returns true on success, false - on failure. - - This assumes that self.installPlans has already been filled - in, which will have been done by self.__readDescFile(). - """ - - for token in self.downloadPackageGenerator(http): - if token != self.stepContinue: - break - Thread.considerYield() - - return (token == self.stepComplete) - - def downloadPackageGenerator(self, http): - """ A generator function that implements downloadPackage() one - piece at a time. It yields one of stepComplete, stepFailed, - or stepContinue. """ - - assert self.hasDescFile - - if self.hasPackage: - # We've already got one. - yield self.stepComplete; return - - if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: - # We're not allowed to download anything. Assume it's already downloaded. - yield self.stepComplete; return - - # We should have an install plan by the time we get here. - assert self.installPlans - - self.http = http - for token in self.__followInstallPlans(): - if token == self.stepContinue: - yield token - else: - break - - while token == self.restartDownload: - # Try again. - for token in self.downloadDescFileGenerator(http): - if token == self.stepContinue: - yield token - else: - break - if token == self.stepComplete: - for token in self.__followInstallPlans(): - if token == self.stepContinue: - yield token - else: - break - - if token == self.stepFailed: - yield self.stepFailed; return - - assert token == self.stepComplete - yield self.stepComplete; return - - - def __followInstallPlans(self): - """ Performs all of the steps in self.installPlans. Yields - one of stepComplete, stepFailed, restartDownload, or - stepContinue. """ - - if not self.installPlans: - self.__buildInstallPlans() - - installPlans = self.installPlans - self.installPlans = None - for plan in installPlans: - self.totalPlanSize = sum([step.getEffort() for step in plan]) - self.totalPlanCompleted = 0 - self.downloadProgress = 0 - - planFailed = False - for step in plan: - self.currentStepEffort = step.getEffort() - - for token in step.func(): - if token == self.stepContinue: - yield token - else: - break - - if token == self.restartDownload: - yield token - if token == self.stepFailed: - planFailed = True - break - assert token == self.stepComplete - - self.totalPlanCompleted += self.currentStepEffort - - if not planFailed: - # Successfully downloaded! - yield self.stepComplete; return - - if taskMgr.destroyed: - yield self.stepFailed; return - - # All plans failed. - yield self.stepFailed; return - - def __findPatchChain(self, fileSpec): - """ Finds the chain of patches that leads from the indicated - patch version to the current patch version. If found, - constructs an installPlan that represents the steps of the - patch installation; otherwise, returns None. """ - - from direct.p3d.PatchMaker import PatchMaker - - patchMaker = PatchMaker(self.getPackageDir()) - patchChain = patchMaker.getPatchChainToCurrent(self.descFileBasename, fileSpec) - if patchChain is None: - # No path. - patchMaker.cleanup() - return None - - plan = [] - for patchfile in patchChain: - downloadSize = patchfile.file.size - func = lambda step, fileSpec = patchfile.file: self.__downloadFile(step, fileSpec, allowPartial = True) - step = self.InstallStep(func, downloadSize, self.downloadFactor, 'download') - plan.append(step) - - patchSize = patchfile.targetFile.size - func = lambda step, patchfile = patchfile: self.__applyPatch(step, patchfile) - step = self.InstallStep(func, patchSize, self.patchFactor, 'patch') - plan.append(step) - - patchMaker.cleanup() - return plan - - def __downloadFile(self, step, fileSpec, urlbase = None, filename = None, - allowPartial = False): - """ Downloads the indicated file from the host into - packageDir. Yields one of stepComplete, stepFailed, - restartDownload, or stepContinue. """ - - if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: - # We're not allowed to download anything. - yield self.stepFailed; return - - self.updated = True - - if not urlbase: - urlbase = self.descFileDirname + '/' + fileSpec.filename - - # Build up a list of URL's to try downloading from. Unlike - # the C++ implementation in P3DPackage.cxx, here we build the - # URL's in forward order. - tryUrls = [] - - if self.host.appRunner and self.host.appRunner.superMirrorUrl: - # We start with the "super mirror", if it's defined. - url = self.host.appRunner.superMirrorUrl + urlbase - tryUrls.append((url, False)) - - if self.host.mirrors: - # Choose two mirrors at random. - mirrors = self.host.mirrors[:] - for i in range(2): - mirror = random.choice(mirrors) - mirrors.remove(mirror) - url = mirror + urlbase - tryUrls.append((url, False)) - if not mirrors: - break - - # After trying two mirrors and failing (or if there are no - # mirrors), go get it from the original host. - url = self.host.downloadUrlPrefix + urlbase - tryUrls.append((url, False)) - - # And finally, if the original host also fails, try again with - # a cache-buster. - tryUrls.append((url, True)) - - for url, cacheBust in tryUrls: - request = DocumentSpec(url) - - if cacheBust: - # On the last attempt to download a particular file, - # we bust through the cache: append a query string to - # do this. - url += '?' + str(int(time.time())) - request = DocumentSpec(url) - request.setCacheControl(DocumentSpec.CCNoCache) - - self.notify.info("%s downloading %s" % (self.packageName, url)) - - if not filename: - filename = fileSpec.filename - targetPathname = Filename(self.getPackageDir(), filename) - targetPathname.setBinary() - - channel = self.http.makeChannel(False) - - # If there's a previous partial download, attempt to resume it. - bytesStarted = 0 - if allowPartial and not cacheBust and targetPathname.exists(): - bytesStarted = targetPathname.getFileSize() - - if bytesStarted < 1024*1024: - # Not enough bytes downloaded to be worth the risk of - # a partial download. - bytesStarted = 0 - elif bytesStarted >= fileSpec.size: - # Couldn't possibly be our file. - bytesStarted = 0 - - if bytesStarted: - self.notify.info("Resuming %s after %s bytes already downloaded" % (url, bytesStarted)) - # Make sure the file is writable. - os.chmod(targetPathname.toOsSpecific(), 0o644) - channel.beginGetSubdocument(request, bytesStarted, 0) - else: - # No partial download possible; get the whole file. - targetPathname.makeDir() - targetPathname.unlink() - channel.beginGetDocument(request) - - channel.downloadToFile(targetPathname) - while channel.run(): - if step: - step.bytesDone = channel.getBytesDownloaded() + channel.getFirstByteDelivered() - if step.bytesDone > step.bytesNeeded: - # Oops, too much data. Might as well abort; - # it's the wrong file. - self.notify.warning("Got more data than expected for download %s" % (url)) - break - - self.__updateStepProgress(step) - - if taskMgr.destroyed: - # If the task manager has been destroyed, we must - # be shutting down. Get out of here. - self.notify.warning("Task Manager destroyed, aborting %s" % (url)) - yield self.stepFailed; return - - yield self.stepContinue - - if step: - step.bytesDone = channel.getBytesDownloaded() + channel.getFirstByteDelivered() - self.__updateStepProgress(step) - - if not channel.isValid(): - self.notify.warning("Failed to download %s" % (url)) - - elif not fileSpec.fullVerify(self.getPackageDir(), pathname = targetPathname, notify = self.notify): - self.notify.warning("After downloading, %s incorrect" % (Filename(fileSpec.filename).getBasename())) - - # This attempt failed. Maybe the original contents.xml - # file is stale. Try re-downloading it now, just to be - # sure. - if self.host.redownloadContentsFile(self.http): - # Yes! Go back and start over from the beginning. - yield self.restartDownload; return - - else: - # Success! - yield self.stepComplete; return - - # Maybe the mirror is bad. Go back and try the next - # mirror. - - # All attempts failed. Maybe the original contents.xml file - # is stale. Try re-downloading it now, just to be sure. - if self.host.redownloadContentsFile(self.http): - # Yes! Go back and start over from the beginning. - yield self.restartDownload; return - - # All mirrors failed; the server (or the internet connection) - # must be just fubar. - yield self.stepFailed; return - - def __applyPatch(self, step, patchfile): - """ Applies the indicated patching in-place to the current - uncompressed archive. The patchfile is removed after the - operation. Yields one of stepComplete, stepFailed, - restartDownload, or stepContinue. """ - - self.updated = True - - origPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) - patchPathname = Filename(self.getPackageDir(), patchfile.file.filename) - result = Filename.temporary('', 'patch_') - self.notify.info("Patching %s with %s" % (origPathname, patchPathname)) - - p = core.Patchfile() # The C++ class - - ret = p.initiate(patchPathname, origPathname, result) - if ret == EUSuccess: - ret = p.run() - while ret == EUOk: - step.bytesDone = step.bytesNeeded * p.getProgress() - self.__updateStepProgress(step) - if taskMgr.destroyed: - # If the task manager has been destroyed, we must - # be shutting down. Get out of here. - self.notify.warning("Task Manager destroyed, aborting patch %s" % (origPathname)) - yield self.stepFailed; return - - yield self.stepContinue - ret = p.run() - del p - patchPathname.unlink() - - if ret < 0: - self.notify.warning("Patching of %s failed." % (origPathname)) - result.unlink() - yield self.stepFailed; return - - if not result.renameTo(origPathname): - self.notify.warning("Couldn't rename %s to %s" % (result, origPathname)) - yield self.stepFailed; return - - yield self.stepComplete; return - - def __uncompressArchive(self, step): - """ Turns the compressed archive into the uncompressed - archive. Yields one of stepComplete, stepFailed, - restartDownload, or stepContinue. """ - - if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: - # We're not allowed to! - yield self.stepFailed; return - - self.updated = True - - sourcePathname = Filename(self.getPackageDir(), self.compressedArchive.filename) - targetPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) - targetPathname.unlink() - self.notify.info("Uncompressing %s to %s" % (sourcePathname, targetPathname)) - decompressor = Decompressor() - decompressor.initiate(sourcePathname, targetPathname) - totalBytes = self.uncompressedArchive.size - result = decompressor.run() - while result == EUOk: - step.bytesDone = int(totalBytes * decompressor.getProgress()) - self.__updateStepProgress(step) - result = decompressor.run() - if taskMgr.destroyed: - # If the task manager has been destroyed, we must - # be shutting down. Get out of here. - self.notify.warning("Task Manager destroyed, aborting decompresss %s" % (sourcePathname)) - yield self.stepFailed; return - - yield self.stepContinue - - if result != EUSuccess: - yield self.stepFailed; return - - step.bytesDone = totalBytes - self.__updateStepProgress(step) - - if not self.uncompressedArchive.quickVerify(self.getPackageDir(), notify= self.notify): - self.notify.warning("after uncompressing, %s still incorrect" % ( - self.uncompressedArchive.filename)) - yield self.stepFailed; return - - # Now that we've verified the archive, make it read-only. - os.chmod(targetPathname.toOsSpecific(), 0o444) - - # Now we can safely remove the compressed archive. - sourcePathname.unlink() - yield self.stepComplete; return - - def __unpackArchive(self, step): - """ Unpacks any files in the archive that want to be unpacked - to disk. Yields one of stepComplete, stepFailed, - restartDownload, or stepContinue. """ - - if not self.extracts: - # Nothing to extract. - self.hasPackage = True - yield self.stepComplete; return - - if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: - # We're not allowed to! - yield self.stepFailed; return - - self.updated = True - - mfPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) - self.notify.info("Unpacking %s" % (mfPathname)) - mf = Multifile() - if not mf.openRead(mfPathname): - self.notify.warning("Couldn't open %s" % (mfPathname)) - yield self.stepFailed; return - - allExtractsOk = True - step.bytesDone = 0 - for file in self.extracts: - i = mf.findSubfile(file.filename) - if i == -1: - self.notify.warning("Not in Multifile: %s" % (file.filename)) - allExtractsOk = False - continue - - targetPathname = Filename(self.getPackageDir(), file.filename) - targetPathname.setBinary() - targetPathname.unlink() - if not mf.extractSubfile(i, targetPathname): - self.notify.warning("Couldn't extract: %s" % (file.filename)) - allExtractsOk = False - continue - - if not file.quickVerify(self.getPackageDir(), notify = self.notify): - self.notify.warning("After extracting, still incorrect: %s" % (file.filename)) - allExtractsOk = False - continue - - # Make sure it's executable, and not writable. - os.chmod(targetPathname.toOsSpecific(), 0o555) - - step.bytesDone += file.size - self.__updateStepProgress(step) - if taskMgr.destroyed: - # If the task manager has been destroyed, we must - # be shutting down. Get out of here. - self.notify.warning("Task Manager destroyed, aborting unpacking %s" % (mfPathname)) - yield self.stepFailed; return - - yield self.stepContinue - - if not allExtractsOk: - yield self.stepFailed; return - - self.hasPackage = True - yield self.stepComplete; return - - def installPackage(self, appRunner): - """ Mounts the package and sets up system paths so it becomes - available for use. Returns true on success, false on failure. """ - - assert self.hasPackage - if self.installed: - # Already installed. - return True - assert self not in appRunner.installedPackages - - mfPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) - mf = Multifile() - if not mf.openRead(mfPathname): - self.notify.warning("Couldn't open %s" % (mfPathname)) - return False - - # We mount it under its actual location on disk. - root = self.getPackageDir() - - vfs = VirtualFileSystem.getGlobalPtr() - vfs.mount(mf, root, vfs.MFReadOnly) - - # Add this to the Python search path, if it's not already - # there. We have to take a bit of care to check if it's - # already there, since there can be some ambiguity in - # os-specific path strings. - osRoot = self.getPackageDir().toOsSpecific() - foundOnPath = False - for p in sys.path: - if osRoot == p: - # Already here, exactly. - foundOnPath = True - break - elif osRoot == Filename.fromOsSpecific(p).toOsSpecific(): - # Already here, with some futzing. - foundOnPath = True - break - - if not foundOnPath: - # Not already here; add it. - sys.path.append(osRoot) - - # Put it on the model-path, too. We do this indiscriminantly, - # because the Panda3D runtime won't be adding things to the - # model-path, so it shouldn't be already there. - getModelPath().appendDirectory(self.getPackageDir()) - - # Set the environment variable to reference the package root. - envvar = '%s_ROOT' % (self.packageName.upper()) - ExecutionEnvironment.setEnvironmentVariable(envvar, osRoot) - - # Add the package root to the system paths. - if sys.platform.startswith('win'): - path = os.environ.get('PATH', '') - os.environ['PATH'] = "%s;%s" % (osRoot, path) - else: - path = os.environ.get('PATH', '') - os.environ['PATH'] = "%s:%s" % (osRoot, path) - path = os.environ.get('LD_LIBRARY_PATH', '') - os.environ['LD_LIBRARY_PATH'] = "%s:%s" % (osRoot, path) - - if sys.platform == "darwin": - path = os.environ.get('DYLD_LIBRARY_PATH', '') - os.environ['DYLD_LIBRARY_PATH'] = "%s:%s" % (osRoot, path) - - # Now that the environment variable is set, read all of the - # prc files in the package. - appRunner.loadMultifilePrcFiles(mf, self.getPackageDir()) - - # Also, find any toplevel Python packages, and add these as - # shared packages. This will allow different packages - # installed in different directories to share Python files as - # if they were all in the same directory. - for filename in mf.getSubfileNames(): - if filename.endswith('/__init__.pyc') or \ - filename.endswith('/__init__.pyo') or \ - filename.endswith('/__init__.py'): - components = filename.split('/')[:-1] - moduleName = '.'.join(components) - VFSImporter.sharedPackages[moduleName] = True - - # Fix up any shared directories so we can load packages from - # disparate locations. - VFSImporter.reloadSharedPackages() - - self.installed = True - appRunner.installedPackages.append(self) - - self.markUsed() - - return True - - def __measureDiskSpace(self): - """ Returns the amount of space used by this package, in - bytes, as determined by examining the actual contents of the - package directory and its subdirectories. """ - - thisDir = ScanDirectoryNode(self.getPackageDir(), ignoreUsageXml = True) - diskSpace = thisDir.getTotalSize() - self.notify.info("Package %s uses %s MB" % ( - self.packageName, (diskSpace + 524288) // 1048576)) - return diskSpace - - def markUsed(self): - """ Marks the package as having been used. This is normally - called automatically by installPackage(). """ - - if not hasattr(core, 'TiXmlDocument'): - return - - if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: - # Not allowed to write any files to the package directory. - return - - if self.updated: - # If we've just installed a new version of the package, - # re-measure the actual disk space used. - self.diskSpace = self.__measureDiskSpace() - - filename = Filename(self.getPackageDir(), self.UsageBasename) - doc = TiXmlDocument(filename.toOsSpecific()) - if not doc.LoadFile(): - decl = TiXmlDeclaration("1.0", "utf-8", "") - doc.InsertEndChild(decl) - - xusage = doc.FirstChildElement('usage') - if not xusage: - doc.InsertEndChild(TiXmlElement('usage')) - xusage = doc.FirstChildElement('usage') - - now = int(time.time()) - - count = xusage.Attribute('count_app') - try: - count = int(count or '') - except ValueError: - count = 0 - xusage.SetAttribute('first_use', str(now)) - count += 1 - xusage.SetAttribute('count_app', str(count)) - - xusage.SetAttribute('last_use', str(now)) - - if self.updated: - xusage.SetAttribute('last_update', str(now)) - self.updated = False - else: - # Since we haven't changed the disk space, we can just - # read it from the previous xml file. - diskSpace = xusage.Attribute('disk_space') - try: - diskSpace = int(diskSpace or '') - except ValueError: - # Unless it wasn't set already. - self.diskSpace = self.__measureDiskSpace() - - xusage.SetAttribute('disk_space', str(self.diskSpace)) - - # Write the file to a temporary filename, then atomically move - # it to its actual filename, to avoid race conditions when - # updating this file. - tfile = Filename.temporary(str(self.getPackageDir()), '.xml') - if doc.SaveFile(tfile.toOsSpecific()): - tfile.renameTo(filename) - - def getUsage(self): - """ Returns the xusage element that is read from the usage.xml - file, or None if there is no usage.xml file. """ - - if not hasattr(core, 'TiXmlDocument'): - return None - - filename = Filename(self.getPackageDir(), self.UsageBasename) - doc = TiXmlDocument(filename.toOsSpecific()) - if not doc.LoadFile(): - return None - - xusage = doc.FirstChildElement('usage') - if not xusage: - return None - - return copy.copy(xusage) - diff --git a/direct/src/p3d/PackageInstaller.py b/direct/src/p3d/PackageInstaller.py deleted file mode 100644 index cec1e07b11..0000000000 --- a/direct/src/p3d/PackageInstaller.py +++ /dev/null @@ -1,640 +0,0 @@ -__all__ = ["PackageInstaller"] - -from direct.showbase.DirectObject import DirectObject -from direct.stdpy.threading import Lock, RLock -from direct.showbase.MessengerGlobal import messenger -from direct.task.TaskManagerGlobal import taskMgr -from direct.p3d.PackageInfo import PackageInfo -from panda3d.core import TPLow, PStatCollector -from direct.directnotify.DirectNotifyGlobal import directNotify - -class PackageInstaller(DirectObject): - - """ This class is used in a p3d runtime environment to manage the - asynchronous download and installation of packages. If you just - want to install a package synchronously, see - appRunner.installPackage() for a simpler interface. - - To use this class, you should subclass from it and override any of - the six callback methods: downloadStarted(), packageStarted(), - packageProgress(), downloadProgress(), packageFinished(), - downloadFinished(). - - Also see DWBPackageInstaller, which does exactly this, to add a - DirectWaitBar GUI. - - """ - - notify = directNotify.newCategory("PackageInstaller") - - globalLock = Lock() - nextUniqueId = 1 - - # This is a chain of state values progressing forward in time. - S_initial = 0 # addPackage() calls are being made - S_ready = 1 # donePackages() has been called - S_started = 2 # download has started - S_done = 3 # download is over - - class PendingPackage: - """ This class describes a package added to the installer for - download. """ - - notify = directNotify.newCategory("PendingPackage") - - def __init__(self, packageName, version, host): - self.packageName = packageName - self.version = version - self.host = host - - # This will be filled in properly by checkDescFile() or - # getDescFile(); in the meantime, set a placeholder. - self.package = PackageInfo(host, packageName, version) - - # Set true when the package has finished downloading, - # either successfully or unsuccessfully. - self.done = False - - # Set true or false when self.done has been set. - self.success = False - - # Set true when the packageFinished() callback has been - # delivered. - self.notified = False - - # These are used to ensure the callbacks only get - # delivered once for a particular package. - self.calledPackageStarted = False - self.calledPackageFinished = False - - # This is the amount of stuff we have to process to - # install this package, and the amount of stuff we have - # processed so far. "Stuff" includes bytes downloaded, - # bytes uncompressed, and bytes extracted; and each of - # which is weighted differently into one grand total. So, - # the total doesn't really represent bytes; it's a - # unitless number, which means something only as a ratio - # to other packages. Filled in by checkDescFile() or - # getDescFile(). - self.downloadEffort = 0 - - # Similar, but this is the theoretical effort if the - # package were already downloaded. - self.prevDownloadedEffort = 0 - - def __cmp__(self, pp): - """ Python comparision function. This makes all - PendingPackages withe same (packageName, version, host) - combination be deemed equivalent. """ - return cmp((self.packageName, self.version, self.host), - (pp.packageName, pp.version, pp.host)) - - def getProgress(self): - """ Returns the download progress of this package in the - range 0..1. """ - - return self.package.downloadProgress - - def checkDescFile(self): - """ Returns true if the desc file is already downloaded - and good, or false if it needs to be downloaded. """ - - if not self.host.hasCurrentContentsFile(): - # If the contents file isn't ready yet, we can't check - # the desc file yet. - return False - - # All right, get the package info now. - package = self.host.getPackage(self.packageName, self.version) - if not package: - self.notify.warning("Package %s %s not known on %s" % ( - self.packageName, self.version, self.host.hostUrl)) - return False - - self.package = package - self.package.checkStatus() - - if not self.package.hasDescFile: - return False - - self.downloadEffort = self.package.getDownloadEffort() - self.prevDownloadEffort = 0 - if self.downloadEffort == 0: - self.prevDownloadedEffort = self.package.getPrevDownloadedEffort() - - return True - - - def getDescFile(self, http): - """ Synchronously downloads the desc files required for - the package. """ - - if not self.host.downloadContentsFile(http): - return False - - # All right, get the package info now. - package = self.host.getPackage(self.packageName, self.version) - if not package: - self.notify.warning("Package %s %s not known on %s" % ( - self.packageName, self.version, self.host.hostUrl)) - return False - - self.package = package - if not self.package.downloadDescFile(http): - return False - - self.package.checkStatus() - self.downloadEffort = self.package.getDownloadEffort() - self.prevDownloadEffort = 0 - if self.downloadEffort == 0: - self.prevDownloadedEffort = self.package.getPrevDownloadedEffort() - - return True - - def __init__(self, appRunner, taskChain = 'default'): - self.globalLock.acquire() - try: - self.uniqueId = PackageInstaller.nextUniqueId - PackageInstaller.nextUniqueId += 1 - finally: - self.globalLock.release() - - self.appRunner = appRunner - self.taskChain = taskChain - - # If we're to be running on an asynchronous task chain, and - # the task chain hasn't yet been set up already, create the - # default parameters now. - if taskChain != 'default' and not taskMgr.hasTaskChain(self.taskChain): - taskMgr.setupTaskChain(self.taskChain, numThreads = 1, - threadPriority = TPLow) - - self.callbackLock = Lock() - self.calledDownloadStarted = False - self.calledDownloadFinished = False - - # A list of all packages that have been added to the - # installer. - self.packageLock = RLock() - self.packages = [] - self.state = self.S_initial - - # A list of packages that are waiting for their desc files. - self.needsDescFile = [] - self.descFileTask = None - - # A list of packages that are waiting to be downloaded and - # installed. - self.needsDownload = [] - self.downloadTask = None - - # A list of packages that were already done at the time they - # were passed to addPackage(). - self.earlyDone = [] - - # A list of packages that have been successfully installed, or - # packages that have failed. - self.done = [] - self.failed = [] - - # This task is spawned on the default task chain, to update - # the status during the download. - self.progressTask = None - - self.accept('PackageInstaller-%s-allHaveDesc' % self.uniqueId, - self.__allHaveDesc) - self.accept('PackageInstaller-%s-packageStarted' % self.uniqueId, - self.__packageStarted) - self.accept('PackageInstaller-%s-packageDone' % self.uniqueId, - self.__packageDone) - - def destroy(self): - """ Interrupts all pending downloads. No further callbacks - will be made. """ - self.cleanup() - - def cleanup(self): - """ Interrupts all pending downloads. No further callbacks - will be made. """ - - self.packageLock.acquire() - try: - if self.descFileTask: - taskMgr.remove(self.descFileTask) - self.descFileTask = None - if self.downloadTask: - taskMgr.remove(self.downloadTask) - self.downloadTask = None - finally: - self.packageLock.release() - - if self.progressTask: - taskMgr.remove(self.progressTask) - self.progressTask = None - - self.ignoreAll() - - def addPackage(self, packageName, version = None, hostUrl = None): - """ Adds the named package to the list of packages to be - downloaded. Call donePackages() to finish the list. """ - - if self.state != self.S_initial: - raise ValueError('addPackage called after donePackages') - - host = self.appRunner.getHostWithAlt(hostUrl) - pp = self.PendingPackage(packageName, version, host) - - self.packageLock.acquire() - try: - self.__internalAddPackage(pp) - finally: - self.packageLock.release() - - def __internalAddPackage(self, pp): - """ Adds the indicated "pending package" to the appropriate - list(s) for downloading and installing. Assumes packageLock - is already held.""" - - if pp in self.packages: - # Already added. - return - - self.packages.append(pp) - - # We always add the package to needsDescFile, even if we - # already have its desc file; this guarantees that packages - # are downloaded in the order they are added. - self.needsDescFile.append(pp) - if not self.descFileTask: - self.descFileTask = taskMgr.add( - self.__getDescFileTask, 'getDescFile', - taskChain = self.taskChain) - - def donePackages(self): - """ After calling addPackage() for each package to be - installed, call donePackages() to mark the end of the list. - This is necessary to determine what the complete set of - packages is (and therefore how large the total download size - is). None of the low-level callbacks will be made before this - call. """ - - if self.state != self.S_initial: - # We've already been here. - return - - # Throw the messages for packages that were already done - # before we started. - for pp in self.earlyDone: - self.__donePackage(pp, True) - self.earlyDone = [] - - self.packageLock.acquire() - try: - if self.state != self.S_initial: - return - self.state = self.S_ready - if not self.needsDescFile: - # All package desc files are already available; so begin. - self.__prepareToStart() - finally: - self.packageLock.release() - - if not self.packages: - # Trivial no-op. - self.__callDownloadFinished(True) - - def downloadStarted(self): - """ This callback is made at some point after donePackages() - is called; at the time of this callback, the total download - size is known, and we can sensibly report progress through the - whole. """ - - self.notify.info("downloadStarted") - - def packageStarted(self, package): - """ This callback is made for each package between - downloadStarted() and downloadFinished() to indicate the start - of a new package. """ - - self.notify.debug("packageStarted: %s" % (package.packageName)) - - def packageProgress(self, package, progress): - """ This callback is made repeatedly between packageStarted() - and packageFinished() to update the current progress on the - indicated package only. The progress value ranges from 0 - (beginning) to 1 (complete). """ - - self.notify.debug("packageProgress: %s %s" % (package.packageName, progress)) - - def downloadProgress(self, overallProgress): - """ This callback is made repeatedly between downloadStarted() - and downloadFinished() to update the current progress through - all packages. The progress value ranges from 0 (beginning) to - 1 (complete). """ - - self.notify.debug("downloadProgress: %s" % (overallProgress)) - - def packageFinished(self, package, success): - """ This callback is made for each package between - downloadStarted() and downloadFinished() to indicate that a - package has finished downloading. If success is true, there - were no problems and the package is now installed. - - If this package did not require downloading (because it was - already downloaded), this callback will be made immediately, - *without* a corresponding call to packageStarted(), and may - even be made before downloadStarted(). """ - - self.notify.info("packageFinished: %s %s" % (package.packageName, success)) - - def downloadFinished(self, success): - """ This callback is made when all of the packages have been - downloaded and installed (or there has been some failure). If - all packages where successfully installed, success is True. - - If there were no packages that required downloading, this - callback will be made immediately, *without* a corresponding - call to downloadStarted(). """ - - self.notify.info("downloadFinished: %s" % (success)) - - def __prepareToStart(self): - """ This is called internally when transitioning from S_ready - to S_started. It sets up whatever initial values are - needed. Assumes self.packageLock is held. Returns False if - there were no packages to download, and the state was - therefore transitioned immediately to S_done. """ - - if not self.needsDownload: - self.state = self.S_done - return False - - self.state = self.S_started - - assert not self.downloadTask - self.downloadTask = taskMgr.add( - self.__downloadPackageTask, 'downloadPackage', - taskChain = self.taskChain) - - assert not self.progressTask - self.progressTask = taskMgr.add( - self.__progressTask, 'packageProgress') - - return True - - def __allHaveDesc(self): - """ This method is called internally when all of the pending - packages have their desc info. """ - working = True - - self.packageLock.acquire() - try: - if self.state == self.S_ready: - # We've already called donePackages(), so move on now. - working = self.__prepareToStart() - finally: - self.packageLock.release() - - if not working: - self.__callDownloadFinished(True) - - def __packageStarted(self, pp): - """ This method is called when a single package is beginning - to download. """ - - self.__callDownloadStarted() - self.__callPackageStarted(pp) - - def __packageDone(self, pp): - """ This method is called when a single package has been - downloaded and installed, or has failed. """ - - self.__callPackageFinished(pp, pp.success) - pp.notified = True - - # See if there are more packages to go. - success = True - allDone = True - self.packageLock.acquire() - try: - for pp in self.packages: - if pp.notified: - success = success and pp.success - else: - allDone = False - finally: - self.packageLock.release() - - if allDone: - self.__callDownloadFinished(success) - - def __callPackageStarted(self, pp): - """ Calls the packageStarted() callback for a particular - package if it has not already been called, being careful to - avoid race conditions. """ - - self.callbackLock.acquire() - try: - if not pp.calledPackageStarted: - self.packageStarted(pp.package) - self.packageProgress(pp.package, 0) - pp.calledPackageStarted = True - finally: - self.callbackLock.release() - - def __callPackageFinished(self, pp, success): - """ Calls the packageFinished() callback for a paricular - package if it has not already been called, being careful to - avoid race conditions. """ - - self.callbackLock.acquire() - try: - if not pp.calledPackageFinished: - if success: - self.packageProgress(pp.package, 1) - self.packageFinished(pp.package, success) - pp.calledPackageFinished = True - finally: - self.callbackLock.release() - - def __callDownloadStarted(self): - """ Calls the downloadStarted() callback if it has not already - been called, being careful to avoid race conditions. """ - - self.callbackLock.acquire() - try: - if not self.calledDownloadStarted: - self.downloadStarted() - self.downloadProgress(0) - self.calledDownloadStarted = True - finally: - self.callbackLock.release() - - def __callDownloadFinished(self, success): - """ Calls the downloadFinished() callback if it has not - already been called, being careful to avoid race - conditions. """ - - self.callbackLock.acquire() - try: - if not self.calledDownloadFinished: - if success: - self.downloadProgress(1) - self.downloadFinished(success) - self.calledDownloadFinished = True - finally: - self.callbackLock.release() - - def __getDescFileTask(self, task): - - """ This task runs on the aysynchronous task chain; each pass, - it extracts one package from self.needsDescFile and downloads - its desc file. On success, it adds the package to - self.needsDownload. """ - - self.packageLock.acquire() - try: - # If we've finished all of the packages that need desc - # files, stop the task. - if not self.needsDescFile: - self.descFileTask = None - - eventName = 'PackageInstaller-%s-allHaveDesc' % self.uniqueId - messenger.send(eventName, taskChain = 'default') - - return task.done - pp = self.needsDescFile[0] - del self.needsDescFile[0] - finally: - self.packageLock.release() - - # Now serve this one package. - if not pp.checkDescFile(): - if not pp.getDescFile(self.appRunner.http): - self.__donePackage(pp, False) - return task.cont - - # This package is now ready to be downloaded. We always add - # it to needsDownload, even if it's already downloaded, to - # guarantee ordering of packages. - - self.packageLock.acquire() - try: - # Also add any packages required by this one. - for packageName, version, host in pp.package.requires: - pp2 = self.PendingPackage(packageName, version, host) - self.__internalAddPackage(pp2) - self.needsDownload.append(pp) - finally: - self.packageLock.release() - - return task.cont - - def __downloadPackageTask(self, task): - - """ This task runs on the aysynchronous task chain; each pass, - it extracts one package from self.needsDownload and downloads - it. """ - - while True: - self.packageLock.acquire() - try: - # If we're done downloading, stop the task. - if self.state == self.S_done or not self.needsDownload: - self.downloadTask = None - self.packageLock.release() - yield task.done; return - - assert self.state == self.S_started - pp = self.needsDownload[0] - del self.needsDownload[0] - except: - self.packageLock.release() - raise - self.packageLock.release() - - # Now serve this one package. - eventName = 'PackageInstaller-%s-packageStarted' % self.uniqueId - messenger.send(eventName, [pp], taskChain = 'default') - - if not pp.package.hasPackage: - for token in pp.package.downloadPackageGenerator(self.appRunner.http): - if token == pp.package.stepContinue: - yield task.cont - else: - break - - if token != pp.package.stepComplete: - pc = PStatCollector(':App:PackageInstaller:donePackage:%s' % (pp.package.packageName)) - pc.start() - self.__donePackage(pp, False) - pc.stop() - yield task.cont - continue - - # Successfully downloaded and installed. - pc = PStatCollector(':App:PackageInstaller:donePackage:%s' % (pp.package.packageName)) - pc.start() - self.__donePackage(pp, True) - pc.stop() - - # Continue the loop without yielding, so we pick up the - # next package within this same frame. - - def __donePackage(self, pp, success): - """ Marks the indicated package as done, either successfully - or otherwise. """ - assert not pp.done - - if success: - pc = PStatCollector(':App:PackageInstaller:install:%s' % (pp.package.packageName)) - pc.start() - pp.package.installPackage(self.appRunner) - pc.stop() - - self.packageLock.acquire() - try: - pp.done = True - pp.success = success - if success: - self.done.append(pp) - else: - self.failed.append(pp) - finally: - self.packageLock.release() - - eventName = 'PackageInstaller-%s-packageDone' % self.uniqueId - messenger.send(eventName, [pp], taskChain = 'default') - - def __progressTask(self, task): - self.callbackLock.acquire() - try: - if not self.calledDownloadStarted: - # We haven't yet officially started the download. - return task.cont - - if self.calledDownloadFinished: - # We've officially ended the download. - self.progressTask = None - return task.done - - downloadEffort = 0 - currentDownloadSize = 0 - for pp in self.packages: - downloadEffort += pp.downloadEffort + pp.prevDownloadedEffort - packageProgress = pp.getProgress() - currentDownloadSize += pp.downloadEffort * packageProgress + pp.prevDownloadedEffort - if pp.calledPackageStarted and not pp.calledPackageFinished: - self.packageProgress(pp.package, packageProgress) - - if not downloadEffort: - progress = 1 - else: - progress = float(currentDownloadSize) / float(downloadEffort) - self.downloadProgress(progress) - - finally: - self.callbackLock.release() - - return task.cont - diff --git a/direct/src/p3d/PackageMerger.py b/direct/src/p3d/PackageMerger.py deleted file mode 100644 index a22d8f5f2d..0000000000 --- a/direct/src/p3d/PackageMerger.py +++ /dev/null @@ -1,306 +0,0 @@ -__all__ = ["PackageMerger", "PackageMergerError"] - -from direct.p3d.FileSpec import FileSpec -from direct.p3d.SeqValue import SeqValue -from direct.directnotify.DirectNotifyGlobal import * -from panda3d.core import * -import shutil -import os - -class PackageMergerError(Exception): - pass - -class PackageMerger: - """ This class will combine two or more separately-built stage - directories, the output of Packager.py or the ppackage tool, into - a single output directory. It assumes that the clocks on all - hosts are in sync, so that the file across all builds with the - most recent timestamp (indicated in the contents.xml file) is - always the most current version of the file. """ - - notify = directNotify.newCategory("PackageMerger") - - class PackageEntry: - """ This corresponds to a entry in the contents.xml - file. """ - - def __init__(self, xpackage, sourceDir): - self.sourceDir = sourceDir - self.loadXml(xpackage) - - def getKey(self): - """ Returns a tuple used for sorting the PackageEntry - objects uniquely per package. """ - return (self.packageName, self.platform, self.version) - - def isNewer(self, other): - return self.descFile.timestamp > other.descFile.timestamp - - def loadXml(self, xpackage): - self.packageName = xpackage.Attribute('name') - self.platform = xpackage.Attribute('platform') - self.version = xpackage.Attribute('version') - solo = xpackage.Attribute('solo') - self.solo = int(solo or '0') - perPlatform = xpackage.Attribute('per_platform') - self.perPlatform = int(perPlatform or '0') - - self.descFile = FileSpec() - self.descFile.loadXml(xpackage) - - self.validatePackageContents() - - self.descFile.quickVerify(packageDir = self.sourceDir, notify = PackageMerger.notify, correctSelf = True) - - self.packageSeq = SeqValue() - self.packageSeq.loadXml(xpackage, 'seq') - self.packageSetVer = SeqValue() - self.packageSetVer.loadXml(xpackage, 'set_ver') - - self.importDescFile = None - ximport = xpackage.FirstChildElement('import') - if ximport: - self.importDescFile = FileSpec() - self.importDescFile.loadXml(ximport) - self.importDescFile.quickVerify(packageDir = self.sourceDir, notify = PackageMerger.notify, correctSelf = True) - - def makeXml(self): - """ Returns a new TiXmlElement. """ - xpackage = TiXmlElement('package') - xpackage.SetAttribute('name', self.packageName) - if self.platform: - xpackage.SetAttribute('platform', self.platform) - if self.version: - xpackage.SetAttribute('version', self.version) - if self.solo: - xpackage.SetAttribute('solo', '1') - if self.perPlatform: - xpackage.SetAttribute('per_platform', '1') - - self.descFile.storeXml(xpackage) - self.packageSeq.storeXml(xpackage, 'seq') - self.packageSetVer.storeXml(xpackage, 'set_ver') - - if self.importDescFile: - ximport = TiXmlElement('import') - self.importDescFile.storeXml(ximport) - xpackage.InsertEndChild(ximport) - - return xpackage - - def validatePackageContents(self): - """ Validates the contents of the package directory itself - against the expected hashes and timestamps. Updates - hashes and timestamps where needed. """ - - if self.solo: - return - - needsChange = False - packageDescFullpath = Filename(self.sourceDir, self.descFile.filename) - packageDir = Filename(packageDescFullpath.getDirname()) - doc = TiXmlDocument(packageDescFullpath.toOsSpecific()) - if not doc.LoadFile(): - message = "Could not read XML file: %s" % (self.descFile.filename) - raise OSError(message) - - xpackage = doc.FirstChildElement('package') - if not xpackage: - message = "No package definition: %s" % (self.descFile.filename) - raise OSError(message) - - xcompressed = xpackage.FirstChildElement('compressed_archive') - if xcompressed: - spec = FileSpec() - spec.loadXml(xcompressed) - if not spec.quickVerify(packageDir = packageDir, notify = PackageMerger.notify, correctSelf = True): - spec.storeXml(xcompressed) - needsChange = True - - xpatch = xpackage.FirstChildElement('patch') - while xpatch: - spec = FileSpec() - spec.loadXml(xpatch) - if not spec.quickVerify(packageDir = packageDir, notify = PackageMerger.notify, correctSelf = True): - spec.storeXml(xpatch) - needsChange = True - - xpatch = xpatch.NextSiblingElement('patch') - - if needsChange: - PackageMerger.notify.info("Rewriting %s" % (self.descFile.filename)) - doc.SaveFile() - self.descFile.quickVerify(packageDir = self.sourceDir, notify = PackageMerger.notify, correctSelf = True) - - # PackageMerger constructor - def __init__(self, installDir): - self.installDir = installDir - self.xhost = None - self.contents = {} - self.maxAge = None - self.contentsSeq = SeqValue() - - # We allow the first one to fail quietly. - self.__readContentsFile(self.installDir, None) - - def __readContentsFile(self, sourceDir, packageNames): - """ Reads the contents.xml file from the indicated sourceDir, - and updates the internal set of packages appropriately. """ - - assert sourceDir != None, "No source directory was specified!" - contentsFilename = Filename(sourceDir, 'contents.xml') - doc = TiXmlDocument(contentsFilename.toOsSpecific()) - if not doc.LoadFile(): - # Couldn't read file. - return False - - xcontents = doc.FirstChildElement('contents') - if xcontents: - maxAge = xcontents.Attribute('max_age') - if maxAge: - maxAge = int(maxAge) - if self.maxAge is None: - self.maxAge = maxAge - else: - self.maxAge = min(self.maxAge, maxAge) - - contentsSeq = SeqValue() - if contentsSeq.loadXml(xcontents): - self.contentsSeq = max(self.contentsSeq, contentsSeq) - - xhost = xcontents.FirstChildElement('host') - if xhost: - self.xhost = xhost.Clone() - - xpackage = xcontents.FirstChildElement('package') - while xpackage: - pe = self.PackageEntry(xpackage, sourceDir) - - # Filter out any packages not listed in - # packageNames (unless packageNames is None, - # in which case don't filter anything). - if packageNames is None or pe.packageName in packageNames: - other = self.contents.get(pe.getKey(), None) - if not other or pe.isNewer(other): - # Store this package in the resulting output. - self.contents[pe.getKey()] = pe - - xpackage = xpackage.NextSiblingElement('package') - - self.contentsDoc = doc - - return True - - def __writeContentsFile(self): - """ Writes the contents.xml file at the end of processing. """ - - filename = Filename(self.installDir, 'contents.xml') - doc = TiXmlDocument(filename.toOsSpecific()) - decl = TiXmlDeclaration("1.0", "utf-8", "") - doc.InsertEndChild(decl) - - xcontents = TiXmlElement('contents') - if self.xhost: - xcontents.InsertEndChild(self.xhost) - - if self.maxAge is not None: - xcontents.SetAttribute('max_age', str(self.maxAge)) - self.contentsSeq.storeXml(xcontents) - - contents = list(self.contents.items()) - contents.sort() - for key, pe in contents: - xpackage = pe.makeXml() - xcontents.InsertEndChild(xpackage) - - doc.InsertEndChild(xcontents) - doc.SaveFile() - - def __copySubdirectory(self, pe): - """ Copies the subdirectory referenced in the indicated - PackageEntry object into the installDir, replacing the - contents of any similarly-named subdirectory already - there. """ - - dirname = Filename(pe.descFile.filename).getDirname() - self.notify.info("copying %s" % (dirname)) - sourceDirname = Filename(pe.sourceDir, dirname) - targetDirname = Filename(self.installDir, dirname) - - self.__rCopyTree(sourceDirname, targetDirname) - - def __rCopyTree(self, sourceFilename, targetFilename): - """ Recursively copies the contents of sourceDirname onto - targetDirname. This behaves like shutil.copytree, but it does - not remove pre-existing subdirectories. """ - - if targetFilename.exists(): - if not targetFilename.isDirectory(): - # Delete any regular files in the way. - targetFilename.unlink() - - elif not sourceFilename.isDirectory(): - # If the source file is a regular file, but the target - # file is a directory, completely remove the target - # file. - shutil.rmtree(targetFilename.toOsSpecific()) - - else: - # Both the source file and target file are - # directories. - - # We have to clean out the target directory first. - # Instead of using shutil.rmtree(), remove the files in - # this directory one at a time, so we don't inadvertently - # clean out subdirectories too. - files = os.listdir(targetFilename.toOsSpecific()) - for file in files: - f = Filename(targetFilename, file) - if f.isRegularFile(): - f.unlink() - - if sourceFilename.isDirectory(): - # Recursively copying a directory. - Filename(targetFilename, '').makeDir() - files = os.listdir(sourceFilename.toOsSpecific()) - for file in files: - self.__rCopyTree(Filename(sourceFilename, file), - Filename(targetFilename, file)) - else: - # Copying a regular file. - sourceFilename.copyTo(targetFilename) - - # Also try to copy the timestamp, but don't fuss too much - # if it doesn't work. - try: - st = os.stat(sourceFilename.toOsSpecific()) - os.utime(targetFilename.toOsSpecific(), (st.st_atime, st.st_mtime)) - except OSError: - pass - - def merge(self, sourceDir, packageNames = None): - """ Adds the contents of the indicated source directory into - the current pool. If packageNames is not None, it is a list - of package names that we wish to include from the source; - packages not named in this list will be unchanged. """ - - if not self.__readContentsFile(sourceDir, packageNames): - message = "Couldn't read %s" % (sourceDir) - raise PackageMergerError(message) - - def close(self): - """ Finalizes the results of all of the previous calls to - merge(), writes the new contents.xml file, and copies in all - of the new contents. """ - - dirname = Filename(self.installDir, '') - dirname.makeDir() - - for pe in self.contents.values(): - if pe.sourceDir != self.installDir: - # Here's a new subdirectory we have to copy in. - self.__copySubdirectory(pe) - - self.contentsSeq += 1 - self.__writeContentsFile() - diff --git a/direct/src/p3d/Packager.py b/direct/src/p3d/Packager.py deleted file mode 100644 index 4e8a303f7f..0000000000 --- a/direct/src/p3d/Packager.py +++ /dev/null @@ -1,3962 +0,0 @@ -""" This module is used to build a "Package", a collection of files -within a Panda3D Multifile, which can be easily be downloaded and/or -patched onto a client machine, for the purpose of running a large -application. """ - -__all__ = ["Packager", "PackagerError", "OutsideOfPackageError", "ArgumentError"] - -# Important to import panda3d first, to avoid naming conflicts with -# Python's "string" and "Loader" names that are imported later. -from panda3d.core import * -import sys -import os -import glob -import struct -import subprocess -import copy -from direct.p3d.FileSpec import FileSpec -from direct.p3d.SeqValue import SeqValue -from direct.p3d.HostInfo import HostInfo -from direct.showbase import Loader -from direct.showbase import AppRunnerGlobal -from direct.dist import FreezeTool -from direct.directnotify.DirectNotifyGlobal import * - -vfs = VirtualFileSystem.getGlobalPtr() - -class PackagerError(Exception): - pass - -class OutsideOfPackageError(PackagerError): - pass - -class ArgumentError(PackagerError): - pass - -class Packager: - notify = directNotify.newCategory("Packager") - - class PackFile: - def __init__(self, package, filename, - newName = None, deleteTemp = False, - explicit = False, compress = None, extract = None, - text = None, unprocessed = None, - executable = None, dependencyDir = None, - platformSpecific = None, required = False): - assert isinstance(filename, Filename) - self.filename = Filename(filename) - self.newName = newName - self.deleteTemp = deleteTemp - self.explicit = explicit - self.compress = compress - self.extract = extract - self.text = text - self.unprocessed = unprocessed - self.executable = executable - self.dependencyDir = dependencyDir - self.platformSpecific = platformSpecific - self.required = required - - if not self.newName: - self.newName = str(self.filename) - - ext = Filename(self.newName).getExtension() - if ext == 'pz' or ext == 'gz': - # Strip off a .pz extension; we can compress files - # within the Multifile without it. - filename = Filename(self.newName) - filename.setExtension('') - self.newName = str(filename) - ext = Filename(self.newName).getExtension() - if self.compress is None: - self.compress = True - - packager = package.packager - if self.compress is None: - self.compress = (ext not in packager.uncompressibleExtensions and ext not in packager.imageExtensions) - - if self.executable is None: - self.executable = (ext in packager.executableExtensions) - - if self.executable and self.dependencyDir is None: - # By default, install executable dependencies in the - # root directory, which is the one that's added to PATH. - self.dependencyDir = '' - - if self.extract is None: - self.extract = self.executable or (ext in packager.extractExtensions) - if self.platformSpecific is None: - self.platformSpecific = self.executable or (ext in packager.platformSpecificExtensions) - - if self.unprocessed is None: - self.unprocessed = self.executable or (ext in packager.unprocessedExtensions) - - if self.executable: - # Look up the filename along the system PATH, if necessary. - if not packager.resolveLibrary(self.filename): - # If it wasn't found, try looking it up under its - # basename only. Sometimes a Mac user will copy - # the library file out of a framework and put that - # along the PATH, instead of the framework itself. - basename = Filename(self.filename.getBasename()) - if packager.resolveLibrary(basename): - self.filename = basename - - if ext in packager.textExtensions and not self.executable: - self.filename.setText() - else: - self.filename.setBinary() - - # Convert the filename to an unambiguous filename for - # searching. - self.filename.makeTrueCase() - if self.filename.exists() or not self.filename.isLocal(): - self.filename.makeCanonical() - - def isExcluded(self, package): - """ Returns true if this file should be excluded or - skipped, false otherwise. """ - - if self.newName.lower() in package.skipFilenames: - return True - - if not self.explicit: - # Make sure it's not one of our auto-excluded system - # files. (But only make this check if this file was - # not explicitly added.) - - basename = Filename(self.newName).getBasename() - if not package.packager.caseSensitive: - basename = basename.lower() - if basename in package.packager.excludeSystemFiles: - return True - for exclude in package.packager.excludeSystemGlobs: - if exclude.matches(basename): - return True - - # Also check if it was explicitly excluded. As above, - # omit this check for an explicitly-added file: if you - # both include and exclude a file, the file is - # included. - for exclude in package.excludedFilenames: - if exclude.matches(self.filename): - return True - - # A platform-specific file is implicitly excluded from - # not-platform-specific packages. - if self.platformSpecific and package.platformSpecificConfig is False: - return True - - return False - - class ExcludeFilename: - def __init__(self, packager, filename, caseSensitive): - self.packager = packager - self.localOnly = (not filename.getDirname()) - if not self.localOnly: - filename = Filename(filename) - filename.makeCanonical() - self.glob = GlobPattern(str(filename)) - - if self.packager.platform.startswith('win'): - self.glob.setCaseSensitive(False) - elif self.packager.platform.startswith('osx'): - self.glob.setCaseSensitive(False) - - def matches(self, filename): - if self.localOnly: - return self.glob.matches(filename.getBasename()) - else: - return self.glob.matches(str(filename)) - - class PackageEntry: - """ This corresponds to a entry in the contents.xml - file. """ - - def __init__(self): - # The "seq" value increments automatically with each publish. - self.packageSeq = SeqValue() - - # The "set_ver" value is optionally specified in the pdef - # file and does not change unless the user says it does. - self.packageSetVer = SeqValue() - - def getKey(self): - """ Returns a tuple used for sorting the PackageEntry - objects uniquely per package. """ - return (self.packageName, self.platform or "", self.version or "") - - def fromFile(self, packageName, platform, version, solo, perPlatform, - installDir, descFilename, importDescFilename): - self.packageName = packageName - self.platform = platform - self.version = version - self.solo = solo - self.perPlatform = perPlatform - - self.descFile = FileSpec() - self.descFile.fromFile(installDir, descFilename) - - self.importDescFile = None - if importDescFilename: - self.importDescFile = FileSpec() - self.importDescFile.fromFile(installDir, importDescFilename) - - def loadXml(self, xpackage): - self.packageName = xpackage.Attribute('name') - self.platform = xpackage.Attribute('platform') - self.version = xpackage.Attribute('version') - solo = xpackage.Attribute('solo') - self.solo = int(solo or '0') - perPlatform = xpackage.Attribute('per_platform') - self.perPlatform = int(perPlatform or '0') - - self.packageSeq = SeqValue() - self.packageSeq.loadXml(xpackage, 'seq') - - self.packageSetVer = SeqValue() - self.packageSetVer.loadXml(xpackage, 'set_ver') - - self.descFile = FileSpec() - self.descFile.loadXml(xpackage) - - self.importDescFile = None - ximport = xpackage.FirstChildElement('import') - if ximport: - self.importDescFile = FileSpec() - self.importDescFile.loadXml(ximport) - - - def makeXml(self): - """ Returns a new TiXmlElement. """ - xpackage = TiXmlElement('package') - xpackage.SetAttribute('name', self.packageName) - if self.platform: - xpackage.SetAttribute('platform', self.platform) - if self.version: - xpackage.SetAttribute('version', self.version) - if self.solo: - xpackage.SetAttribute('solo', '1') - if self.perPlatform: - xpackage.SetAttribute('per_platform', '1') - - self.packageSeq.storeXml(xpackage, 'seq') - self.packageSetVer.storeXml(xpackage, 'set_ver') - self.descFile.storeXml(xpackage) - - if self.importDescFile: - ximport = TiXmlElement('import') - self.importDescFile.storeXml(ximport) - xpackage.InsertEndChild(ximport) - - return xpackage - - class HostEntry: - def __init__(self, url = None, downloadUrl = None, - descriptiveName = None, hostDir = None, - mirrors = None): - self.url = url - self.downloadUrl = downloadUrl - self.descriptiveName = descriptiveName - self.hostDir = hostDir - self.mirrors = mirrors or [] - self.altHosts = {} - - def loadXml(self, xhost, packager): - self.url = xhost.Attribute('url') - self.downloadUrl = xhost.Attribute('download_url') - self.descriptiveName = xhost.Attribute('descriptive_name') - self.hostDir = xhost.Attribute('host_dir') - self.mirrors = [] - xmirror = xhost.FirstChildElement('mirror') - while xmirror: - url = xmirror.Attribute('url') - self.mirrors.append(url) - xmirror = xmirror.NextSiblingElement('mirror') - - xalthost = xhost.FirstChildElement('alt_host') - while xalthost: - url = xalthost.Attribute('url') - he = packager.addHost(url) - he.loadXml(xalthost, packager) - xalthost = xalthost.NextSiblingElement('alt_host') - - def makeXml(self, packager = None): - """ Returns a new TiXmlElement. """ - xhost = TiXmlElement('host') - xhost.SetAttribute('url', self.url) - if self.downloadUrl and self.downloadUrl != self.url: - xhost.SetAttribute('download_url', self.downloadUrl) - if self.descriptiveName: - xhost.SetAttribute('descriptive_name', self.descriptiveName) - if self.hostDir: - xhost.SetAttribute('host_dir', self.hostDir) - - for mirror in self.mirrors: - xmirror = TiXmlElement('mirror') - xmirror.SetAttribute('url', mirror) - xhost.InsertEndChild(xmirror) - - if packager: - altHosts = sorted(self.altHosts.items()) - for keyword, alt in altHosts: - he = packager.hosts.get(alt, None) - if he: - xalthost = he.makeXml() - xalthost.SetValue('alt_host') - xalthost.SetAttribute('keyword', keyword) - xhost.InsertEndChild(xalthost) - - return xhost - - - class Package: - """ This is the full information on a particular package we - are constructing. Don't confuse it with PackageEntry, above, - which contains only the information found in the toplevel - contents.xml file.""" - - def __init__(self, packageName, packager): - self.packageName = packageName - self.packager = packager - self.notify = packager.notify - - # The platform is initially None until we know the file is - # platform-specific. - self.platform = None - - # This is always true on modern packages. - self.perPlatform = True - - # The arch string, though, is pre-loaded from the system - # arch string, so we can sensibly call otool. - self.arch = self.packager.arch - - self.version = None - self.host = None - self.p3dApplication = False - self.solo = False - self.compressionLevel = 0 - self.importedMapsDir = 'imported_maps' - self.mainModule = None - self.signParams = [] - self.requires = [] - - # This may be set explicitly in the pdef file to a - # particular sequence value. - self.packageSetVer = SeqValue() - - # This is the set of config variables assigned to the - # package. - self.configs = {} - - # This is the set of files and modules, already included - # by required packages, that we can skip. - self.skipFilenames = {} - self.skipModules = {} - - # This is a list of ExcludeFilename objects, representing - # the files that have been explicitly excluded. - self.excludedFilenames = [] - - # This is the list of files we will be adding, and a pair - # of cross references. - self.files = [] - self.sourceFilenames = {} - self.targetFilenames = {} - - # This is the set of files and modules that are - # required and may not be excluded from the package. - self.requiredFilenames = [] - self.requiredModules = [] - - # A list of required packages that were missing. - self.missingPackages = [] - - # This records the current list of modules we have added so - # far. - self.freezer = FreezeTool.Freezer(platform = self.packager.platform) - self.freezer.storePythonSource = self.packager.storePythonSource - - # Map of extensions to files to number (ignored by dir) - self.ignoredDirFiles = {} - - def close(self): - """ Writes out the contents of the current package. Returns True - if the package was constructed successfully, False if one or more - required files or modules are missing. """ - - if not self.p3dApplication and not self.packager.allowPackages: - message = 'Cannot generate packages without an installDir; use -i' - raise PackagerError(message) - - if self.ignoredDirFiles: - exts = sorted(self.ignoredDirFiles.keys()) - total = sum([x for x in self.ignoredDirFiles.values()]) - self.notify.warning("excluded %s files not marked for inclusion: %s" \ - % (total, ", ".join(["'" + ext + "'" for ext in exts]))) - - if not self.host: - self.host = self.packager.host - - # Check the version config variable. - version = self.configs.get('version', None) - if version is not None: - self.version = version - del self.configs['version'] - - # Check the platform_specific config variable. This has - # only three settings: None (unset), True, or False. - self.platformSpecificConfig = self.configs.get('platform_specific', None) - if self.platformSpecificConfig is not None: - # First, convert it to an int, in case it's "0" or "1". - try: - self.platformSpecificConfig = int(self.platformSpecificConfig) - except ValueError: - pass - # Then, make it a bool. - self.platformSpecificConfig = bool(self.platformSpecificConfig) - del self.configs['platform_specific'] - - # A special case when building the "panda3d" package. We - # enforce that the version number matches what we've been - # compiled with. - if self.packageName == 'panda3d': - if self.version is None: - self.version = PandaSystem.getPackageVersionString() - - if self.version != PandaSystem.getPackageVersionString(): - message = 'mismatched Panda3D version: requested %s, but Panda3D is built as %s' % (self.version, PandaSystem.getPackageVersionString()) - raise PackagerError(message) - - if self.host != PandaSystem.getPackageHostUrl(): - message = 'mismatched Panda3D host: requested %s, but Panda3D is built as %s' % (self.host, PandaSystem.getPackageHostUrl()) - raise PackagerError(message) - - if self.p3dApplication: - # Default compression level for an app. - self.compressionLevel = 6 - - # Every p3dapp requires panda3d. - if 'panda3d' not in [p.packageName for p in self.requires]: - assert not self.packager.currentPackage - self.packager.currentPackage = self - self.packager.do_require('panda3d') - self.packager.currentPackage = None - - # If this flag is set, enable allow_python_dev. - if self.packager.allowPythonDev: - self.configs['allow_python_dev'] = True - - if not self.p3dApplication and not self.version: - # If we don't have an implicit version, inherit the - # version from the 'panda3d' package on our require - # list. - for p2 in self.requires: - if p2.packageName == 'panda3d' and p2.version: - self.version = p2.version - break - - if self.solo: - result = self.installSolo() - else: - result = self.installMultifile() - - if self.p3dApplication: - allowPythonDev = self.configs.get('allow_python_dev', 0) - if int(allowPythonDev): - print("\n*** Generating %s.p3d with allow_python_dev enabled ***\n" % (self.packageName)) - - return result - - - def considerPlatform(self): - # Check to see if any of the files are platform-specific, - # making the overall package platform-specific. - - platformSpecific = self.platformSpecificConfig - for file in self.files: - if file.isExcluded(self): - # Skip this file. - continue - if file.platformSpecific: - platformSpecific = True - - if platformSpecific and self.platformSpecificConfig is not False: - if not self.platform: - self.platform = self.packager.platform - - if self.platform and self.platform.startswith('osx_'): - # Get the OSX "arch" specification. - self.arch = self.platform[4:] - - - def installMultifile(self): - """ Installs the package, either as a p3d application, or - as a true package. Either is implemented with a - Multifile. """ - - if self.missingPackages: - missing = ', '.join([name for name, version in self.missingPackages]) - self.notify.warning("Cannot build package %s due to missing dependencies: %s" % (self.packageName, missing)) - self.cleanup() - return False - - self.multifile = Multifile() - - # Write the multifile to a temporary filename until we - # know enough to determine the output filename. - multifileFilename = Filename.temporary('', self.packageName + '.', '.mf') - self.multifile.openReadWrite(multifileFilename) - - if self.p3dApplication: - # p3d files should be tagged to make them executable. - self.multifile.setHeaderPrefix('#! /usr/bin/env panda3d\n') - else: - # Package multifiles might be patched, and therefore - # don't want to record an internal timestamp, which - # would make patching less efficient. - self.multifile.setRecordTimestamp(False) - - # Make sure that all required files are present. - missing = [] - for file in self.requiredFilenames: - if file not in self.files or file.isExcluded(self): - missing.append(file.filename.getBasename()) - if len(missing) > 0: - self.notify.warning("Cannot build package %s, missing required files: %r" % (self.packageName, missing)) - self.cleanup() - return False - - self.extracts = [] - self.components = [] - - # Add the explicit py files that were requested by the - # pdef file. These get turned into Python modules. - for file in self.files: - if file.isExcluded(self): - # Skip this file. - continue - if file.unprocessed: - # Unprocessed files get dealt with below. - continue - - ext = Filename(file.newName).getExtension() - if ext == 'dc': - # Add the modules named implicitly in the dc file. - self.addDcImports(file) - - elif ext == 'py': - self.addPyFile(file) - - # Add the main module, if any. - if not self.mainModule and self.p3dApplication: - message = 'No main_module specified for application %s' % (self.packageName) - raise PackagerError(message) - if self.mainModule: - moduleName, newName = self.mainModule - if newName not in self.freezer.modules: - self.freezer.addModule(moduleName, newName = newName) - - # Now all module files have been added. Exclude modules - # already imported in a required package, and not - # explicitly included by this package. - for moduleName, mdef in self.skipModules.items(): - if moduleName not in self.freezer.modules: - self.freezer.excludeModule( - moduleName, allowChildren = mdef.allowChildren, - forbid = mdef.forbid, fromSource = 'skip') - - # Pick up any unfrozen Python files. - self.freezer.done() - - # But first, make sure that all required modules are present. - missing = [] - moduleDict = dict(self.freezer.getModuleDefs()) - for module in self.requiredModules: - if module not in moduleDict: - missing.append(module) - if len(missing) > 0: - self.notify.warning("Cannot build package %s, missing required modules: %r" % (self.packageName, missing)) - self.cleanup() - return False - - # OK, we can add it. - self.freezer.addToMultifile(self.multifile, self.compressionLevel) - self.addExtensionModules() - - # Add known module names. - self.moduleNames = {} - modules = sorted(self.freezer.modules.items()) - for newName, mdef in modules: - if mdef.guess: - # Not really a module. - continue - - if mdef.fromSource == 'skip': - # This record already appeared in a required - # module; don't repeat it now. - continue - - if mdef.exclude and mdef.implicit: - # Don't bother mentioning implicitly-excluded - # (i.e. missing) modules. - continue - - #if newName == '__main__': - # # Ignore this special case. - # continue - - self.moduleNames[newName] = mdef - - xmodule = TiXmlElement('module') - xmodule.SetAttribute('name', newName) - if mdef.exclude: - xmodule.SetAttribute('exclude', '1') - if mdef.forbid: - xmodule.SetAttribute('forbid', '1') - if mdef.exclude and mdef.allowChildren: - xmodule.SetAttribute('allowChildren', '1') - self.components.append(('m', newName.lower(), xmodule)) - - # Now look for implicit shared-library dependencies. - if self.packager.platform.startswith('win'): - self.__addImplicitDependenciesWindows() - elif self.packager.platform.startswith('osx'): - self.__addImplicitDependenciesOSX() - else: - self.__addImplicitDependenciesPosix() - - # Now add all the real, non-Python files (except model - # files). This will include the extension modules we just - # discovered above. - for file in self.files: - if file.isExcluded(self): - # Skip this file. - continue - ext = Filename(file.newName).getExtension() - if file.unprocessed: - # Add an unprocessed file verbatim. - self.addComponent(file) - elif ext == 'py': - # Already handled, above. - pass - elif file.isExcluded(self): - # Skip this file. - pass - elif ext == 'egg' or ext == 'bam': - # Skip model files this pass. - pass - elif ext == 'dc': - # dc files get a special treatment. - self.addDcFile(file) - elif ext == 'prc': - # So do prc files. - self.addPrcFile(file) - else: - # Any other file. - self.addComponent(file) - - # Now add the model files. It's important to add these - # after we have added all of the texture files, so we can - # determine which textures need to be implicitly pulled - # in. - - # We walk through a copy of the files list, since we might - # be adding more files (textures) to this list as we - # discover them in model files referenced in this list. - for file in self.files[:]: - if file.isExcluded(self): - # Skip this file. - continue - ext = Filename(file.newName).getExtension() - if file.unprocessed: - # Already handled, above. - pass - elif ext == 'py': - # Already handled, above. - pass - elif file.isExcluded(self): - # Skip this file. - pass - elif ext == 'egg': - self.addEggFile(file) - elif ext == 'bam': - self.addBamFile(file) - else: - # Handled above. - pass - - # Check to see if we should be platform-specific. - self.considerPlatform() - - # Now that we've processed all of the component files, - # (and set our platform if necessary), we can generate the - # output filename and write the output files. - - self.packageBasename = self.packageName - packageDir = self.packageName - if self.version: - self.packageBasename += '.' + self.version - packageDir += '/' + self.version - if self.platform: - self.packageBasename += '.' + self.platform - packageDir += '/' + self.platform - - self.packageDesc = self.packageBasename + '.xml' - self.packageImportDesc = self.packageBasename + '.import.xml' - if self.p3dApplication: - self.packageBasename += self.packager.p3dSuffix - self.packageBasename += '.p3d' - packageDir = '' - else: - self.packageBasename += '.mf' - packageDir += '/' - - self.packageDir = packageDir - self.packageFilename = packageDir + self.packageBasename - self.packageDesc = packageDir + self.packageDesc - self.packageImportDesc = packageDir + self.packageImportDesc - - print("Generating %s" % (self.packageFilename)) - - if self.p3dApplication: - self.packageFullpath = Filename(self.packager.p3dInstallDir, self.packageFilename) - self.packageFullpath.makeDir() - self.makeP3dInfo() - else: - self.packageFullpath = Filename(self.packager.installDir, self.packageFilename) - self.packageFullpath.makeDir() - - self.multifile.repack() - - # Also sign the multifile before we close it. - for certificate, chain, pkey, password in self.signParams: - self.multifile.addSignature(certificate, chain or '', pkey or '', password or '') - - self.multifile.close() - - if not multifileFilename.renameTo(self.packageFullpath): - self.notify.error("Cannot move %s to %s" % (multifileFilename, self.packageFullpath)) - - if self.p3dApplication: - # No patches for an application; just move it into place. - # Make the application file executable. - os.chmod(self.packageFullpath.toOsSpecific(), 0o755) - else: - self.readDescFile() - self.packageSeq += 1 - self.perPlatform = True # always true on modern packages. - self.compressMultifile() - self.writeDescFile() - self.writeImportDescFile() - - # Now that we've written out the desc file, we don't - # need to keep around the uncompressed archive - # anymore. - self.packageFullpath.unlink() - - # Replace or add the entry in the contents. - pe = Packager.PackageEntry() - pe.fromFile(self.packageName, self.platform, self.version, - False, self.perPlatform, self.packager.installDir, - self.packageDesc, self.packageImportDesc) - pe.packageSeq = self.packageSeq - pe.packageSetVer = self.packageSetVer - - self.packager.contents[pe.getKey()] = pe - self.packager.contentsChanged = True - - self.cleanup() - return True - - def installSolo(self): - """ Installs the package as a "solo", which means we - simply copy the one file into the install directory. This - is primarily intended for the "coreapi" plugin, which is - just a single dll and a jpg file; but it can support other - kinds of similar "solo" packages as well. """ - - self.considerPlatform() - self.perPlatform = False # Not true on "solo" packages. - - packageDir = self.packageName - if self.platform: - packageDir += '/' + self.platform - if self.version: - packageDir += '/' + self.version - - if not self.packager.allowPackages: - message = 'Cannot generate packages without an installDir; use -i' - raise PackagerError(message) - - installPath = Filename(self.packager.installDir, packageDir) - # Remove any files already in the installPath. - origFiles = vfs.scanDirectory(installPath) - if origFiles: - for origFile in origFiles: - origFile.getFilename().unlink() - - files = [] - for file in self.files: - if file.isExcluded(self): - # Skip this file. - continue - files.append(file) - - if not files: - # No files, never mind. - return - - if len(files) != 1: - raise PackagerError('Multiple files in "solo" package %s' % (self.packageName)) - - Filename(installPath, '').makeDir() - - file = files[0] - targetPath = Filename(installPath, file.newName) - targetPath.setBinary() - file.filename.setBinary() - if not file.filename.copyTo(targetPath): - self.notify.warning("Could not copy %s to %s" % ( - file.filename, targetPath)) - - # Replace or add the entry in the contents. - pe = Packager.PackageEntry() - pe.fromFile(self.packageName, self.platform, self.version, - True, self.perPlatform, self.packager.installDir, - Filename(packageDir, file.newName), None) - peOrig = self.packager.contents.get(pe.getKey(), None) - if peOrig: - pe.packageSeq = peOrig.packageSeq + 1 - pe.packageSetVer = peOrig.packageSetVer - if self.packageSetVer: - pe.packageSetVer = self.packageSetVer - - self.packager.contents[pe.getKey()] = pe - self.packager.contentsChanged = True - - # Hack for coreapi package, to preserve backward compatibility - # with old versions of the runtime, which still called the - # 32-bit Windows platform "win32". - if self.packageName == "coreapi" and self.platform == "win_i386": - pe2 = copy.copy(pe) - pe2.platform = "win32" - self.packager.contents[pe2.getKey()] = pe2 - - self.cleanup() - return True - - def cleanup(self): - # Now that all the files have been packed, we can delete - # the temporary files. - for file in self.files: - if file.deleteTemp: - file.filename.unlink() - - def addFile(self, *args, **kw): - """ Adds the named file to the package. Returns the file - object, or None if it was not added by this call. """ - - file = Packager.PackFile(self, *args, **kw) - if file.filename in self.sourceFilenames: - # Don't bother, it's already here. - return None - - lowerName = file.newName.lower() - if lowerName in self.targetFilenames: - # Another file is already in the same place. - file2 = self.targetFilenames[lowerName] - self.packager.notify.warning( - "%s is shadowing %s" % (file2.filename, file.filename)) - return None - - self.sourceFilenames[file.filename] = file - if file.required: - self.requiredFilenames.append(file) - - if file.text is None and not file.filename.exists(): - if not file.isExcluded(self): - self.packager.notify.warning("No such file: %s" % (file.filename)) - return None - - self.files.append(file) - self.targetFilenames[lowerName] = file - - return file - - def excludeFile(self, filename): - """ Excludes the named file (or glob pattern) from the - package. """ - xfile = Packager.ExcludeFilename(self.packager, filename, self.packager.caseSensitive) - self.excludedFilenames.append(xfile) - - def __addImplicitDependenciesWindows(self): - """ Walks through the list of files, looking for dll's and - exe's that might include implicit dependencies on other - dll's and assembly manifests. Tries to determine those - dependencies, and adds them back into the filelist. """ - - # We walk through the list as we modify it. That's OK, - # because we want to follow the transitive closure of - # dependencies anyway. - for file in self.files: - if not file.executable: - continue - - if file.isExcluded(self): - # Skip this file. - continue - - if file.filename.getExtension().lower() == "manifest": - filenames = self.__parseManifest(file.filename) - if filenames is None: - self.notify.warning("Unable to determine dependent assemblies from %s" % (file.filename)) - continue - - else: - tempFile = Filename.temporary('', 'p3d_', '.txt') - command = 'dumpbin /dependents "%s" >"%s"' % ( - file.filename.toOsSpecific(), - tempFile.toOsSpecific()) - try: - os.system(command) - except: - pass - filenames = None - - if tempFile.exists(): - filenames = self.__parseDependenciesWindows(tempFile) - tempFile.unlink() - if filenames is None: - self.notify.warning("Unable to determine dependencies from %s" % (file.filename)) - filenames = [] - - # Extract the manifest file so we can figure out - # the dependent assemblies. - tempFile = Filename.temporary('', 'p3d_', '.manifest') - resindex = 2 - if file.filename.getExtension().lower() == "exe": - resindex = 1 - command = 'mt -inputresource:"%s";#%d -out:"%s" > nul' % ( - file.filename.toOsSpecific(), - resindex, tempFile.toOsSpecific()) - try: - out = os.system(command) - except: - pass - afilenames = None - - if tempFile.exists(): - afilenames = self.__parseManifest(tempFile) - tempFile.unlink() - - # Also check for an explicit private-assembly - # manifest file on disk. - mfile = file.filename + '.manifest' - if mfile.exists(): - if afilenames is None: - afilenames = [] - afilenames += self.__parseManifest(mfile) - # Since it's an explicit manifest file, it - # means we should include the manifest - # file itself in the package. - newName = Filename(file.dependencyDir, mfile.getBasename()) - self.addFile(mfile, newName = str(newName), - explicit = False, executable = True) - - if afilenames is None and out != 31: - self.notify.warning("Unable to determine dependent assemblies from %s" % (file.filename)) - - if afilenames is not None: - filenames += afilenames - - # Attempt to resolve the dependent filename relative - # to the original filename, before we resolve it along - # the PATH. - path = DSearchPath(Filename(file.filename.getDirname())) - - for filename in filenames: - filename = Filename.fromOsSpecific(filename) - filename.resolveFilename(path) - filename.makeTrueCase() - - newName = Filename(file.dependencyDir, filename.getBasename()) - self.addFile(filename, newName = str(newName), - explicit = False, executable = True) - - def __parseDependenciesWindows(self, tempFile): - """ Reads the indicated temporary file, the output from - dumpbin /dependents, to determine the list of dll's this - executable file depends on. """ - - lines = open(tempFile.toOsSpecific(), 'rU').readlines() - li = 0 - while li < len(lines): - line = lines[li] - li += 1 - if line.find(' has the following dependencies') != -1: - break - - if li < len(lines): - line = lines[li] - if line.strip() == '': - # Skip a blank line. - li += 1 - - # Now we're finding filenames, until the next blank line. - filenames = [] - while li < len(lines): - line = lines[li] - li += 1 - line = line.strip() - if line == '': - # We're done. - return filenames - filenames.append(line) - - # Hmm, we ran out of data. Oh well. - if not filenames: - # Some parse error. - return None - - # At least we got some data. - return filenames - - def __parseManifest(self, tempFile): - """ Reads the indicated application manifest file, to - determine the list of dependent assemblies this - executable file depends on. """ - - doc = TiXmlDocument(tempFile.toOsSpecific()) - if not doc.LoadFile(): - return None - - assembly = doc.FirstChildElement("assembly") - if not assembly: - return None - - # Pick up assemblies that it depends on - filenames = [] - dependency = assembly.FirstChildElement("dependency") - while dependency: - depassembly = dependency.FirstChildElement("dependentAssembly") - if depassembly: - ident = depassembly.FirstChildElement("assemblyIdentity") - if ident: - name = ident.Attribute("name") - if name: - filenames.append(name + ".manifest") - - dependency = dependency.NextSiblingElement("dependency") - - # Pick up direct dll dependencies that it lists - dfile = assembly.FirstChildElement("file") - while dfile: - name = dfile.Attribute("name") - if name: - filenames.append(name) - dfile = dfile.NextSiblingElement("file") - - return filenames - - def __locateFrameworkLibrary(self, library): - """ Locates the given library inside its framework on the - default framework paths, and returns its location as Filename. """ - - # If it's already a full existing path, we - # don't search for it anymore, of course. - if Filename.fromOsSpecific(library).exists(): - return Filename.fromOsSpecific(library) - - # DSearchPath appears not to work for directories. - fpath = [] - fpath.append(Filename("/Library/Frameworks")) - fpath.append(Filename("/System/Library/Frameworks")) - fpath.append(Filename("/Developer/Library/Frameworks")) - fpath.append(Filename(os.path.expanduser("~"), "Library/Frameworks")) - if "HOME" in os.environ: - fpath.append(Filename(os.environ["HOME"], "Library/Frameworks")) - ffilename = Filename(library.split('.framework/', 1)[0].split('/')[-1] + '.framework') - ffilename = Filename(ffilename, library.split('.framework/', 1)[-1]) - - # Look under the system root first, if supplied. - if self.packager.systemRoot: - for i in fpath: - fw = Filename(self.packager.systemRoot, i) - if Filename(fw, ffilename).exists(): - return Filename(fw, ffilename) - - for i in fpath: - if Filename(i, ffilename).exists(): - return Filename(i, ffilename) - - # Not found? Well, let's just return the framework + file - # path, the user will be presented with a warning later. - return ffilename - - def __alterFrameworkDependencies(self, file, framework_deps): - """ Copies the given library file to a temporary directory, - and alters the dependencies so that it doesn't contain absolute - framework dependencies. """ - - if not file.deleteTemp: - # Copy the file to a temporary location because we - # don't want to modify the original (there's a big - # chance that we break it). - - # Copy it every time, because the source file might - # have changed since last time we ran. - assert file.filename.exists(), "File doesn't exist: %s" % file.filename - tmpfile = Filename.temporary('', "p3d_" + file.filename.getBasename()) - tmpfile.setBinary() - file.filename.copyTo(tmpfile) - file.filename = tmpfile - file.deleteTemp = True - - # Alter the dependencies to have a relative path rather than absolute - for filename in framework_deps: - loc = self.__locateFrameworkLibrary(filename) - - if loc == file.filename: - os.system('install_name_tool -id "%s" "%s"' % (os.path.basename(filename), file.filename.toOsSpecific())) - elif "/System/" in loc.toOsSpecific(): - # Let's keep references to system frameworks absolute - os.system('install_name_tool -change "%s" "%s" "%s"' % (filename, loc.toOsSpecific(), file.filename.toOsSpecific())) - else: - os.system('install_name_tool -change "%s" "%s" "%s"' % (filename, os.path.basename(filename), file.filename.toOsSpecific())) - - def __addImplicitDependenciesOSX(self): - """ Walks through the list of files, looking for dylib's - and executables that might include implicit dependencies - on other dylib's. Tries to determine those dependencies, - and adds them back into the filelist. """ - - # We walk through the list as we modify it. That's OK, - # because we want to follow the transitive closure of - # dependencies anyway. - for file in self.files: - if not file.executable: - continue - - if file.isExcluded(self): - # Skip this file. - continue - - origFilename = Filename(file.filename) - - tempFile = Filename.temporary('', 'p3d_', '.txt') - command = '/usr/bin/otool -arch all -L "%s" >"%s"' % ( - origFilename.toOsSpecific(), - tempFile.toOsSpecific()) - if self.arch: - arch = self.arch - if arch == "amd64": - arch = "x86_64" - command = '/usr/bin/otool -arch %s -L "%s" >"%s"' % ( - arch, - origFilename.toOsSpecific(), - tempFile.toOsSpecific()) - exitStatus = os.system(command) - if exitStatus != 0: - self.notify.warning('Command failed: %s' % (command)) - filenames = None - - if tempFile.exists(): - filenames = self.__parseDependenciesOSX(tempFile) - tempFile.unlink() - if filenames is None: - self.notify.warning("Unable to determine dependencies from %s" % (origFilename)) - continue - - # Attempt to resolve the dependent filename relative - # to the original filename, before we resolve it along - # the PATH. - path = DSearchPath(Filename(origFilename.getDirname())) - - # Find the dependencies that are referencing a framework - framework_deps = [] - for filename in filenames: - if '.framework/' in filename: - framework_deps.append(filename) - - if len(framework_deps) > 0: - # Fixes dependencies like @executable_path/../Library/Frameworks/Cg.framework/Cg - self.__alterFrameworkDependencies(file, framework_deps) - - for filename in filenames: - if '@loader_path' in filename: - filename = filename.replace('@loader_path', origFilename.getDirname()) - - if False and '.framework/' in filename: - # It references a framework, and besides the fact - # that those often contain absolute paths, they - # aren't commonly on the library path either. - filename = self.__locateFrameworkLibrary(filename) - filename.setBinary() - else: - # It's just a normal library - find it on the path. - filename = Filename.fromOsSpecific(filename) - filename.setBinary() - - if filename.isLocal(): - filename.resolveFilename(path) - else: - # It's a fully-specified filename; look - # for it under the system root first. - if self.packager.systemRoot: - f2 = Filename(self.packager.systemRoot, filename) - if f2.exists(): - filename = f2 - - # Skip libraries and frameworks in system directory - if "/System/" in filename.toOsSpecific(): - continue - - newName = Filename(file.dependencyDir, filename.getBasename()) - self.addFile(filename, newName = str(newName), - explicit = False, executable = True) - - def __parseDependenciesOSX(self, tempFile): - """ Reads the indicated temporary file, the output from - otool -L, to determine the list of dylibs this - executable file depends on. """ - - lines = open(tempFile.toOsSpecific(), 'rU').readlines() - - filenames = [] - for line in lines: - if not line[0].isspace(): - continue - line = line.strip() - s = line.find(' (compatibility') - if s != -1: - line = line[:s] - else: - s = line.find('.dylib') - if s != -1: - line = line[:s + 6] - else: - continue - filenames.append(line) - - return filenames - - def __readAndStripELF(self, file): - """ Reads the indicated ELF binary, and returns a list with - dependencies. If it contains data that should be stripped, - it writes the stripped library to a temporary file. Returns - None if the file failed to read (e.g. not an ELF file). """ - - # Read the first 16 bytes, which identify the ELF file. - elf = open(file.filename.toOsSpecific(), 'rb') - try: - ident = elf.read(16) - except IOError: - elf.close() - return None - - if not ident.startswith(b"\177ELF"): - # No elf magic! Beware of orcs. - return None - - # Make sure we read in the correct endianness and integer size - byteOrder = "<>"[ord(ident[5:6]) - 1] - elfClass = ord(ident[4:5]) - 1 # 0 = 32-bits, 1 = 64-bits - headerStruct = byteOrder + ("HHIIIIIHHHHHH", "HHIQQQIHHHHHH")[elfClass] - sectionStruct = byteOrder + ("4xI8xIII8xI", "4xI16xQQI12xQ")[elfClass] - dynamicStruct = byteOrder + ("iI", "qQ")[elfClass] - - type, machine, version, entry, phoff, shoff, flags, ehsize, phentsize, phnum, shentsize, shnum, shstrndx \ - = struct.unpack(headerStruct, elf.read(struct.calcsize(headerStruct))) - dynamicSections = [] - stringTables = {} - - # Seek to the section header table and find the .dynamic section. - elf.seek(shoff) - for i in range(shnum): - type, offset, size, link, entsize = struct.unpack_from(sectionStruct, elf.read(shentsize)) - if type == 6 and link != 0: # DYNAMIC type, links to string table - dynamicSections.append((offset, size, link, entsize)) - stringTables[link] = None - - # Read the relevant string tables. - for idx in stringTables.keys(): - elf.seek(shoff + idx * shentsize) - type, offset, size, link, entsize = struct.unpack_from(sectionStruct, elf.read(shentsize)) - if type != 3: continue - elf.seek(offset) - stringTables[idx] = elf.read(size) - - # Loop through the dynamic sections and rewrite it if it has an rpath/runpath. - rewriteSections = [] - filenames = [] - rpath = [] - for offset, size, link, entsize in dynamicSections: - elf.seek(offset) - data = elf.read(entsize) - tag, val = struct.unpack_from(dynamicStruct, data) - newSectionData = b"" - startReplace = None - pad = 0 - - # Read tags until we find a NULL tag. - while tag != 0: - if tag == 1: # A NEEDED entry. Read it from the string table. - filenames.append(stringTables[link][val : stringTables[link].find(b'\0', val)]) - - elif tag == 15 or tag == 29: - rpath += stringTables[link][val : stringTables[link].find(b'\0', val)].split(b':') - # An RPATH or RUNPATH entry. - if not startReplace: - startReplace = elf.tell() - entsize - if startReplace: - pad += entsize - - elif startReplace is not None: - newSectionData += data - - data = elf.read(entsize) - tag, val = struct.unpack_from(dynamicStruct, data) - - if startReplace is not None: - newSectionData += data + (b"\0" * pad) - rewriteSections.append((startReplace, newSectionData)) - elf.close() - - # No rpaths/runpaths found, so nothing to do any more. - if len(rewriteSections) == 0: - return filenames - - # Attempt to resolve any of the directly - # dependent filenames along the RPATH. - for f in range(len(filenames)): - filename = filenames[f] - for rdir in rpath: - if os.path.isfile(os.path.join(rdir, filename)): - filenames[f] = os.path.join(rdir, filename) - break - - if not file.deleteTemp: - # Copy the file to a temporary location because we - # don't want to modify the original (there's a big - # chance that we break it). - - tmpfile = Filename.temporary('', "p3d_" + file.filename.getBasename()) - tmpfile.setBinary() - file.filename.copyTo(tmpfile) - file.filename = tmpfile - file.deleteTemp = True - - # Open the temporary file and rewrite the dynamic sections. - elf = open(file.filename.toOsSpecific(), 'r+b') - for offset, data in rewriteSections: - elf.seek(offset) - elf.write(data) - elf.write(b"\0" * pad) - elf.close() - return filenames - - def __addImplicitDependenciesPosix(self): - """ Walks through the list of files, looking for so's - and executables that might include implicit dependencies - on other so's. Tries to determine those dependencies, - and adds them back into the filelist. """ - - # We walk through the list as we modify it. That's OK, - # because we want to follow the transitive closure of - # dependencies anyway. - for file in self.files: - if not file.executable: - continue - - if file.isExcluded(self): - # Skip this file. - continue - - # Check if this is an ELF binary. - filenames = self.__readAndStripELF(file) - - # If that failed, perhaps ldd will help us. - if filenames is None: - self.notify.warning("Reading ELF library %s failed, using ldd instead" % (file.filename)) - tempFile = Filename.temporary('', 'p3d_', '.txt') - command = 'ldd "%s" >"%s"' % ( - file.filename.toOsSpecific(), - tempFile.toOsSpecific()) - try: - os.system(command) - except: - pass - - if tempFile.exists(): - filenames = self.__parseDependenciesPosix(tempFile) - tempFile.unlink() - - if filenames is None: - self.notify.warning("Unable to determine dependencies from %s" % (file.filename)) - continue - - # Attempt to resolve the dependent filename relative - # to the original filename, before we resolve it along - # the PATH. - path = DSearchPath(Filename(file.filename.getDirname())) - - for filename in filenames: - # These vDSO's provided by Linux aren't - # supposed to be anywhere on the system. - if filename in ["linux-gate.so.1", "linux-vdso.so.1"]: - continue - - filename = Filename.fromOsSpecific(filename) - filename.resolveFilename(path) - filename.setBinary() - - newName = Filename(file.dependencyDir, filename.getBasename()) - self.addFile(filename, newName = str(newName), - explicit = False, executable = True) - - def __parseDependenciesPosix(self, tempFile): - """ Reads the indicated temporary file, the output from - ldd, to determine the list of so's this executable file - depends on. """ - - lines = open(tempFile.toOsSpecific(), 'rU').readlines() - - filenames = [] - for line in lines: - line = line.strip() - s = line.find(' => ') - if s == -1: - continue - - line = line[:s].strip() - filenames.append(line) - - return filenames - - def addExtensionModules(self): - """ Adds the extension modules detected by the freezer to - the current list of files. """ - - freezer = self.freezer - for moduleName, filename in freezer.extras: - filename = Filename.fromOsSpecific(filename) - newName = filename.getBasename() - if '.' in moduleName: - newName = '/'.join(moduleName.split('.')[:-1]) - newName += '/' + filename.getBasename() - # Sometimes the PYTHONPATH has the wrong case in it. - filename.makeTrueCase() - self.addFile(filename, newName = newName, - explicit = False, extract = True, - executable = True, - platformSpecific = True) - freezer.extras = [] - - - def makeP3dInfo(self): - """ Makes the p3d_info.xml file that defines the - application startup parameters and such. """ - - doc = TiXmlDocument() - decl = TiXmlDeclaration("1.0", "utf-8", "") - doc.InsertEndChild(decl) - - xpackage = TiXmlElement('package') - xpackage.SetAttribute('name', self.packageName) - if self.platform: - xpackage.SetAttribute('platform', self.platform) - if self.version: - xpackage.SetAttribute('version', self.version) - - xpackage.SetAttribute('main_module', self.mainModule[1]) - - self.__addConfigs(xpackage) - - requireHosts = {} - for package in self.requires: - xrequires = TiXmlElement('requires') - xrequires.SetAttribute('name', package.packageName) - if package.version: - xrequires.SetAttribute('version', package.version) - xrequires.SetAttribute('host', package.host) - package.packageSeq.storeXml(xrequires, 'seq') - package.packageSetVer.storeXml(xrequires, 'set_ver') - requireHosts[package.host] = True - xpackage.InsertEndChild(xrequires) - - for host in requireHosts.keys(): - he = self.packager.hosts.get(host, None) - if he: - xhost = he.makeXml(packager = self.packager) - xpackage.InsertEndChild(xhost) - - self.extracts.sort() - for name, xextract in self.extracts: - xpackage.InsertEndChild(xextract) - - doc.InsertEndChild(xpackage) - - # Write the xml file to a temporary file on disk, so we - # can add it to the multifile. - filename = Filename.temporary('', 'p3d_', '.xml') - - # This should really be setText() for an xml file, but it - # doesn't really matter that much since tinyxml can read - # it either way; and if we use setBinary() it will remain - # compatible with older versions of the core API that - # didn't understand the SF_text flag. - filename.setBinary() - - doc.SaveFile(filename.toOsSpecific()) - - # It's important not to compress this file: the core API - # runtime can't decode compressed subfiles. - self.multifile.addSubfile('p3d_info.xml', filename, 0) - - self.multifile.flush() - filename.unlink() - - - def compressMultifile(self): - """ Compresses the .mf file into an .mf.pz file. """ - - if self.oldCompressedBasename: - # Remove the previous compressed file first. - compressedPath = Filename(self.packager.installDir, Filename(self.packageDir, self.oldCompressedBasename)) - compressedPath.unlink() - - newCompressedFilename = '%s.pz' % (self.packageFilename) - - # Now build the new version. - compressedPath = Filename(self.packager.installDir, newCompressedFilename) - if not compressFile(self.packageFullpath, compressedPath, 6): - message = 'Unable to write %s' % (compressedPath) - raise PackagerError(message) - - def readDescFile(self): - """ Reads the existing package.xml file before rewriting - it. We need this to preserve the list of patches, and - similar historic data, between sessions. """ - - self.packageSeq = SeqValue() - self.packageSetVer = SeqValue() - self.patchVersion = None - self.patches = [] - - self.oldCompressedBasename = None - - packageDescFullpath = Filename(self.packager.installDir, self.packageDesc) - doc = TiXmlDocument(packageDescFullpath.toOsSpecific()) - if not doc.LoadFile(): - return - - xpackage = doc.FirstChildElement('package') - if not xpackage: - return - - perPlatform = xpackage.Attribute('per_platform') - self.perPlatform = int(perPlatform or '0') - - self.packageSeq.loadXml(xpackage, 'seq') - self.packageSetVer.loadXml(xpackage, 'set_ver') - - xcompressed = xpackage.FirstChildElement('compressed_archive') - if xcompressed: - compressedFilename = xcompressed.Attribute('filename') - if compressedFilename: - self.oldCompressedBasename = compressedFilename - - patchVersion = xpackage.Attribute('patch_version') - if not patchVersion: - patchVersion = xpackage.Attribute('last_patch_version') - if patchVersion: - self.patchVersion = patchVersion - - # Extract the base_version, top_version, and patch - # entries, if any, and preserve these entries verbatim for - # the next version. - xbase = xpackage.FirstChildElement('base_version') - if xbase: - self.patches.append(xbase.Clone()) - xtop = xpackage.FirstChildElement('top_version') - if xtop: - self.patches.append(xtop.Clone()) - - xpatch = xpackage.FirstChildElement('patch') - while xpatch: - self.patches.append(xpatch.Clone()) - xpatch = xpatch.NextSiblingElement('patch') - - def writeDescFile(self): - """ Makes the package.xml file that describes the package - and its contents, for download. """ - - packageDescFullpath = Filename(self.packager.installDir, self.packageDesc) - doc = TiXmlDocument(packageDescFullpath.toOsSpecific()) - decl = TiXmlDeclaration("1.0", "utf-8", "") - doc.InsertEndChild(decl) - - xpackage = TiXmlElement('package') - xpackage.SetAttribute('name', self.packageName) - if self.platform: - xpackage.SetAttribute('platform', self.platform) - if self.version: - xpackage.SetAttribute('version', self.version) - if self.perPlatform: - xpackage.SetAttribute('per_platform', '1') - - if self.patchVersion: - xpackage.SetAttribute('last_patch_version', self.patchVersion) - - self.packageSeq.storeXml(xpackage, 'seq') - self.packageSetVer.storeXml(xpackage, 'set_ver') - - self.__addConfigs(xpackage) - - for package in self.requires: - xrequires = TiXmlElement('requires') - xrequires.SetAttribute('name', package.packageName) - if self.platform and package.platform: - xrequires.SetAttribute('platform', package.platform) - if package.version: - xrequires.SetAttribute('version', package.version) - package.packageSeq.storeXml(xrequires, 'seq') - package.packageSetVer.storeXml(xrequires, 'set_ver') - xrequires.SetAttribute('host', package.host) - xpackage.InsertEndChild(xrequires) - - xuncompressedArchive = self.getFileSpec( - 'uncompressed_archive', self.packageFullpath, - self.packageBasename) - xpackage.InsertEndChild(xuncompressedArchive) - - xcompressedArchive = self.getFileSpec( - 'compressed_archive', self.packageFullpath + '.pz', - self.packageBasename + '.pz') - xpackage.InsertEndChild(xcompressedArchive) - - # Copy in the patch entries read from the previous version - # of the desc file. - for xpatch in self.patches: - xpackage.InsertEndChild(xpatch) - - self.extracts.sort() - for name, xextract in self.extracts: - xpackage.InsertEndChild(xextract) - - doc.InsertEndChild(xpackage) - doc.SaveFile() - - def __addConfigs(self, xpackage): - """ Adds the XML config values defined in self.configs to - the indicated XML element. """ - - if self.configs: - xconfig = TiXmlElement('config') - - for variable, value in self.configs.items(): - if sys.version_info < (3, 0) and isinstance(value, unicode): - xconfig.SetAttribute(variable, value.encode('utf-8')) - elif isinstance(value, bool): - # True or False must be encoded as 1 or 0. - xconfig.SetAttribute(variable, str(int(value))) - else: - xconfig.SetAttribute(variable, str(value)) - - xpackage.InsertEndChild(xconfig) - - def writeImportDescFile(self): - """ Makes the package.import.xml file that describes the - package and its contents, for other packages and - applications that may wish to "require" this one. """ - - packageImportDescFullpath = Filename(self.packager.installDir, self.packageImportDesc) - doc = TiXmlDocument(packageImportDescFullpath.toOsSpecific()) - decl = TiXmlDeclaration("1.0", "utf-8", "") - doc.InsertEndChild(decl) - - xpackage = TiXmlElement('package') - xpackage.SetAttribute('name', self.packageName) - if self.platform: - xpackage.SetAttribute('platform', self.platform) - if self.version: - xpackage.SetAttribute('version', self.version) - xpackage.SetAttribute('host', self.host) - - self.packageSeq.storeXml(xpackage, 'seq') - self.packageSetVer.storeXml(xpackage, 'set_ver') - - requireHosts = {} - requireHosts[self.host] = True - - for package in self.requires: - xrequires = TiXmlElement('requires') - xrequires.SetAttribute('name', package.packageName) - if self.platform and package.platform: - xrequires.SetAttribute('platform', package.platform) - if package.version: - xrequires.SetAttribute('version', package.version) - xrequires.SetAttribute('host', package.host) - package.packageSeq.storeXml(xrequires, 'seq') - package.packageSetVer.storeXml(xrequires, 'set_ver') - requireHosts[package.host] = True - xpackage.InsertEndChild(xrequires) - - # Make sure we also write the full host descriptions for - # any hosts we reference, so we can find these guys later. - for host in requireHosts.keys(): - he = self.packager.hosts.get(host, None) - if he: - xhost = he.makeXml(packager = self.packager) - xpackage.InsertEndChild(xhost) - - self.components.sort() - for type, name, xcomponent in self.components: - xpackage.InsertEndChild(xcomponent) - - doc.InsertEndChild(xpackage) - doc.SaveFile() - - def readImportDescFile(self, filename): - """ Reads the import desc file. Returns True on success, - False on failure. """ - - self.packageSeq = SeqValue() - self.packageSetVer = SeqValue() - - doc = TiXmlDocument(filename.toOsSpecific()) - if not doc.LoadFile(): - return False - xpackage = doc.FirstChildElement('package') - if not xpackage: - return False - - self.packageName = xpackage.Attribute('name') - self.platform = xpackage.Attribute('platform') - self.version = xpackage.Attribute('version') - self.host = xpackage.Attribute('host') - - # Get any new host descriptors. - xhost = xpackage.FirstChildElement('host') - while xhost: - he = self.packager.HostEntry() - he.loadXml(xhost, self) - if he.url not in self.packager.hosts: - self.packager.hosts[he.url] = he - xhost = xhost.NextSiblingElement('host') - - self.packageSeq.loadXml(xpackage, 'seq') - self.packageSetVer.loadXml(xpackage, 'set_ver') - - self.requires = [] - xrequires = xpackage.FirstChildElement('requires') - while xrequires: - packageName = xrequires.Attribute('name') - platform = xrequires.Attribute('platform') - version = xrequires.Attribute('version') - host = xrequires.Attribute('host') - if packageName: - package = self.packager.findPackage( - packageName, platform = platform, version = version, - host = host, requires = self.requires) - if package: - self.requires.append(package) - xrequires = xrequires.NextSiblingElement('requires') - - self.targetFilenames = {} - xcomponent = xpackage.FirstChildElement('component') - while xcomponent: - name = xcomponent.Attribute('filename') - if name: - self.targetFilenames[name.lower()] = True - xcomponent = xcomponent.NextSiblingElement('component') - - self.moduleNames = {} - xmodule = xpackage.FirstChildElement('module') - while xmodule: - moduleName = xmodule.Attribute('name') - exclude = int(xmodule.Attribute('exclude') or 0) - forbid = int(xmodule.Attribute('forbid') or 0) - allowChildren = int(xmodule.Attribute('allowChildren') or 0) - - if moduleName: - mdef = FreezeTool.Freezer.ModuleDef( - moduleName, exclude = exclude, forbid = forbid, - allowChildren = allowChildren) - self.moduleNames[moduleName] = mdef - xmodule = xmodule.NextSiblingElement('module') - - return True - - def getFileSpec(self, element, pathname, newName): - """ Returns an xcomponent or similar element with the file - information for the indicated file. """ - - xspec = TiXmlElement(element) - - size = pathname.getFileSize() - timestamp = pathname.getTimestamp() - - hv = HashVal() - hv.hashFile(pathname) - hash = hv.asHex() - - xspec.SetAttribute('filename', newName) - xspec.SetAttribute('size', str(size)) - xspec.SetAttribute('timestamp', str(timestamp)) - xspec.SetAttribute('hash', hash) - - return xspec - - def addPyFile(self, file): - """ Adds the indicated python file, identified by filename - instead of by module name, to the package. """ - - # Convert the raw filename back to a module name, so we - # can see if we've already loaded this file. We assume - # that all Python files within the package will be rooted - # at the top of the package. - - filename = file.newName.rsplit('.', 1)[0] - moduleName = filename.replace("/", ".") - if moduleName.endswith('.__init__'): - moduleName = moduleName.rsplit('.', 1)[0] - - if moduleName in self.freezer.modules: - # This Python file is already known. We don't have to - # deal with it again. - return - - # Make sure that it is actually in a package. - parentName = moduleName - while '.' in parentName: - parentName = parentName.rsplit('.', 1)[0] - if parentName not in self.freezer.modules: - message = 'Cannot add Python file %s; not in package' % (file.newName) - if file.required or file.explicit: - raise Exception(message) - else: - self.notify.warning(message) - return - - if file.text: - self.freezer.addModule(moduleName, filename = file.filename, text = file.text) - else: - self.freezer.addModule(moduleName, filename = file.filename) - - def addEggFile(self, file): - # Precompile egg files to bam's. - np = self.packager.loader.loadModel(file.filename, self.packager.loaderOptions) - if not np: - raise Exception('Could not read egg file %s' % (file.filename)) - - bamName = Filename(file.newName) - bamName.setExtension('bam') - self.addNode(np.node(), file.filename, str(bamName)) - - def addBamFile(self, file): - # Load the bam file so we can massage its textures. - bamFile = BamFile() - if not bamFile.openRead(file.filename): - raise Exception('Could not read bam file %s' % (file.filename)) - - bamFile.getReader().setLoaderOptions(self.packager.loaderOptions) - - if not bamFile.resolve(): - raise Exception('Could not resolve bam file %s' % (file.filename)) - - node = bamFile.readNode() - if not node: - raise Exception('Not a model file: %s' % (file.filename)) - - self.addNode(node, file.filename, file.newName) - - def addNode(self, node, filename, newName): - """ Converts the indicated node to a bam stream, and adds the - bam file to the multifile under the indicated newName. """ - - # If the Multifile already has a file by this name, don't - # bother adding it again. - if self.multifile.findSubfile(newName) >= 0: - return - - # Be sure to import all of the referenced textures, and tell - # them their new location within the multifile. - - for tex in NodePath(node).findAllTextures(): - if not tex.hasFullpath() and tex.hasRamImage(): - # We need to store this texture as a raw-data image. - # Clear the newName so this will happen - # automatically. - tex.clearFilename() - tex.clearAlphaFilename() - - else: - # We can store this texture as a file reference to its - # image. Copy the file into our multifile, and rename - # its reference in the texture. - if tex.hasFilename(): - tex.setFilename(self.addFoundTexture(tex.getFullpath())) - if tex.hasAlphaFilename(): - tex.setAlphaFilename(self.addFoundTexture(tex.getAlphaFullpath())) - - # Now generate an in-memory bam file. Tell the bam writer to - # keep the textures referenced by their in-multifile path. - bamFile = BamFile() - stream = StringStream() - bamFile.openWrite(stream) - bamFile.getWriter().setFileTextureMode(bamFile.BTMUnchanged) - bamFile.writeObject(node) - bamFile.close() - - # Clean the node out of memory. - node.removeAllChildren() - - # Now we have an in-memory bam file. - stream.seekg(0) - self.multifile.addSubfile(newName, stream, self.compressionLevel) - - # Flush it so the data gets written to disk immediately, so we - # don't have to keep it around in ram. - self.multifile.flush() - - xcomponent = TiXmlElement('component') - xcomponent.SetAttribute('filename', newName) - self.components.append(('c', newName.lower(), xcomponent)) - - def addFoundTexture(self, filename): - """ Adds the newly-discovered texture to the output, if it has - not already been included. Returns the new name within the - package tree. """ - - filename = Filename(filename) - filename.makeCanonical() - - file = self.sourceFilenames.get(filename, None) - if file: - # Never mind, it's already on the list. - return file.newName - - # We have to copy the image into the plugin tree somewhere. - newName = self.importedMapsDir + '/' + filename.getBasename() - uniqueId = 0 - while newName.lower() in self.targetFilenames: - uniqueId += 1 - newName = '%s/%s_%s.%s' % ( - self.importedMapsDir, filename.getBasenameWoExtension(), - uniqueId, filename.getExtension()) - - file = self.addFile( - filename, newName = newName, explicit = False, - compress = False) - - if file: - # If we added the file in this pass, then also - # immediately add it to the multifile (because we - # won't be visiting the files list again). - self.addComponent(file) - - return newName - - def addDcFile(self, file): - """ Adds a dc file to the archive. A dc file gets its - internal comments and parameter names stripped out of the - final result automatically. This is as close as we can - come to "compiling" a dc file, since all of the remaining - symbols are meaningful at runtime. """ - - # First, read in the dc file - from panda3d.direct import DCFile - dcFile = DCFile() - if not dcFile.read(file.filename): - self.notify.error("Unable to parse %s." % (file.filename)) - - # And then write it out without the comments and such. - stream = StringStream() - if not dcFile.write(stream, True): - self.notify.error("Unable to write %s." % (file.filename)) - - file.text = stream.getData() - self.addComponent(file) - - def addDcImports(self, file): - """ Adds the Python modules named by the indicated dc - file. """ - - from panda3d.direct import DCFile - dcFile = DCFile() - if not dcFile.read(file.filename): - self.notify.error("Unable to parse %s." % (file.filename)) - - for n in range(dcFile.getNumImportModules()): - moduleName = dcFile.getImportModule(n) - moduleSuffixes = [] - if '/' in moduleName: - moduleName, suffixes = moduleName.split('/', 1) - moduleSuffixes = suffixes.split('/') - self.freezer.addModule(moduleName) - - for suffix in self.packager.dcClientSuffixes: - if suffix in moduleSuffixes: - self.freezer.addModule(moduleName + suffix) - - for i in range(dcFile.getNumImportSymbols(n)): - symbolName = dcFile.getImportSymbol(n, i) - symbolSuffixes = [] - if '/' in symbolName: - symbolName, suffixes = symbolName.split('/', 1) - symbolSuffixes = suffixes.split('/') - - # "from moduleName import symbolName". - - # Maybe this symbol is itself a module; if that's - # the case, we need to add it to the list also. - self.freezer.addModule('%s.%s' % (moduleName, symbolName), - implicit = True) - for suffix in self.packager.dcClientSuffixes: - if suffix in symbolSuffixes: - self.freezer.addModule('%s.%s%s' % (moduleName, symbolName, suffix), - implicit = True) - - - def addPrcFile(self, file): - """ Adds a prc file to the archive. Like the dc file, - this strips comments and such before adding. It's also - possible to set prcEncryptionKey and/or prcSignCommand to - further manipulate prc files during processing. """ - - # First, read it in. - if file.text: - textLines = file.text.split('\n') - else: - textLines = open(file.filename.toOsSpecific(), 'rU').readlines() - - # Then write it out again, without the comments. - tempFilename = Filename.temporary('', 'p3d_', '.prc') - tempFilename.setBinary() # Binary is more reliable for signing. - temp = open(tempFilename.toOsSpecific(), 'w') - for line in textLines: - line = line.strip() - if line and line[0] != '#': - # Write the line out only if it's not a comment. - temp.write(line + '\n') - temp.close() - - if self.packager.prcSignCommand: - # Now sign the file. - command = '%s -n "%s"' % ( - self.packager.prcSignCommand, tempFilename.toOsSpecific()) - self.notify.info(command) - exitStatus = os.system(command) - if exitStatus != 0: - self.notify.error('Command failed: %s' % (command)) - - if self.packager.prcEncryptionKey: - # And now encrypt it. - if file.newName.endswith('.prc'): - # Change .prc -> .pre - file.newName = file.newName[:-1] + 'e' - - preFilename = Filename.temporary('', 'p3d_', '.pre') - preFilename.setBinary() - tempFilename.setText() - encryptFile(tempFilename, preFilename, self.packager.prcEncryptionKey) - tempFilename.unlink() - tempFilename = preFilename - - if file.deleteTemp: - file.filename.unlink() - - file.filename = tempFilename - file.text = None - file.deleteTemp = True - - self.addComponent(file) - - def addComponent(self, file): - compressionLevel = 0 - if file.compress: - compressionLevel = self.compressionLevel - - if file.text: - stream = StringStream(file.text) - self.multifile.addSubfile(file.newName, stream, compressionLevel) - self.multifile.flush() - - elif file.executable and self.arch: - if not self.__addOsxExecutable(file): - return - - else: - # Copy an ordinary file into the multifile. - self.multifile.addSubfile(file.newName, file.filename, compressionLevel) - if file.extract: - if file.text: - # Better write it to a temporary file, so we can - # get its hash. - tfile = Filename.temporary('', 'p3d_') - open(tfile.toOsSpecific(), 'wb').write(file.text) - xextract = self.getFileSpec('extract', tfile, file.newName) - tfile.unlink() - - else: - # The file data exists on disk already. - xextract = self.getFileSpec('extract', file.filename, file.newName) - self.extracts.append((file.newName.lower(), xextract)) - - xcomponent = TiXmlElement('component') - xcomponent.SetAttribute('filename', file.newName) - self.components.append(('c', file.newName.lower(), xcomponent)) - - def __addOsxExecutable(self, file): - """ Adds an executable or shared library to the multifile, - with respect to OSX's fat-binary features. Returns true - on success, false on failure. """ - - compressionLevel = 0 - if file.compress: - compressionLevel = self.compressionLevel - - # If we're on OSX and adding only files for a - # particular architecture, use lipo to strip out the - # part of the file for that architecture. - - arch = self.arch - if arch == "amd64": - arch = "x86_64" - - # First, we need to verify that it is in fact a - # universal binary. - tfile = Filename.temporary('', 'p3d_') - tfile.setBinary() - command = '/usr/bin/lipo -info "%s" >"%s"' % ( - file.filename.toOsSpecific(), - tfile.toOsSpecific()) - exitStatus = os.system(command) - if exitStatus != 0: - self.notify.warning("Not an executable file: %s" % (file.filename)) - # Just add it anyway. - file.filename.setBinary() - self.multifile.addSubfile(file.newName, file.filename, compressionLevel) - return True - - # The lipo command succeeded, so it really is an - # executable file. Parse the lipo output to figure out - # which architectures the file supports. - arches = [] - lipoData = open(tfile.toOsSpecific(), 'r').read() - tfile.unlink() - if ':' in lipoData: - arches = lipoData.rsplit(':', 1)[1] - arches = arches.split() - - if arches == [arch]: - # The file only contains the one architecture that - # we want anyway. - file.filename.setBinary() - self.multifile.addSubfile(file.newName, file.filename, compressionLevel) - return True - - if arch not in arches: - # The file doesn't support the architecture that we - # want at all. Omit the file. - self.notify.warning("%s doesn't support architecture %s" % ( - file.filename, self.arch)) - return False - - # The file contains multiple architectures. Get - # out just the one we want. - command = '/usr/bin/lipo -thin %s -output "%s" "%s"' % ( - arch, tfile.toOsSpecific(), - file.filename.toOsSpecific()) - exitStatus = os.system(command) - if exitStatus != 0: - self.notify.error('Command failed: %s' % (command)) - self.multifile.addSubfile(file.newName, tfile, compressionLevel) - if file.deleteTemp: - file.filename.unlink() - file.filename = tfile - file.deleteTemp = True - return True - - - def requirePackage(self, package): - """ Indicates a dependency on the given package. This - also implicitly requires all of the package's requirements - as well (though this transitive requirement happens at - runtime, not here at build time). """ - - if package not in self.requires: - self.requires.append(package) - for lowerName in package.targetFilenames: - ext = Filename(lowerName).getExtension() - if ext not in self.packager.nonuniqueExtensions: - self.skipFilenames[lowerName] = True - - for moduleName, mdef in package.moduleNames.items(): - if not mdef.exclude: - self.skipModules[moduleName] = mdef - - # Packager constructor - def __init__(self, platform = None): - - # The following are config settings that the caller may adjust - # before calling any of the command methods. - - # The platform string. - self.setPlatform(platform) - - # This should be set to a Filename. - self.installDir = None - - # If specified, this is a directory to search first for any - # library references, before searching the system. - # Particularly useful on OSX to reference the universal SDK. - self.systemRoot = None - - # Set this true to treat setHost() the same as addHost(), thus - # ignoring any request to specify a particular download host, - # e.g. for testing and development. - self.ignoreSetHost = False - - # Set this to true to verbosely log files ignored by dir(). - self.verbosePrint = False - - # This will be appended to the basename of any .p3d package, - # before the .p3d extension. - self.p3dSuffix = '' - - # The download URL at which these packages will eventually be - # hosted. - self.hosts = {} - self.host = PandaSystem.getPackageHostUrl() - self.addHost(self.host) - - # This will be used when we're not compiling in the packaged - # environment. - self.__hostInfos = {} - self.http = HTTPClient.getGlobalPtr() - - # The maximum amount of time a client should cache the - # contents.xml before re-querying the server, in seconds. - self.maxAge = 0 - - # The contents seq: a tuple of integers, representing the - # current seq value. The contents seq generally increments - # with each modification to the contents.xml file. There is - # also a package seq for each package, which generally - # increments with each modification to the package. - - # The contents seq and package seq are used primarily for - # documentation purposes, to note when a new version is - # released. The package seq value can also be used to verify - # that the contents.xml, desc.xml, and desc.import.xml files - # were all built at the same time. - - # Although the package seqs are used at runtime to verify that - # the latest contents.xml file has been downloaded, they are - # not otherwise used at runtime, and they are not binding on - # the download version. The md5 hash, not the package seq, is - # actually used to differentiate different download versions. - self.contentsSeq = SeqValue() - - # A search list for previously-built local packages. - - # We use a bit of caution to read the Filenames out of the - # config variable. Since cvar.getDirectories() returns a list - # of references to Filename objects stored within the config - # variable itself, we have to make a copy of each Filename - # returned, so they will persist beyond the lifespan of the - # config variable. - cvar = ConfigVariableSearchPath('pdef-path') - self.installSearch = list(map(Filename, cvar.getDirectories())) - - # This is where we cache the location of libraries. - self.libraryCache = {} - - # The system PATH, for searching dll's and exe's. - self.executablePath = DSearchPath() - - # By convention, we include sys.path at the front of - # self.executablePath, mainly to aid makepanda when building - # an rtdist build. - for dirname in sys.path: - self.executablePath.appendDirectory(Filename.fromOsSpecific(dirname)) - - # Now add the actual system search path. - if self.platform.startswith('win'): - self.addWindowsSearchPath(self.executablePath, "PATH") - - else: - if self.platform.startswith('osx'): - self.addPosixSearchPath(self.executablePath, "DYLD_LIBRARY_PATH") - - self.addPosixSearchPath(self.executablePath, "LD_LIBRARY_PATH") - self.addPosixSearchPath(self.executablePath, "PATH") - - if self.platform.startswith('linux'): - # It used to be okay to just add some common paths on Linux. - # But nowadays, each distribution has their own convention for - # where they put their libraries. Instead, we query the ldconfig - # cache, which contains the location of all libraries. - - if not self.loadLdconfigCache(): - # Ugh, failure. All that remains is to guess. This should - # work for the most common Debian configurations. - multiarchDir = "/lib/%s-linux-gnu" % (os.uname()[4]) - if os.path.isdir(multiarchDir): - self.executablePath.appendDirectory(multiarchDir) - if os.path.isdir("/usr/" + multiarchDir): - self.executablePath.appendDirectory("/usr/" + multiarchDir) - - else: - # FreeBSD, or some other system that still makes sense. - self.executablePath.appendDirectory('/lib') - self.executablePath.appendDirectory('/usr/lib') - self.executablePath.appendDirectory('/usr/local/lib') - - if self.platform.startswith('freebsd') and os.uname()[1] == "pcbsd": - self.executablePath.appendDirectory('/usr/PCBSD/local/lib') - - # Set this flag true to automatically add allow_python_dev to - # any applications. - self.allowPythonDev = False - - # Set this flag to store the original Python source files, - # without compiling them to .pyc or .pyo. - self.storePythonSource = False - - # Fill this with a list of (certificate, chain, pkey, - # password) tuples to automatically sign each p3d file - # generated. - self.signParams = [] - - # Optional signing and encrypting features. - self.encryptionKey = None - self.prcEncryptionKey = None - self.prcSignCommand = None - - # This is a list of filename extensions and/or basenames that - # indicate files that should be encrypted within the - # multifile. This provides obfuscation only, not real - # security, since the decryption key must be part of the - # client and is therefore readily available to any hacker. - # Not only is this feature useless, but using it also - # increases the size of your patchfiles, since encrypted files - # can't really be patched. But it's here if you really want - # it. ** Note: Actually, this isn't implemented yet. - #self.encryptExtensions = [] - #self.encryptFiles = [] - - # This is the list of DC import suffixes that should be - # available to the client. Other suffixes, like AI and UD, - # are server-side only and should be ignored by the Scrubber. - self.dcClientSuffixes = ['OV'] - - # Is this file system case-sensitive? - self.caseSensitive = True - if self.platform.startswith('win'): - self.caseSensitive = False - elif self.platform.startswith('osx'): - self.caseSensitive = False - - # Get the list of filename extensions that are recognized as - # image files. - self.imageExtensions = [] - for type in PNMFileTypeRegistry.getGlobalPtr().getTypes(): - self.imageExtensions += type.getExtensions() - - # Other useful extensions. The .pz extension is implicitly - # stripped. - - # Model files. - self.modelExtensions = [ 'egg', 'bam' ] - - # Text files that are copied (and compressed) to the package - # with end-of-line conversion. - self.textExtensions = [ 'prc', 'ptf', 'txt', 'cg', 'sha', 'dc', 'xml' ] - - # Binary files that are copied (and compressed) without - # processing. - self.binaryExtensions = [ 'ttf', 'TTF', 'mid', 'ico', 'cur' ] - - # Files that can have an existence in multiple different - # packages simultaneously without conflict. - self.nonuniqueExtensions = [ 'prc' ] - - # Files that represent an executable or shared library. - if self.platform.startswith('win'): - self.executableExtensions = [ 'dll', 'pyd', 'exe' ] - elif self.platform.startswith('osx'): - self.executableExtensions = [ 'so', 'dylib' ] - else: - self.executableExtensions = [ 'so' ] - - # Files that represent a Windows "manifest" file. These files - # must be explicitly extracted to disk so the OS can find - # them. - if self.platform.startswith('win'): - self.manifestExtensions = [ 'manifest' ] - else: - self.manifestExtensions = [ ] - - # Extensions that are automatically remapped by convention. - self.remapExtensions = {} - if self.platform.startswith('win'): - pass - elif self.platform.startswith('osx'): - self.remapExtensions = { - 'dll' : 'dylib', - 'pyd' : 'so', - 'exe' : '' - } - else: - self.remapExtensions = { - 'dll' : 'so', - 'pyd' : 'so', - 'exe' : '' - } - - # Files that should be extracted to disk. - self.extractExtensions = self.executableExtensions[:] + self.manifestExtensions[:] + [ 'ico', 'cur' ] - - # Files that indicate a platform dependency. - self.platformSpecificExtensions = self.executableExtensions[:] - - # Binary files that are considered uncompressible, and are - # copied without compression. - self.uncompressibleExtensions = [ 'mp3', 'ogg', 'ogv', 'wav', 'rml', 'rcss', 'otf' ] - # wav files are compressible, but p3openal_audio won't load - # them compressed. - # rml, rcss and otf files must be added here because - # libRocket wants to be able to seek in these files. - - # Files which are not to be processed further, but which - # should be added exactly byte-for-byte as they are. - self.unprocessedExtensions = [] - - # Files for which warnings should be suppressed when they are - # not handled by dir() - self.suppressWarningForExtensions = ['', 'pyc', 'pyo', - 'p3d', 'pdef', - 'c', 'C', 'cxx', 'cpp', 'h', 'H', - 'hpp', 'pp', 'I', 'pem', 'p12', 'crt', - 'o', 'obj', 'a', 'lib', 'bc', 'll'] - - # System files that should never be packaged. For - # case-insensitive filesystems (like Windows and OSX), put the - # lowercase filename here. Case-sensitive filesystems should - # use the correct case. - self.excludeSystemFiles = [ - 'kernel32.dll', 'user32.dll', 'wsock32.dll', 'ws2_32.dll', - 'advapi32.dll', 'opengl32.dll', 'glu32.dll', 'gdi32.dll', - 'shell32.dll', 'ntdll.dll', 'ws2help.dll', 'rpcrt4.dll', - 'imm32.dll', 'ddraw.dll', 'shlwapi.dll', 'secur32.dll', - 'dciman32.dll', 'comdlg32.dll', 'comctl32.dll', 'ole32.dll', - 'oleaut32.dll', 'gdiplus.dll', 'winmm.dll', 'iphlpapi.dll', - 'msvcrt.dll', 'kernelbase.dll', 'msimg32.dll', 'msacm32.dll', - - 'libsystem.b.dylib', 'libmathcommon.a.dylib', 'libmx.a.dylib', - 'libstdc++.6.dylib', 'libobjc.a.dylib', 'libauto.dylib', - ] - - # As above, but with filename globbing to catch a range of - # filenames. - self.excludeSystemGlobs = [ - GlobPattern('d3dx9_*.dll'), - GlobPattern('api-ms-win-*.dll'), - - GlobPattern('libGL.so*'), - GlobPattern('libGLU.so*'), - GlobPattern('libGLcore.so*'), - GlobPattern('libGLES*.so*'), - GlobPattern('libEGL.so*'), - GlobPattern('libX11.so*'), - GlobPattern('libXau.so*'), - GlobPattern('libXdmcp.so*'), - GlobPattern('libxcb*.so*'), - GlobPattern('libc.so*'), - GlobPattern('libgcc_s.so*'), - GlobPattern('libdl.so*'), - GlobPattern('libm.so*'), - GlobPattern('libnvidia*.so*'), - GlobPattern('libpthread.so*'), - GlobPattern('libthr.so*'), - GlobPattern('ld-linux.so*'), - GlobPattern('ld-linux-*.so*'), - GlobPattern('librt.so*'), - ] - - # A Loader for loading models. - self.loader = Loader.Loader(self) - self.sfxManagerList = None - self.musicManager = None - - # These options will be used when loading models and textures. By - # default we don't load textures beyond the header and don't store - # models in the RAM cache in order to conserve on memory usage. - opts = LoaderOptions() - opts.setFlags(opts.getFlags() | LoaderOptions.LFNoRamCache) - opts.setTextureFlags(opts.getTextureFlags() & ~LoaderOptions.TFPreload) - self.loaderOptions = opts - - # This is filled in during readPackageDef(). - self.packageList = [] - - # A table of all known packages by name. - self.packages = {} - - # A list of PackageEntry objects read from the contents.xml - # file. - self.contents = {} - - def loadLdconfigCache(self): - """ On GNU/Linux, runs ldconfig -p to find out where all the - libraries on the system are located. Assumes that the platform - has already been set. """ - - if not os.path.isfile('/sbin/ldconfig'): - return False - - handle = subprocess.Popen(['/sbin/ldconfig', '-p'], stdout=subprocess.PIPE, universal_newlines=True) - out, err = handle.communicate() - - if handle.returncode != 0: - self.notify.warning("/sbin/ldconfig -p returned code %d" %(handle.returncode)) - return False - - for line in out.splitlines(): - if '=>' not in line: - continue - - prefix, location = line.rsplit('=>', 1) - prefix = prefix.strip() - location = location.strip() - - if not location or not prefix or ' ' not in prefix: - self.notify.warning("Ignoring malformed ldconfig -p line: " + line) - continue - - lib, opts = prefix.split(' ', 1) - if ('x86-64' in opts) != self.platform.endswith('_amd64'): - # This entry isn't meant for our architecture. I think - # x86-64 is the only platform where ldconfig supplies - # this extra arch string. - continue - - self.libraryCache[lib] = Filename.fromOsSpecific(location) - - return True - - def resolveLibrary(self, filename): - """ Resolves the given shared library filename along the executable path, - or by cross-referencing it with the library cache. """ - - path = str(filename) - - if path in self.libraryCache: - filename.setFullpath(self.libraryCache[path].getFullpath()) - return True - - if filename.resolveFilename(self.executablePath): - self.libraryCache[path] = Filename(filename) - return True - - return False - - def setPlatform(self, platform = None): - """ Sets the platform that this Packager will compute for. On - OSX, this can be used to specify the particular architecture - we are building; on other platforms, it is probably a mistake - to set this. - - You should call this before doing anything else with the - Packager. It's even better to pass the platform string to the - constructor. """ - - self.platform = platform or PandaSystem.getPlatform() - - # OSX uses this "arch" string for the otool and lipo commands. - self.arch = None - if self.platform.startswith('osx_'): - self.arch = self.platform[4:] - - - def setHost(self, host, downloadUrl = None, - descriptiveName = None, hostDir = None, - mirrors = None): - """ Specifies the URL that will ultimately host these - contents. """ - - if not self.ignoreSetHost: - self.host = host - - self.addHost(host, downloadUrl = downloadUrl, - descriptiveName = descriptiveName, hostDir = hostDir, - mirrors = mirrors) - - def addHost(self, host, downloadUrl = None, descriptiveName = None, - hostDir = None, mirrors = None): - """ Adds a host to the list of known download hosts. This - information will be written into any p3d files that reference - this host; this can be used to pre-define the possible mirrors - for a given host, for instance. Returns the newly-created - HostEntry object.""" - - scheme = URLSpec(host).getScheme() - if scheme == 'https' and downloadUrl is None: - # If we specified an SSL-protected host URL, but no - # explicit download URL, then assume the download URL is - # the same, over cleartext. - url = URLSpec(host) - url.setScheme('http') - downloadUrl = url.getUrl() - - he = self.hosts.get(host, None) - if he is None: - # Define a new host entry - he = self.HostEntry(host, downloadUrl = downloadUrl, - descriptiveName = descriptiveName, - hostDir = hostDir, mirrors = mirrors) - self.hosts[host] = he - else: - # Update an existing host entry - if downloadUrl is not None: - he.downloadUrl = downloadUrl - if descriptiveName is not None: - he.descriptiveName = descriptiveName - if hostDir is not None: - he.hostDir = hostDir - if mirrors is not None: - he.mirrors = mirrors - - return he - - def addAltHost(self, keyword, altHost, origHost = None, - downloadUrl = None, descriptiveName = None, - hostDir = None, mirrors = None): - """ Adds an alternate host to any already-known host. This - defines an alternate server that may be contacted, if - specified on the HTML page, which hosts a different version of - the server's contents. (This is different from a mirror, - which hosts an identical version of the server's contents.) - """ - - if not origHost: - origHost = self.host - - self.addHost(altHost, downloadUrl = downloadUrl, - descriptiveName = descriptiveName, hostDir = hostDir, - mirrors = mirrors) - he = self.addHost(origHost) - he.altHosts[keyword] = altHost - - def addWindowsSearchPath(self, searchPath, varname): - """ Expands $varname, interpreting as a Windows-style search - path, and adds its contents to the indicated DSearchPath. """ - - path = ExecutionEnvironment.getEnvironmentVariable(varname) - if len(path) == 0: - if varname not in os.environ: - return - path = os.environ[varname] - for dirname in path.split(';'): - dirname = Filename.fromOsSpecific(dirname) - if dirname.makeTrueCase(): - searchPath.appendDirectory(dirname) - - def addPosixSearchPath(self, searchPath, varname): - """ Expands $varname, interpreting as a Posix-style search - path, and adds its contents to the indicated DSearchPath. """ - - path = ExecutionEnvironment.getEnvironmentVariable(varname) - if len(path) == 0: - if varname not in os.environ: - return - path = os.environ[varname] - for dirname in path.split(':'): - dirname = Filename.fromOsSpecific(dirname) - if dirname.makeTrueCase(): - searchPath.appendDirectory(dirname) - - def _ensureExtensions(self): - self.knownExtensions = \ - self.imageExtensions + \ - self.modelExtensions + \ - self.textExtensions + \ - self.binaryExtensions + \ - self.uncompressibleExtensions + \ - self.unprocessedExtensions - - def setup(self): - """ Call this method to initialize the class after filling in - some of the values in the constructor. """ - - self._ensureExtensions() - - self.currentPackage = None - - if self.installDir: - # If we were given an install directory, we can build - # packages as well as plain p3d files, and it all goes - # into the specified directory. - self.p3dInstallDir = self.installDir - self.allowPackages = True - else: - # If we don't have an actual install directory, we can - # only build p3d files, and we drop them into the current - # directory. - self.p3dInstallDir = '.' - self.allowPackages = False - - if not PandaSystem.getPackageVersionString() or not PandaSystem.getPackageHostUrl(): - raise PackagerError('This script must be run using a version of Panda3D that has been built\nfor distribution. Try using ppackage.p3d or packp3d.p3d instead.\nIf you are running this script for development purposes, you may also\nset the Config variable panda-package-host-url to the URL you expect\nto download these contents from (for instance, a file:// URL).') - - self.readContentsFile() - - def close(self): - """ Called after reading all of the package def files, this - performs any final cleanup appropriate. """ - - self.writeContentsFile() - - def buildPatches(self, packages): - """ Call this after calling close(), to build patches for the - indicated packages. """ - - # We quietly ignore any p3d applications or solo packages - # passed in the packages list; we only build patches for - # actual Multifile-based packages. - packageNames = [] - for package in packages: - if not package.p3dApplication and not package.solo: - packageNames.append(package.packageName) - - if packageNames: - from .PatchMaker import PatchMaker - pm = PatchMaker(self.installDir) - pm.buildPatches(packageNames = packageNames) - - def readPackageDef(self, packageDef, packageNames = None): - """ Reads the named .pdef file and constructs the named - packages, or all packages if packageNames is None. Raises an - exception if the pdef file is invalid. Returns the list of - packages constructed. """ - - self.notify.info('Reading %s' % (packageDef)) - - # We use exec to "read" the .pdef file. This has the nice - # side-effect that the user can put arbitrary Python code in - # there to control conditional execution, and such. - - # Set up the namespace dictionary for exec. - globals = {} - globals['__name__'] = packageDef.getBasenameWoExtension() - globals['__dir__'] = Filename(packageDef.getDirname()).toOsSpecific() - globals['__file__'] = packageDef.toOsSpecific() - globals['packageDef'] = packageDef - - globals['platform'] = self.platform - globals['packager'] = self - - # We'll stuff all of the predefined functions, and the - # predefined classes, in the global dictionary, so the pdef - # file can reference them. - - # By convention, the existence of a method of this class named - # do_foo(self) is sufficient to define a pdef method call - # foo(). - for methodName in list(self.__class__.__dict__.keys()): - if methodName.startswith('do_'): - name = methodName[3:] - c = func_closure(name) - globals[name] = c.generic_func - - globals['p3d'] = class_p3d - globals['package'] = class_package - globals['solo'] = class_solo - - # Now exec the pdef file. Assuming there are no syntax - # errors, and that the pdef file doesn't contain any really - # crazy Python code, all this will do is fill in the - # '__statements' list in the module scope. - fn = packageDef.toOsSpecific() - f = open(fn) - code = compile(f.read(), fn, 'exec') - f.close() - - # It appears that having a separate globals and locals - # dictionary causes problems with resolving symbols within a - # class scope. So, we just use one dictionary, the globals. - exec(code, globals) - - packages = [] - - # Now iterate through the statements and operate on them. - statements = globals.get('__statements', []) - if not statements: - self.notify.info("No packages defined.") - - try: - for (lineno, stype, name, args, kw) in statements: - if stype == 'class': - if packageNames is None or name in packageNames: - classDef = globals[name] - p3dApplication = (class_p3d in classDef.__bases__) - solo = (class_solo in classDef.__bases__) - self.beginPackage(name, p3dApplication = p3dApplication, - solo = solo) - statements = classDef.__dict__.get('__statements', []) - if not statements: - self.notify.info("No files added to %s" % (name)) - for (lineno, stype, sname, args, kw) in statements: - if stype == 'class': - raise PackagerError('Nested classes not allowed') - self.__evalFunc(sname, args, kw) - package = self.endPackage() - if package is not None: - packages.append(package) - elif packageNames is not None: - # If the name is explicitly specified, this means - # we should abort if the package faild to construct. - raise PackagerError('Failed to construct %s' % name) - else: - self.__evalFunc(name, args, kw) - except PackagerError: - # Append the line number and file name to the exception - # error message. - inst = sys.exc_info()[1] - if not inst.args: - inst.args = ('Error',) - - inst.args = (inst.args[0] + ' on line %s of %s' % (lineno, packageDef),) - raise - - return packages - - def __evalFunc(self, name, args, kw): - """ This is called from readPackageDef(), above, to call the - function do_name(*args, **kw), as extracted from the pdef - file. """ - - funcname = 'do_%s' % (name) - func = getattr(self, funcname) - try: - func(*args, **kw) - except OutsideOfPackageError: - message = '%s encountered outside of package definition' % (name) - raise OutsideOfPackageError(message) - - def __expandTabs(self, line, tabWidth = 8): - """ Expands tab characters in the line to 8 spaces. """ - p = 0 - while p < len(line): - if line[p] == '\t': - # Expand a tab. - nextStop = ((p + tabWidth) / tabWidth) * tabWidth - numSpaces = nextStop - p - line = line[:p] + ' ' * numSpaces + line[p + 1:] - p = nextStop - else: - p += 1 - - return line - - def __countLeadingWhitespace(self, line): - """ Returns the number of leading whitespace characters in the - line. """ - - line = self.__expandTabs(line) - return len(line) - len(line.lstrip()) - - def __stripLeadingWhitespace(self, line, whitespaceCount): - """ Removes the indicated number of whitespace characters, but - no more. """ - - line = self.__expandTabs(line) - line = line[:whitespaceCount].lstrip() + line[whitespaceCount:] - return line - - def __parseArgs(self, words, argList): - args = {} - - while len(words) > 1: - arg = words[-1] - if '=' not in arg: - return args - - parameter, value = arg.split('=', 1) - parameter = parameter.strip() - value = value.strip() - if parameter not in argList: - message = 'Unknown parameter %s' % (parameter) - raise PackagerError(message) - if parameter in args: - message = 'Duplicate parameter %s' % (parameter) - raise PackagerError(message) - - args[parameter] = value - - del words[-1] - - - def beginPackage(self, packageName, p3dApplication = False, - solo = False): - """ Begins a new package specification. packageName is the - basename of the package. Follow this with a number of calls - to file() etc., and close the package with endPackage(). """ - - if self.currentPackage: - raise PackagerError('unclosed endPackage %s' % (self.currentPackage.packageName)) - - package = self.Package(packageName, self) - self.currentPackage = package - - package.p3dApplication = p3dApplication - package.solo = solo - - if not package.p3dApplication and not self.allowPackages: - message = 'Cannot generate packages without an installDir; use -i' - raise PackagerError(message) - - - def endPackage(self): - """ Closes the current package specification. This actually - generates the package file. Returns the finished package, - or None if the package failed to close (e.g. missing files). """ - - if not self.currentPackage: - raise PackagerError('unmatched endPackage') - - package = self.currentPackage - package.signParams += self.signParams[:] - - self.currentPackage = None - if not package.close(): - return None - - self.packageList.append(package) - self.packages[(package.packageName, package.platform, package.version)] = package - self.currentPackage = None - - return package - - def findPackage(self, packageName, platform = None, version = None, - host = None, requires = None): - """ Searches for the named package from a previous publish - operation along the install search path. - - If requires is not None, it is a list of Package objects that - are already required. The new Package object must be - compatible with the existing Packages, or an error is - returned. This is also useful for determining the appropriate - package version to choose when a version is not specified. - - Returns the Package object, or None if the package cannot be - located. """ - - # Is it a package we already have resident? - package = self.packages.get((packageName, platform or self.platform, version, host), None) - if package: - return package - - # Look on the searchlist. - for dirname in self.installSearch: - package = self.__scanPackageDir(dirname, packageName, platform or self.platform, version, host, requires = requires) - if not package: - package = self.__scanPackageDir(dirname, packageName, platform, version, host, requires = requires) - - if package and host and package.host != host: - # Wrong host. - package = None - - if package: - break - - if not package: - # Query the indicated host. - package = self.__findPackageOnHost(packageName, platform or self.platform, version or None, host, requires = requires) - if not package: - package = self.__findPackageOnHost(packageName, platform, version, host, requires = requires) - - if package: - package = self.packages.setdefault((package.packageName, package.platform, package.version, package.host), package) - self.packages[(packageName, platform or self.platform, version, host)] = package - return package - - return None - - def __scanPackageDir(self, rootDir, packageName, platform, version, - host, requires = None): - """ Scans a directory on disk, looking for *.import.xml files - that match the indicated packageName and optional version. If a - suitable xml file is found, reads it and returns the assocated - Package definition. - - If a version is not specified, and multiple versions are - available, the highest-numbered version that matches will be - selected. - """ - - packages = [] - - if version: - # A specific version package. - versionList = [version] - else: - # An unversioned package, or any old version. - versionList = [None, '*'] - - for version in versionList: - packageDir = Filename(rootDir, packageName) - basename = packageName - - if version: - # A specific or nonspecific version package. - packageDir = Filename(packageDir, version) - basename += '.%s' % (version) - - if platform: - packageDir = Filename(packageDir, platform) - basename += '.%s' % (platform) - - # Actually, the host means little for this search, since we're - # only looking in a local directory at this point. - - basename += '.import.xml' - filename = Filename(packageDir, basename) - filelist = glob.glob(filename.toOsSpecific()) - if not filelist: - # It doesn't exist in the nested directory; try the root - # directory. - filename = Filename(rootDir, basename) - filelist = glob.glob(filename.toOsSpecific()) - - for file in filelist: - package = self.__readPackageImportDescFile(Filename.fromOsSpecific(file)) - packages.append(package) - - self.__sortImportPackages(packages) - for package in packages: - if package and self.__packageIsValid(package, requires, platform): - return package - - return None - - def __findPackageOnHost(self, packageName, platform, version, hostUrl, requires = None): - appRunner = AppRunnerGlobal.appRunner - - # Make sure we have a fresh version of the contents file. - host = self.__getHostInfo(hostUrl) - if not host.downloadContentsFile(self.http): - return None - - packageInfos = [] - packageInfo = host.getPackage(packageName, version, platform = platform) - if not packageInfo and not version: - # No explicit version is specified, first fallback: look - # for the compiled-in version. - packageInfo = host.getPackage(packageName, PandaSystem.getPackageVersionString(), platform = platform) - - if not packageInfo and not version: - # No explicit version is specified, second fallback: get - # the highest-numbered version available. - packageInfos = host.getPackages(packageName, platform = platform) - self.__sortPackageInfos(packageInfos) - - if packageInfo and not packageInfos: - packageInfos = [packageInfo] - - for packageInfo in packageInfos: - if not packageInfo or not packageInfo.importDescFile: - continue - - # Now we've retrieved a PackageInfo. Get the import desc file - # from it. - if host.hostDir: - filename = Filename(host.hostDir, 'imports/' + packageInfo.importDescFile.basename) - else: - # We're not running in the packaged environment, so download - # to a temporary file instead of the host directory. - filename = Filename.temporary('', 'import_' + packageInfo.importDescFile.basename, '.xml') - - if not host.freshenFile(self.http, packageInfo.importDescFile, filename): - self.notify.error("Couldn't download import file.") - continue - - # Now that we have the import desc file, use it to load one of - # our Package objects. - package = self.Package('', self) - success = package.readImportDescFile(filename) - - if not host.hostDir: - # Don't forget to delete the temporary file we created. - filename.unlink() - - if success and self.__packageIsValid(package, requires, platform): - return package - - # Couldn't find a suitable package. - return None - - def __getHostInfo(self, hostUrl = None): - """ This shadows appRunner.getHost(), for the purpose of running - outside the packaged environment. """ - - if not hostUrl: - hostUrl = PandaSystem.getPackageHostUrl() - - if AppRunnerGlobal.appRunner: - return AppRunnerGlobal.appRunner.getHost(hostUrl) - - host = self.__hostInfos.get(hostUrl, None) - if not host: - host = HostInfo(hostUrl) - self.__hostInfos[hostUrl] = host - return host - - def __sortImportPackages(self, packages): - """ Given a list of Packages read from *.import.xml filenames, - sorts them in reverse order by version, so that the - highest-numbered versions appear first in the list. """ - - tuples = [] - for package in packages: - version = self.__makeVersionTuple(package.version) - tuples.append((version, package)) - tuples.sort(reverse = True) - - return [t[1] for t in tuples] - - def __sortPackageInfos(self, packages): - """ Given a list of PackageInfos retrieved from a Host, sorts - them in reverse order by version, so that the highest-numbered - versions appear first in the list. """ - - tuples = [] - for package in packages: - version = self.__makeVersionTuple(package.packageVersion) - tuples.append((version, package)) - tuples.sort(reverse = True) - - return [t[1] for t in tuples] - - def __makeVersionTuple(self, version): - """ Converts a version string into a tuple for sorting, by - separating out numbers into separate numeric fields, so that - version numbers sort numerically where appropriate. """ - - if not version: - return ('',) - - words = [] - p = 0 - while p < len(version): - # Scan to the first digit. - w = '' - while p < len(version) and not version[p].isdigit(): - w += version[p] - p += 1 - words.append(w) - - # Scan to the end of the string of digits. - w = '' - while p < len(version) and version[p].isdigit(): - w += version[p] - p += 1 - if w: - words.append(int(w)) - - return tuple(words) - - def __packageIsValid(self, package, requires, platform): - """ Returns true if the package is valid, meaning it can be - imported without conflicts with existing packages already - required (such as different versions of panda3d). """ - - if package.platform and package.platform != platform: - # Incorrect platform. - return False - - if not requires: - # No other restrictions. - return True - - # Really, we only check the panda3d package. The other - # packages will list this as a dependency, and this is all - # that matters. - - panda1 = self.__findPackageInRequires('panda3d', [package] + package.requires) - panda2 = self.__findPackageInRequires('panda3d', requires) - - if not panda1 or not panda2: - return True - - if panda1.version == panda2.version: - return True - - print('Rejecting package %s, version "%s": depends on %s, version "%s" instead of version "%s"' % ( - package.packageName, package.version, - panda1.packageName, panda1.version, panda2.version)) - return False - - def __findPackageInRequires(self, packageName, list): - """ Returns the first package with the indicated name in the - list of packages, or in the list of packages required by the - packages in the list. """ - - for package in list: - if package.packageName == packageName: - return package - p2 = self.__findPackageInRequires(packageName, package.requires) - if p2: - return p2 - - return None - - def __readPackageImportDescFile(self, filename): - """ Reads the named xml file as a Package, and returns it if - valid, or None otherwise. """ - - package = self.Package('', self) - if package.readImportDescFile(filename): - return package - - return None - - def do_setVer(self, value): - """ Sets an explicit set_ver number for the package, as a tuple - of integers, or as a string of dot-separated integers. """ - - self.currentPackage.packageSetVer = SeqValue(value) - - def do_config(self, **kw): - """ Called with any number of keyword parameters. For each - keyword parameter, sets the corresponding p3d config variable - to the given value. This will be written into the - p3d_info.xml file at the top of the application, or to the - package desc file for a package file. """ - - if not self.currentPackage: - raise OutsideOfPackageError - - for keyword, value in list(kw.items()): - self.currentPackage.configs[keyword] = value - - def do_require(self, *args, **kw): - """ Indicates a dependency on the named package(s), supplied - as a name. - - Attempts to install this package will implicitly install the - named package also. Files already included in the named - package will be omitted from this one when building it. """ - - self.requirePackagesNamed(args, **kw) - - def requirePackagesNamed(self, names, version = None, host = None): - """ Indicates a dependency on the named package(s), supplied - as a name. - - Attempts to install this package will implicitly install the - named package also. Files already included in the named - package will be omitted from this one when building it. """ - - if not self.currentPackage: - raise OutsideOfPackageError - - for packageName in names: - # A special case when requiring the "panda3d" package. We - # supply the version number which we've been compiled with - # as a default. - pversion = version - phost = host - if packageName == 'panda3d': - if not pversion: - pversion = PandaSystem.getPackageVersionString() - if not phost: - phost = PandaSystem.getPackageHostUrl() - - package = self.findPackage(packageName, version = pversion, host = phost, - requires = self.currentPackage.requires) - if not package: - message = 'Unknown package %s, version "%s"' % (packageName, version) - self.notify.warning(message) - self.currentPackage.missingPackages.append((packageName, pversion)) - continue - - self.requirePackage(package) - - def requirePackage(self, package): - """ Indicates a dependency on the indicated package, supplied - as a Package object. - - Attempts to install this package will implicitly install the - named package also. Files already included in the named - package will be omitted from this one. """ - - if not self.currentPackage: - raise OutsideOfPackageError - - # A special case when requiring the "panda3d" package. We - # complain if the version number doesn't match what we've been - # compiled with. - if package.packageName == 'panda3d': - if package.version != PandaSystem.getPackageVersionString(): - self.notify.warning("Requiring panda3d version %s, which does not match the current build of Panda, which is version %s." % (package.version, PandaSystem.getPackageVersionString())) - elif package.host != PandaSystem.getPackageHostUrl(): - self.notify.warning("Requiring panda3d host %s, which does not match the current build of Panda, which is host %s." % (package.host, PandaSystem.getPackageHostUrl())) - - self.currentPackage.requirePackage(package) - - def do_module(self, *args, **kw): - """ Adds the indicated Python module(s) to the current package. """ - self.addModule(args, **kw) - - def addModule(self, moduleNames, newName = None, filename = None, required = False): - if not self.currentPackage: - raise OutsideOfPackageError - - if (newName or filename) and len(moduleNames) != 1: - raise PackagerError('Cannot specify newName with multiple modules') - - if required: - self.currentPackage.requiredModules += moduleNames - - for moduleName in moduleNames: - self.currentPackage.freezer.addModule(moduleName, newName = newName, filename = filename) - - def do_excludeModule(self, *args): - """ Marks the indicated Python module as not to be included. """ - - if not self.currentPackage: - raise OutsideOfPackageError - - for moduleName in args: - self.currentPackage.freezer.excludeModule(moduleName) - - def do_main(self, filename): - """ Includes the indicated file as __main__ module of the application. - Also updates mainModule to point to this module. """ - - self.addModule(['__main__'], '__main__', filename, required = True) - self.currentPackage.mainModule = ('__main__', '__main__') - - def do_mainModule(self, moduleName, newName = None, filename = None): - """ Names the indicated module as the "main" module of the - application or exe. In most cases, you will want to use main() - instead. """ - - if not self.currentPackage: - raise OutsideOfPackageError - - if self.currentPackage.mainModule and self.currentPackage.mainModule[0] != moduleName: - self.notify.warning("Replacing mainModule %s with %s" % ( - self.currentPackage.mainModule[0], moduleName)) - - if not newName: - newName = moduleName - - if filename: - filename = Filename(filename) - newFilename = Filename('/'.join(moduleName.split('.'))) - newFilename.setExtension(filename.getExtension()) - self.currentPackage.addFile( - filename, newName = str(newFilename), - explicit = True, extract = True, required = True) - - self.currentPackage.mainModule = (moduleName, newName) - - def do_sign(self, certificate, chain = None, pkey = None, password = None): - """ Signs the resulting p3d file (or package multifile) with - the indicated certificate. If needed, the chain file should - contain the list of additional certificate authorities needed - to validate the signing certificate. The pkey file should - contain the private key. - - It is also legal for the certificate file to contain the chain - and private key embedded within it. - - If the private key is encrypted, the password should be - supplied. """ - - self.currentPackage.signParams.append((certificate, chain, pkey, password)) - - def do_setupPanda3D(self, p3dpythonName=None, p3dpythonwName=None): - """ A special convenience command that adds the minimum - startup modules for a panda3d package, intended for developers - producing their own custom panda3d for download. Should be - called before any other Python modules are named. """ - - # This module and all its dependencies come frozen into p3dpython. - # We should mark them as having already been added so that we don't - # add them again to the Multifile. - self.do_module('direct.showbase.VFSImporter') - self.currentPackage.freezer.done(addStartupModules=True) - self.currentPackage.freezer.writeCode(None) - self.currentPackage.addExtensionModules() - self.currentPackage.freezer.reset() - - self.do_file('panda3d/core.pyd', newDir='panda3d') - - # This is the key Python module that is imported at runtime to - # start an application running. - self.do_module('direct.p3d.AppRunner') - - # This is the main program that drives the runtime Python. It - # is responsible for importing direct.p3d.AppRunner to start an - # application running. The program comes in two parts: an - # executable, and an associated dynamic library. Note that the - # .exe and .dll extensions are automatically replaced with the - # appropriate platform-specific extensions. - - if self.platform.startswith('osx'): - # On Mac, we package up a P3DPython.app bundle. This - # includes specifications in the plist file to avoid - # creating a dock icon and stuff. - - resources = [] - - # Find p3dpython.plist in the direct source tree. - import direct - plist = Filename(direct.__path__[0], 'plugin/p3dpython.plist') - -## # Find panda3d.icns in the models tree. -## filename = Filename('plugin_images/panda3d.icns') -## found = filename.resolveFilename(getModelPath().getValue()) -## if not found: -## found = filename.resolveFilename("models") -## if found: -## resources.append(filename) - - self.do_makeBundle('P3DPython.app', plist, executable = 'p3dpython', - resources = resources, dependencyDir = '') - - else: - # Anywhere else, we just ship the executable file p3dpython.exe. - if p3dpythonName is None: - p3dpythonName = 'p3dpython' - else: - self.do_config(p3dpython_name=p3dpythonName) - - if self.platform.startswith('win'): - self.do_file('p3dpython.exe', newName=p3dpythonName+'.exe') - else: - self.do_file('p3dpython.exe', newName=p3dpythonName) - - # The "Windows" executable appends a 'w' to whatever name is used - # above, unless an override name is explicitly specified. - if self.platform.startswith('win'): - if p3dpythonwName is None: - p3dpythonwName = p3dpythonName+'w' - else: - self.do_config(p3dpythonw_name=p3dpythonwName) - - if self.platform.startswith('win'): - self.do_file('p3dpythonw.exe', newName=p3dpythonwName+'.exe') - else: - self.do_file('p3dpythonw.exe', newName=p3dpythonwName) - - self.do_file('libp3dpython.dll') - - def do_freeze(self, filename, compileToExe = False): - """ Freezes all of the current Python code into either an - executable (if compileToExe is true) or a dynamic library (if - it is false). The resulting compiled binary is added to the - current package under the indicated filename. The filename - should not include an extension; that will be added. """ - - if not self.currentPackage: - raise OutsideOfPackageError - - package = self.currentPackage - freezer = package.freezer - - if package.mainModule and not compileToExe: - self.notify.warning("Ignoring main_module for dll %s" % (filename)) - package.mainModule = None - if not package.mainModule and compileToExe: - message = "No main_module specified for exe %s" % (filename) - raise PackagerError(message) - - if package.mainModule: - moduleName, newName = package.mainModule - if compileToExe: - # If we're producing an exe, the main module must - # be called "__main__". - newName = '__main__' - package.mainModule = (moduleName, newName) - - if newName not in freezer.modules: - freezer.addModule(moduleName, newName = newName) - else: - freezer.modules[newName] = freezer.modules[moduleName] - freezer.done(addStartupModules = compileToExe) - - dirname = '' - basename = filename - if '/' in basename: - dirname, basename = filename.rsplit('/', 1) - dirname += '/' - - basename = freezer.generateCode(basename, compileToExe = compileToExe) - - package.addFile(Filename(basename), newName = dirname + basename, - deleteTemp = True, explicit = True, extract = True) - package.addExtensionModules() - if not package.platform: - package.platform = self.platform - - # Reset the freezer for more Python files. - freezer.reset() - package.mainModule = None - - def do_makeBundle(self, bundleName, plist, executable = None, - resources = None, dependencyDir = None): - """ Constructs a minimal OSX "bundle" consisting of an - executable and a plist file, with optional resource files - (such as icons), and adds it to the package under the given - name. """ - - contents = bundleName + '/Contents' - - self.addFiles([plist], newName = contents + '/Info.plist', - extract = True) - if executable: - basename = Filename(executable).getBasename() - self.addFiles([executable], newName = contents + '/MacOS/' + basename, - extract = True, executable = True, dependencyDir = dependencyDir) - if resources: - self.addFiles(resources, newDir = contents + '/Resources', - extract = True, dependencyDir = dependencyDir) - - - - def do_file(self, *args, **kw): - """ Adds the indicated file or files to the current package. - See addFiles(). """ - - self.addFiles(args, **kw) - - def addFiles(self, filenames, text = None, newName = None, - newDir = None, extract = None, executable = None, - deleteTemp = False, literal = False, - dependencyDir = None, required = False): - - """ Adds the indicated arbitrary files to the current package. - - filenames is a list of Filename or string objects, and each - may include shell globbing characters. - - Each file is placed in the named directory, or the toplevel - directory if no directory is specified. - - Certain special behavior is invoked based on the filename - extension. For instance, .py files may be automatically - compiled and stored as Python modules. - - If newDir is not None, it specifies the directory in which the - file should be placed. In this case, all files matched by the - filename expression are placed in the named directory. - - If newName is not None, it specifies a new filename. In this - case, newDir is ignored, and the filename expression must - match only one file. - - If newName and newDir are both None, the file is placed in the - toplevel directory, regardless of its source directory. - - If text is nonempty, it contains the text of the file. In - this case, the filename is not read, but the supplied text is - used instead. - - If extract is true, the file is explicitly extracted at - runtime. - - If executable is true, the file is marked as an executable - filename, for special treatment. - - If deleteTemp is true, the file is a temporary file and will - be deleted after its contents are copied to the package. - - If literal is true, then the file extension will be respected - exactly as it appears, and glob characters will not be - expanded. If this is false, then .dll or .exe files will be - renamed to .dylib and no extension on OSX (or .so on Linux); - and glob characters will be expanded. - - If required is true, then the file is marked a vital part of - the package. The package will not be built if this file - somehow cannot be added to the package. - - """ - - if not self.currentPackage: - raise OutsideOfPackageError - - files = [] - explicit = True - - for filename in filenames: - filename = Filename(filename) - - if literal: - thisFiles = [filename.toOsSpecific()] - - else: - ext = filename.getExtension() - - # A special case, since OSX and Linux don't have a - # standard extension for program files. - if executable is None and ext == 'exe': - executable = True - - newExt = self.remapExtensions.get(ext, None) - if newExt is not None: - filename.setExtension(newExt) - - thisFiles = glob.glob(filename.toOsSpecific()) - if not thisFiles: - thisFiles = [filename.toOsSpecific()] - - if newExt == 'dll' or (ext == 'dll' and newExt is None): - # Go through the dsoFilename interface on Windows, - # to insert a _d if we are running on a debug - # build. - dllFilename = Filename(filename) - dllFilename.setExtension('so') - dllFilename = Filename.dsoFilename(str(dllFilename)) - if dllFilename != filename: - thisFiles = glob.glob(filename.toOsSpecific()) - if not thisFiles: - # We have to resolve this filename to - # determine if it's a _d or not. - if self.resolveLibrary(dllFilename): - thisFiles = [dllFilename.toOsSpecific()] - else: - thisFiles = [filename.toOsSpecific()] - - if len(thisFiles) > 1: - explicit = False - files += thisFiles - - prefix = '' - if newDir is not None: - prefix = str(Filename(newDir)) - if prefix and prefix[-1] != '/': - prefix += '/' - - if newName: - if len(files) != 1: - message = 'Cannot install multiple files on target filename %s' % (newName) - raise PackagerError(message) - - if text: - if len(files) != 1: - message = 'Cannot install text to multiple files' - raise PackagerError(message) - if not newName: - newName = str(filenames[0]) - - for filename in files: - filename = Filename.fromOsSpecific(filename) - basename = filename.getBasename() - name = newName - if not name: - name = prefix + basename - - self.currentPackage.addFile( - filename, newName = name, extract = extract, - explicit = explicit, executable = executable, - text = text, deleteTemp = deleteTemp, - dependencyDir = dependencyDir, required = required) - - def do_exclude(self, filename): - """ Marks the indicated filename as not to be included. The - filename may include shell globbing characters, and may or may - not include a dirname. (If it does not include a dirname, it - refers to any file with the given basename from any - directory.)""" - - if not self.currentPackage: - raise OutsideOfPackageError - - filename = Filename(filename) - self.currentPackage.excludeFile(filename) - - - def do_includeExtensions(self, executableExtensions = None, extractExtensions = None, - imageExtensions = None, textExtensions = None, - uncompressibleExtensions = None, unprocessedExtensions = None, - suppressWarningForExtensions = None): - """ Ensure that dir() will include files with the given extensions. - The extensions should not have '.' prefixes. - - All except 'suppressWarningForExtensions' allow the given kinds of files - to be packaged with their respective semantics (read the source). - - 'suppressWarningForExtensions' lists extensions *expected* to be ignored, - so no warnings will be emitted for them. - """ - if executableExtensions: - self.executableExtensions += executableExtensions - - if extractExtensions: - self.extractExtensions += extractExtensions - - if imageExtensions: - self.imageExtensions += imageExtensions - - if textExtensions: - self.textExtensions += textExtensions - - if uncompressibleExtensions: - self.uncompressibleExtensions += uncompressibleExtensions - - if unprocessedExtensions: - self.unprocessedExtensions += unprocessedExtensions - - if suppressWarningForExtensions: - self.suppressWarningForExtensions += suppressWarningForExtensions - - self._ensureExtensions() - - def do_dir(self, dirname, newDir = None, unprocessed = None): - - """ Adds the indicated directory hierarchy to the current - package. The directory hierarchy is walked recursively, and - all files that match a known extension are added to the package. - - newDir specifies the directory name within the package which - the contents of the named directory should be installed to. - If it is omitted, the contents of the named directory are - installed to the root of the package. - - If unprocessed is false (the default), bam files are loaded and - scanned for textures, and these texture paths within the bam - files are manipulated to point to the new paths within the - package. If unprocessed is true, this operation is bypassed, - and bam files are packed exactly as they are. - """ - - if not self.currentPackage: - raise OutsideOfPackageError - - dirname = Filename(dirname) - if not newDir: - newDir = '' - - # Adding the directory to sys.path is a cheesy way to help the - # modulefinder find it. - sys.path.append(dirname.toOsSpecific()) - self.__recurseDir(dirname, newDir, unprocessed = unprocessed) - - def __recurseDir(self, filename, newName, unprocessed = None, packageTree = None): - if filename.isDirectory(): - # It's a directory name. Recurse. - prefix = newName - if prefix and prefix[-1] != '/': - prefix += '/' - - # First check if this is a Python package tree. If so, add it - # implicitly as a module. - dirList = vfs.scanDirectory(filename) - for subfile in dirList: - filename = subfile.getFilename() - if filename.getBasename() == '__init__.py': - moduleName = newName.replace("/", ".") - self.addModule([moduleName], filename=filename) - - for subfile in dirList: - filename = subfile.getFilename() - self.__recurseDir(filename, prefix + filename.getBasename(), - unprocessed = unprocessed) - return - elif not filename.exists(): - # It doesn't exist. Perhaps it's a virtual file. Ignore it. - return - - # It's a file name. Add it. - ext = filename.getExtension() - if ext == 'py': - self.currentPackage.addFile(filename, newName = newName, - explicit = False, unprocessed = unprocessed) - else: - if ext == 'pz' or ext == 'gz': - # Strip off an implicit .pz extension. - newFilename = Filename(filename) - newFilename.setExtension('') - newFilename = Filename(str(newFilename)) - ext = newFilename.getExtension() - - if ext in self.knownExtensions: - if ext in self.textExtensions: - filename.setText() - else: - filename.setBinary() - self.currentPackage.addFile(filename, newName = newName, - explicit = False, unprocessed = unprocessed) - elif not ext in self.suppressWarningForExtensions: - newCount = self.currentPackage.ignoredDirFiles.get(ext, 0) + 1 - self.currentPackage.ignoredDirFiles[ext] = newCount - - if self.verbosePrint: - self.notify.warning("ignoring file %s" % filename) - - def readContentsFile(self): - """ Reads the contents.xml file at the beginning of - processing. """ - - self.hosts = {} - # Since we've blown away the self.hosts map, we have to make - # sure that our own host at least is added to the map. - self.addHost(self.host) - - self.maxAge = 0 - self.contentsSeq = SeqValue() - self.contents = {} - self.contentsChanged = False - - if not self.allowPackages: - # Don't bother. - return - - contentsFilename = Filename(self.installDir, 'contents.xml') - doc = TiXmlDocument(contentsFilename.toOsSpecific()) - if not doc.LoadFile(): - # Couldn't read file. - return - - xcontents = doc.FirstChildElement('contents') - if xcontents: - maxAge = xcontents.Attribute('max_age') - if maxAge: - self.maxAge = int(maxAge) - - self.contentsSeq.loadXml(xcontents) - - xhost = xcontents.FirstChildElement('host') - if xhost: - he = self.HostEntry() - he.loadXml(xhost, self) - self.hosts[he.url] = he - self.host = he.url - - xpackage = xcontents.FirstChildElement('package') - while xpackage: - pe = self.PackageEntry() - pe.loadXml(xpackage) - self.contents[pe.getKey()] = pe - xpackage = xpackage.NextSiblingElement('package') - - def writeContentsFile(self): - """ Rewrites the contents.xml file at the end of - processing. """ - - if not self.contentsChanged: - # No need to rewrite. - return - - contentsFilename = Filename(self.installDir, 'contents.xml') - doc = TiXmlDocument(contentsFilename.toOsSpecific()) - decl = TiXmlDeclaration("1.0", "utf-8", "") - doc.InsertEndChild(decl) - - xcontents = TiXmlElement('contents') - if self.maxAge: - xcontents.SetAttribute('max_age', str(self.maxAge)) - - self.contentsSeq += 1 - self.contentsSeq.storeXml(xcontents) - - if self.host: - he = self.hosts.get(self.host, None) - if he: - xhost = he.makeXml(packager = self) - xcontents.InsertEndChild(xhost) - - contents = sorted(self.contents.items()) - for key, pe in contents: - xpackage = pe.makeXml() - xcontents.InsertEndChild(xpackage) - - doc.InsertEndChild(xcontents) - doc.SaveFile() - - -# The following class and function definitions represent a few sneaky -# Python tricks to allow the pdef syntax to contain the pseudo-Python -# code they do. These tricks bind the function and class definitions -# into a bit table as they are parsed from the pdef file, so we can -# walk through that table later and perform the operations requested -# in order. - -class metaclass_def(type): - """ A metaclass is invoked by Python when the class definition is - read, for instance to define a child class. By defining a - metaclass for class_p3d and class_package, we can get a callback - when we encounter "class foo(p3d)" in the pdef file. The callback - actually happens after all of the code within the class scope has - been parsed first. """ - - def __new__(self, name, bases, dict): - - # At the point of the callback, now, "name" is the name of the - # class we are instantiating, "bases" is the list of parent - # classes, and "dict" is the class dictionary we have just - # parsed. - - # If "dict" contains __metaclass__, then we must be parsing - # class_p3d or class_ppackage, below--skip it. But if it - # doesn't contain __metaclass__, then we must be parsing - # "class foo(p3d)" (or whatever) from the pdef file. - - if '__metaclass__' not in dict: - # Get the context in which this class was created - # (presumably, the module scope) out of the stack frame. - frame = sys._getframe(1) - mdict = frame.f_locals - lineno = frame.f_lineno - - # Store the class name on a statements list in that - # context, so we can later resolve the class names in - # the order they appeared in the file. - mdict.setdefault('__statements', []).append((lineno, 'class', name, None, None)) - - return type.__new__(self, name, bases, dict) - -# Define these dynamically to stay compatible with Python 2 and 3. -class_p3d = metaclass_def(str('class_p3d'), (), {}) -class_package = metaclass_def(str('class_package'), (), {}) -class_solo = metaclass_def(str('class_solo'), (), {}) - -class func_closure: - - """ This class is used to create a closure on the function name, - and also allows the *args, **kw syntax. In Python, the lambda - syntax, used with default parameters, is used more often to create - a closure (that is, a binding of one or more variables into a - callable object), but that syntax doesn't work with **kw. - Fortunately, a class method is also a form of a closure, because - it binds self; and this doesn't have any syntax problems with - **kw. """ - - def __init__(self, name): - self.name = name - - def generic_func(self, *args, **kw): - """ This method is bound to all the functions that might be - called from the pdef file. It's a special function; when it is - called, it does nothing but store its name and arguments in the - caller's local scope, where they can be pulled out later. """ - - # Get the context in which this function was called (presumably, - # the class dictionary) out of the stack frame. - frame = sys._getframe(1) - cldict = frame.f_locals - lineno = frame.f_lineno - - # Store the function on a statements list in that context, so we - # can later walk through the function calls for each class. - cldict.setdefault('__statements', []).append((lineno, 'func', self.name, args, kw)) diff --git a/direct/src/p3d/PatchMaker.py b/direct/src/p3d/PatchMaker.py deleted file mode 100644 index c1624b3cc1..0000000000 --- a/direct/src/p3d/PatchMaker.py +++ /dev/null @@ -1,814 +0,0 @@ -__all__ = ["PatchMaker"] - -from direct.p3d.FileSpec import FileSpec -from direct.p3d.SeqValue import SeqValue -from panda3d.core import * -import copy - -class PatchMaker: - """ This class will operate on an existing package install - directory, as generated by the Packager, and create patchfiles - between versions as needed. It is also used at runtime, to apply - the downloaded patches. """ - - class PackageVersion: - """ A specific patch version of a package. This is not just - the package's "version" string; it also corresponds to the - particular patch version, which increments independently of - the "version". """ - - def __init__(self, packageName, platform, version, hostUrl, file): - self.packageName = packageName - self.platform = platform - self.version = version - self.hostUrl = hostUrl - self.file = file - self.printName = None - - # The Package object that produces this version, if this - # is the current, base, or top form, respectively. - self.packageCurrent = None - self.packageBase = None - self.packageTop = None - - # A list of patchfiles that can produce this version. - self.fromPatches = [] - - # A list of patchfiles that can start from this version. - self.toPatches = [] - - # A temporary file for re-creating the archive file for - # this version. - self.tempFile = None - - def cleanup(self): - if self.tempFile: - self.tempFile.unlink() - - def getPatchChain(self, startPv, alreadyVisited = []): - """ Returns a list of patches that, when applied in - sequence to the indicated PackageVersion object, will - produce this PackageVersion object. Returns None if no - chain can be found. """ - - if self is startPv: - # We're already here. A zero-length patch chain is - # therefore the answer. - return [] - if self in alreadyVisited: - # We've already been here; this is a loop. Avoid - # infinite recursion. - return None - - alreadyVisited = alreadyVisited[:] - alreadyVisited.append(self) - - bestPatchChain = None - for patchfile in self.fromPatches: - fromPv = patchfile.fromPv - patchChain = fromPv.getPatchChain(startPv, alreadyVisited) - if patchChain is not None: - # There's a path through this patchfile. - patchChain = patchChain + [patchfile] - if bestPatchChain is None or len(patchChain) < len(bestPatchChain): - bestPatchChain = patchChain - - # Return the shortest path found, or None if there were no - # paths found. - return bestPatchChain - - def getRecreateFilePlan(self, alreadyVisited = []): - """ Returns the tuple (startFile, startPv, plan), - describing how to recreate the archive file for this - version. startFile and startPv is the Filename and - packageVersion of the file to start with, and plan is a - list of tuples (patchfile, pv), listing the patches to - apply in sequence, and the packageVersion object - associated with each patch. Returns (None, None, None) if - there is no way to recreate this archive file. """ - - if self.tempFile: - return (self.tempFile, self, []) - - if self in alreadyVisited: - # We've already been here; this is a loop. Avoid - # infinite recursion. - return (None, None, None) - - alreadyVisited = alreadyVisited[:] - alreadyVisited.append(self) - - if self.packageCurrent: - # This PackageVersion instance represents the current - # version of some package. - package = self.packageCurrent - return (Filename(package.packageDir, package.compressedFilename), self, []) - - if self.packageBase: - # This PackageVersion instance represents the base - # (oldest) version of some package. - package = self.packageBase - return (Filename(package.packageDir, package.baseFile.filename + '.pz'), self, []) - - # We'll need to re-create the file. - bestPlan = None - bestStartFile = None - bestStartPv = None - for patchfile in self.fromPatches: - fromPv = patchfile.fromPv - startFile, startPv, plan = fromPv.getRecreateFilePlan(alreadyVisited) - if plan is not None: - # There's a path through this patchfile. - plan = plan + [(patchfile, self)] - if bestPlan is None or len(plan) < len(bestPlan): - bestPlan = plan - bestStartFile = startFile - bestStartPv = startPv - - # Return the shortest path found, or None if there were no - # paths found. - return (bestStartFile, bestStartPv, bestPlan) - - def getFile(self): - """ Returns the Filename of the archive file associated - with this version. If the file doesn't actually exist on - disk, a temporary file will be created. Returns None if - the file can't be recreated. """ - - startFile, startPv, plan = self.getRecreateFilePlan() - - if startFile.getExtension() in ('pz', 'gz'): - # If the starting file is compressed, we have to - # decompress it first. - assert startPv.tempFile is None - startPv.tempFile = Filename.temporary('', 'patch_') - if not decompressFile(startFile, startPv.tempFile): - # Failure trying to decompress the file. - return None - startFile = startPv.tempFile - - if not plan: - # If plan is a zero-length list, we're already - # here--return startFile. If plan is None, there's no - # solution, and startFile is None. In either case, we - # can return startFile. - return startFile - - # If plan is a non-empty list, we have to walk the list to - # apply the patch plan. - prevFile = startFile - for patchfile, pv in plan: - fromPv = patchfile.fromPv - patchFilename = Filename(patchfile.package.packageDir, patchfile.file.filename) - result = self.applyPatch(prevFile, patchFilename) - if not result: - # Failure trying to re-create the file. - return None - - pv.tempFile = result - prevFile = result - - # Successfully patched. - assert pv is self and prevFile is self.tempFile - return prevFile - - def applyPatch(self, origFile, patchFilename): - """ Applies the named patch to the indicated original - file, storing the results in a temporary file, and returns - that temporary Filename. Returns None on failure. """ - - result = Filename.temporary('', 'patch_') - p = Patchfile() - if not p.apply(patchFilename, origFile, result): - print("Internal patching failed: %s" % (patchFilename)) - return None - - return result - - def getNext(self, package): - """ Gets the next patch in the chain towards this - package. """ - for patch in self.toPatches: - if patch.packageName == package.packageName and \ - patch.platform == package.platform and \ - patch.version == package.version and \ - patch.hostUrl == package.hostUrl: - return patch.toPv - - return None - - class Patchfile: - """ A single patchfile for a package. """ - - def __init__(self, package): - self.package = package - self.packageName = package.packageName - self.platform = package.platform - self.version = package.version - self.hostUrl = None - - # FileSpec for the patchfile itself - self.file = None - - # FileSpec for the package file that the patch is applied to - self.sourceFile = None - - # FileSpec for the package file that the patch generates - self.targetFile = None - - # The PackageVersion corresponding to our sourceFile - self.fromPv = None - - # The PackageVersion corresponding to our targetFile - self.toPv = None - - def getSourceKey(self): - """ Returns the key for locating the package that this - patchfile can be applied to. """ - return (self.packageName, self.platform, self.version, self.hostUrl, self.sourceFile) - - def getTargetKey(self): - """ Returns the key for locating the package that this - patchfile will generate. """ - return (self.packageName, self.platform, self.version, self.hostUrl, self.targetFile) - - def fromFile(self, packageDir, patchFilename, sourceFile, targetFile): - """ Creates the data structures from an existing patchfile - on disk. """ - - self.file = FileSpec() - self.file.fromFile(packageDir, patchFilename) - self.sourceFile = sourceFile - self.targetFile = targetFile - - def loadXml(self, xpatch): - """ Reads the data structures from an xml file. """ - - self.packageName = xpatch.Attribute('name') or self.packageName - self.platform = xpatch.Attribute('platform') or self.platform - self.version = xpatch.Attribute('version') or self.version - self.hostUrl = xpatch.Attribute('host') or self.hostUrl - - self.file = FileSpec() - self.file.loadXml(xpatch) - - xsource = xpatch.FirstChildElement('source') - if xsource: - self.sourceFile = FileSpec() - self.sourceFile.loadXml(xsource) - - xtarget = xpatch.FirstChildElement('target') - if xtarget: - self.targetFile = FileSpec() - self.targetFile.loadXml(xtarget) - - def makeXml(self, package): - xpatch = TiXmlElement('patch') - - if self.packageName != package.packageName: - xpatch.SetAttribute('name', self.packageName) - if self.platform != package.platform: - xpatch.SetAttribute('platform', self.platform) - if self.version != package.version: - xpatch.SetAttribute('version', self.version) - if self.hostUrl != package.hostUrl: - xpatch.SetAttribute('host', self.hostUrl) - - self.file.storeXml(xpatch) - - xsource = TiXmlElement('source') - self.sourceFile.storeMiniXml(xsource) - xpatch.InsertEndChild(xsource) - - xtarget = TiXmlElement('target') - self.targetFile.storeMiniXml(xtarget) - xpatch.InsertEndChild(xtarget) - - return xpatch - - class Package: - """ This is a particular package. This contains all of the - information needed to reconstruct the package's desc file. """ - - def __init__(self, packageDesc, patchMaker, xpackage = None): - self.packageDir = Filename(patchMaker.installDir, packageDesc.getDirname()) - self.packageDesc = packageDesc - self.patchMaker = patchMaker - self.contentsDocPackage = xpackage - self.patchVersion = 1 - self.currentPv = None - self.basePv = None - self.topPv = None - - self.packageName = None - self.platform = None - self.version = None - self.hostUrl = None - self.currentFile = None - self.baseFile = None - - self.doc = None - self.anyChanges = False - self.patches = [] - - def getCurrentKey(self): - """ Returns the key to locate the current version of this - package. """ - - return (self.packageName, self.platform, self.version, self.hostUrl, self.currentFile) - - def getBaseKey(self): - """ Returns the key to locate the "base" or oldest version - of this package. """ - - return (self.packageName, self.platform, self.version, self.hostUrl, self.baseFile) - - def getTopKey(self): - """ Returns the key to locate the "top" or newest version - of this package. """ - - return (self.packageName, self.platform, self.version, self.hostUrl, self.topFile) - - def getGenericKey(self, fileSpec): - """ Returns the key that has the indicated hash. """ - return (self.packageName, self.platform, self.version, self.hostUrl, fileSpec) - - def readDescFile(self, doProcessing = False): - """ Reads the existing package.xml file and stores it in - this class for later rewriting. if doProcessing is true, - it may massage the file and the directory contents in - preparation for building patches. Returns true on - success, false on failure. """ - - self.anyChanges = False - - packageDescFullpath = Filename(self.patchMaker.installDir, self.packageDesc) - self.doc = TiXmlDocument(packageDescFullpath.toOsSpecific()) - if not self.doc.LoadFile(): - print("Couldn't read %s" % (packageDescFullpath)) - return False - - xpackage = self.doc.FirstChildElement('package') - if not xpackage: - return False - self.packageName = xpackage.Attribute('name') - self.platform = xpackage.Attribute('platform') - self.version = xpackage.Attribute('version') - - # All packages we defined in-line are assigned to the - # "none" host. TODO: support patching from packages on - # other hosts, which means we'll need to fill in a value - # here for those hosts. - self.hostUrl = None - - self.currentFile = None - self.baseFile = None - self.topFile = None - self.compressedFilename = None - compressedFile = None - - # Assume there are changes for this version, until we - # discover that there aren't. - isNewVersion = True - - # Get the actual current version. - xarchive = xpackage.FirstChildElement('uncompressed_archive') - if xarchive: - self.currentFile = FileSpec() - self.currentFile.loadXml(xarchive) - - # Get the top_version--the top (newest) of the patch - # chain. - xarchive = xpackage.FirstChildElement('top_version') - if xarchive: - self.topFile = FileSpec() - self.topFile.loadXml(xarchive) - - if self.topFile.hash == self.currentFile.hash: - # No new version this pass. - isNewVersion = False - else: - # There's a new version this pass. Update it. - self.anyChanges = True - - else: - # If there isn't a top_version yet, we have to make - # one, by duplicating the currentFile. - self.topFile = copy.copy(self.currentFile) - self.anyChanges = True - - # Get the current patch version. If we have a - # patch_version attribute, it refers to this particular - # instance of the file, and that is the current patch - # version number. If we only have a last_patch_version - # attribute, it means a patch has not yet been built for - # this particular instance, and that number is the - # previous version's patch version number. - patchVersion = xpackage.Attribute('patch_version') - if patchVersion: - self.patchVersion = int(patchVersion) - else: - patchVersion = xpackage.Attribute('last_patch_version') - if patchVersion: - self.patchVersion = int(patchVersion) - if isNewVersion: - self.patchVersion += 1 - self.anyChanges = True - - # Put the patchVersion in the compressed filename, for - # cache-busting. This means when the version changes, its - # URL will also change, guaranteeing that users will - # download the latest version, and not some stale cache - # file. - xcompressed = xpackage.FirstChildElement('compressed_archive') - if xcompressed: - compressedFile = FileSpec() - compressedFile.loadXml(xcompressed) - - oldCompressedFilename = compressedFile.filename - self.compressedFilename = oldCompressedFilename - - if doProcessing: - newCompressedFilename = '%s.%s.pz' % (self.currentFile.filename, self.patchVersion) - if newCompressedFilename != oldCompressedFilename: - oldCompressedPathname = Filename(self.packageDir, oldCompressedFilename) - newCompressedPathname = Filename(self.packageDir, newCompressedFilename) - if oldCompressedPathname.renameTo(newCompressedPathname): - compressedFile.fromFile(self.packageDir, newCompressedFilename) - compressedFile.storeXml(xcompressed) - - self.compressedFilename = newCompressedFilename - self.anyChanges = True - - # Get the base_version--the bottom (oldest) of the patch - # chain. - xarchive = xpackage.FirstChildElement('base_version') - if xarchive: - self.baseFile = FileSpec() - self.baseFile.loadXml(xarchive) - else: - # If there isn't a base_version yet, we have to make - # one, by duplicating the currentFile. - self.baseFile = copy.copy(self.currentFile) - - # Note that the we only store the compressed version - # of base_filename on disk, but we store the md5 of - # the uncompressed version in the xml file. To - # emphasize this, we name it without the .pz extension - # in the xml file, even though the compressed file on - # disk actually has a .pz extension. - self.baseFile.filename += '.base' - - # Also duplicate the (compressed) file itself. - if doProcessing and self.compressedFilename: - fromPathname = Filename(self.packageDir, self.compressedFilename) - toPathname = Filename(self.packageDir, self.baseFile.filename + '.pz') - fromPathname.copyTo(toPathname) - self.anyChanges = True - - self.patches = [] - xpatch = xpackage.FirstChildElement('patch') - while xpatch: - patchfile = PatchMaker.Patchfile(self) - patchfile.loadXml(xpatch) - self.patches.append(patchfile) - xpatch = xpatch.NextSiblingElement('patch') - - return True - - def writeDescFile(self): - """ Rewrites the desc file with the new patch - information. """ - - if not self.anyChanges: - # No need to rewrite. - return - - xpackage = self.doc.FirstChildElement('package') - if not xpackage: - return - - packageSeq = SeqValue() - packageSeq.loadXml(xpackage, 'seq') - packageSeq += 1 - packageSeq.storeXml(xpackage, 'seq') - - # Remove all of the old patch entries from the desc file - # we read earlier. - xremove = [] - for value in ['base_version', 'top_version', 'patch']: - xpatch = xpackage.FirstChildElement(value) - while xpatch: - xremove.append(xpatch) - xpatch = xpatch.NextSiblingElement(value) - - for xelement in xremove: - xpackage.RemoveChild(xelement) - - xpackage.RemoveAttribute('last_patch_version') - - # Now replace them with the current patch information. - xpackage.SetAttribute('patch_version', str(self.patchVersion)) - - xarchive = TiXmlElement('base_version') - self.baseFile.storeXml(xarchive) - xpackage.InsertEndChild(xarchive) - - # The current version is now the top version. - xarchive = TiXmlElement('top_version') - self.currentFile.storeXml(xarchive) - xpackage.InsertEndChild(xarchive) - - for patchfile in self.patches: - xpatch = patchfile.makeXml(self) - xpackage.InsertEndChild(xpatch) - - self.doc.SaveFile() - - # Also copy the seq to the import desc file, for - # documentation purposes. - - importDescFilename = str(self.packageDesc)[:-3] + 'import.xml' - importDescFullpath = Filename(self.patchMaker.installDir, importDescFilename) - doc = TiXmlDocument(importDescFullpath.toOsSpecific()) - if doc.LoadFile(): - xpackage = doc.FirstChildElement('package') - if xpackage: - packageSeq.storeXml(xpackage, 'seq') - doc.SaveFile() - else: - print("Couldn't read %s" % (importDescFullpath)) - - if self.contentsDocPackage: - # Now that we've rewritten the xml file, we have to - # change the contents.xml file that references it to - # indicate the new file hash. - fileSpec = FileSpec() - fileSpec.fromFile(self.patchMaker.installDir, self.packageDesc) - fileSpec.storeXml(self.contentsDocPackage) - - # Also important to update the import.xml hash. - ximport = self.contentsDocPackage.FirstChildElement('import') - if ximport: - fileSpec = FileSpec() - fileSpec.fromFile(self.patchMaker.installDir, importDescFilename) - fileSpec.storeXml(ximport) - - # Also copy the package seq value into the - # contents.xml file, mainly for documentation purposes - # (the authoritative seq value is within the desc - # file). - packageSeq.storeXml(self.contentsDocPackage, 'seq') - - - # PatchMaker constructor. - def __init__(self, installDir): - self.installDir = installDir - self.packageVersions = {} - self.packages = [] - - def buildPatches(self, packageNames = None): - """ Makes the patches required in a particular directory - structure on disk. If packageNames is None, this makes - patches for all packages; otherwise, it should be a list of - package name strings, limiting the set of packages that are - processed. """ - - if not self.readContentsFile(): - return False - self.buildPatchChains() - if packageNames is None: - self.processAllPackages() - else: - self.processSomePackages(packageNames) - - self.writeContentsFile() - self.cleanup() - return True - - def cleanup(self): - """ Should be called on exit to remove temporary files and - such created during processing. """ - - for pv in self.packageVersions.values(): - pv.cleanup() - - def getPatchChainToCurrent(self, descFilename, fileSpec): - """ Reads the package defined in the indicated desc file, and - constructs a patch chain from the version represented by - fileSpec to the current version of this package, if possible. - Returns the patch chain if successful, or None otherwise. """ - - package = self.readPackageDescFile(descFilename) - if not package: - return None - - self.buildPatchChains() - fromPv = self.getPackageVersion(package.getGenericKey(fileSpec)) - toPv = package.currentPv - - patchChain = None - if toPv and fromPv: - patchChain = toPv.getPatchChain(fromPv) - - return patchChain - - def readPackageDescFile(self, descFilename): - """ Reads a desc file associated with a particular package, - and adds the package to self.packages. Returns the Package - object, or None on failure. """ - - package = self.Package(Filename(descFilename), self) - if not package.readDescFile(doProcessing = False): - return None - - self.packages.append(package) - return package - - def readContentsFile(self): - """ Reads the contents.xml file at the beginning of - processing. """ - - contentsFilename = Filename(self.installDir, 'contents.xml') - doc = TiXmlDocument(contentsFilename.toOsSpecific()) - if not doc.LoadFile(): - # Couldn't read file. - print("couldn't read %s" % (contentsFilename)) - return False - - xcontents = doc.FirstChildElement('contents') - if xcontents: - contentsSeq = SeqValue() - contentsSeq.loadXml(xcontents) - contentsSeq += 1 - contentsSeq.storeXml(xcontents) - - xpackage = xcontents.FirstChildElement('package') - while xpackage: - solo = xpackage.Attribute('solo') - solo = int(solo or '0') - filename = xpackage.Attribute('filename') - if filename and not solo: - filename = Filename(filename) - package = self.Package(filename, self, xpackage) - package.readDescFile(doProcessing = True) - self.packages.append(package) - - xpackage = xpackage.NextSiblingElement('package') - - self.contentsDoc = doc - - return True - - def writeContentsFile(self): - """ Writes the contents.xml file at the end of processing. """ - - # We also have to write the desc file for all packages that - # might need it, because we might have changed some of them on - # read. - for package in self.packages: - package.writeDescFile() - - # The above writeDescFile() call should also update each - # package's element within the contents.xml document, so all - # we have to do now is write out the document. - self.contentsDoc.SaveFile() - - def getPackageVersion(self, key): - """ Returns a shared PackageVersion object for the indicated - key. """ - - packageName, platform, version, hostUrl, file = key - - # We actually key on the hash, not the FileSpec itself. - k = (packageName, platform, version, hostUrl, file.hash) - pv = self.packageVersions.get(k, None) - if not pv: - pv = self.PackageVersion(*key) - self.packageVersions[k] = pv - return pv - - def buildPatchChains(self): - """ Builds up the chains of PackageVersions and the patchfiles - that connect them. """ - - self.patchFilenames = {} - - for package in self.packages: - if not package.baseFile: - # This package doesn't have any versions yet. - continue - - currentPv = self.getPackageVersion(package.getCurrentKey()) - package.currentPv = currentPv - currentPv.packageCurrent = package - currentPv.printName = package.currentFile.filename - - basePv = self.getPackageVersion(package.getBaseKey()) - package.basePv = basePv - basePv.packageBase = package - basePv.printName = package.baseFile.filename - - topPv = self.getPackageVersion(package.getTopKey()) - package.topPv = topPv - topPv.packageTop = package - - for patchfile in package.patches: - self.recordPatchfile(patchfile) - - def recordPatchfile(self, patchfile): - """ Adds the indicated patchfile to the patch chains. """ - self.patchFilenames[patchfile.file.filename] = patchfile - - fromPv = self.getPackageVersion(patchfile.getSourceKey()) - patchfile.fromPv = fromPv - fromPv.toPatches.append(patchfile) - - toPv = self.getPackageVersion(patchfile.getTargetKey()) - patchfile.toPv = toPv - toPv.fromPatches.append(patchfile) - toPv.printName = patchfile.file.filename - - def processSomePackages(self, packageNames): - """ Builds missing patches only for the named packages. """ - - remainingNames = packageNames[:] - for package in self.packages: - if package.packageName in packageNames: - self.processPackage(package) - if package.packageName in remainingNames: - remainingNames.remove(package.packageName) - - if remainingNames: - print("Unknown packages: %s" % (remainingNames,)) - - def processAllPackages(self): - """ Walks through the list of packages, and builds missing - patches for each one. """ - - for package in self.packages: - self.processPackage(package) - - def processPackage(self, package): - """ Builds missing patches for the indicated package. """ - - if not package.baseFile: - # No versions. - return - - # What's the current version on the top of the tree? - topPv = package.topPv - currentPv = package.currentPv - - if topPv != currentPv: - # They're different, so build a new patch. - filename = Filename(package.currentFile.filename + '.%s.patch' % (package.patchVersion)) - assert filename not in self.patchFilenames - if not self.buildPatch(topPv, currentPv, package, filename): - raise Exception("Couldn't build patch.") - - def buildPatch(self, v1, v2, package, patchFilename): - """ Builds a patch from PackageVersion v1 to PackageVersion - v2, and stores it in patchFilename.pz. Returns true on - success, false on failure.""" - - pathname = Filename(package.packageDir, patchFilename) - if not self.buildPatchFile(v1.getFile(), v2.getFile(), pathname, - v1.printName, v2.printName): - return False - - compressedPathname = Filename(pathname + '.pz') - compressedPathname.unlink() - if not compressFile(pathname, compressedPathname, 9): - raise Exception("Couldn't compress patch.") - pathname.unlink() - - patchfile = self.Patchfile(package) - patchfile.fromFile(package.packageDir, patchFilename + '.pz', - v1.file, v2.file) - package.patches.append(patchfile) - package.anyChanges = True - - self.recordPatchfile(patchfile) - - return True - - def buildPatchFile(self, origFilename, newFilename, patchFilename, - printOrigName, printNewName): - """ Creates a patch file from origFilename to newFilename, - storing the result in patchFilename. Returns true on success, - false on failure. """ - - if not origFilename.exists(): - # No original version to patch from. - return False - - print("Building patch from %s to %s" % (printOrigName, printNewName)) - patchFilename.unlink() - p = Patchfile() # The C++ class - if p.build(origFilename, newFilename, patchFilename): - return True - - # Unable to build a patch for some reason. - patchFilename.unlink() - return False diff --git a/direct/src/p3d/ScanDirectoryNode.py b/direct/src/p3d/ScanDirectoryNode.py deleted file mode 100644 index 429b8f0fd2..0000000000 --- a/direct/src/p3d/ScanDirectoryNode.py +++ /dev/null @@ -1,95 +0,0 @@ -__all__ = ["ScanDirectoryNode"] - -from panda3d.core import VirtualFileSystem, VirtualFileMountSystem, Filename, TiXmlDocument -vfs = VirtualFileSystem.getGlobalPtr() - -class ScanDirectoryNode: - """ This class is used to scan a list of files on disk. """ - - def __init__(self, pathname, ignoreUsageXml = False): - self.pathname = pathname - self.filenames = [] - self.fileSize = 0 - self.nested = [] - self.nestedSize = 0 - - xusage = None - if not ignoreUsageXml: - # Look for a usage.xml file in this directory. If we find - # one, we read it for the file size and then stop here, as - # an optimization. - usageFilename = Filename(pathname, 'usage.xml') - doc = TiXmlDocument(usageFilename.toOsSpecific()) - if doc.LoadFile(): - xusage = doc.FirstChildElement('usage') - if xusage: - diskSpace = xusage.Attribute('disk_space') - try: - diskSpace = int(diskSpace or '') - except ValueError: - diskSpace = None - if diskSpace is not None: - self.fileSize = diskSpace - return - - files = vfs.scanDirectory(self.pathname) - if files is None: - files = [] - for vfile in files: - if hasattr(vfile, 'getMount'): - if not isinstance(vfile.getMount(), VirtualFileMountSystem): - # Not a real file; ignore it. - continue - - if vfile.isDirectory(): - # A nested directory. - subdir = ScanDirectoryNode(vfile.getFilename(), ignoreUsageXml = ignoreUsageXml) - self.nested.append(subdir) - self.nestedSize += subdir.getTotalSize() - - elif vfile.isRegularFile(): - # A nested file. - self.filenames.append(vfile.getFilename()) - self.fileSize += vfile.getFileSize() - - else: - # Some other wacky file thing. - self.filenames.append(vfile.getFilename()) - - if xusage: - # Now update the usage.xml file with the newly-determined - # disk space. - xusage.SetAttribute('disk_space', str(self.getTotalSize())) - tfile = Filename.temporary(str(pathname), '.xml') - if doc.SaveFile(tfile.toOsSpecific()): - tfile.renameTo(usageFilename) - - def getTotalSize(self): - return self.nestedSize + self.fileSize - - def extractSubdir(self, pathname): - """ Finds the ScanDirectoryNode within this node that - corresponds to the indicated full pathname. If it is found, - removes it from its parent, and returns it. If it is not - found, returns None. """ - - # We could be a little smarter here, but why bother. Just - # recursively search all children. - for subdir in self.nested: - if subdir.pathname == pathname: - self.nested.remove(subdir) - self.nestedSize -= subdir.getTotalSize() - return subdir - - result = subdir.extractSubdir(pathname) - if result: - self.nestedSize -= result.getTotalSize() - if subdir.getTotalSize() == 0: - # No other files in the subdirectory that contains - # this package; remove it too. - self.nested.remove(subdir) - return result - - return None - - diff --git a/direct/src/p3d/SeqValue.py b/direct/src/p3d/SeqValue.py deleted file mode 100644 index 958132f74b..0000000000 --- a/direct/src/p3d/SeqValue.py +++ /dev/null @@ -1,90 +0,0 @@ -__all__ = ["SeqValue"] - -class SeqValue: - - """ This represents a sequence value read from a contents.xml - file, either from the or the section. It's - represented as series of dotted integers in the xml file, and - stored internally as a tuple of integers. - - It may be incremented, which increments only the last integer in - the series; or it may be compared with another SeqValue, which - compares all of the integers componentwise. """ - - def __init__(self, value = None): - self.value = () - if value is not None: - self.set(value) - - def set(self, value): - """ Sets the seq from the indicated value of unspecified - type. """ - if isinstance(value, tuple): - self.setFromTuple(value) - elif isinstance(value, str): - self.setFromString(value) - else: - raise TypeError('Invalid sequence type: %s' % (value,)) - - def setFromTuple(self, value): - """ Sets the seq from the indicated tuple of integers. """ - assert isinstance(value, tuple) - self.value = value - - def setFromString(self, value): - """ Sets the seq from the indicated string of dot-separated - integers. Raises ValueError on error. """ - assert isinstance(value, str) - - self.value = () - if value: - value = value.split('.') - value = map(int, value) - self.value = tuple(value) - - def loadXml(self, xelement, attribute = 'seq'): - """ Reads the seq from the indicated XML element. Returns - true if loaded, false if not given or if there was an - error. """ - - self.value = () - value = xelement.Attribute(attribute) - if value: - try: - self.setFromString(value) - except ValueError: - return False - return True - - return False - - - def storeXml(self, xelement, attribute = 'seq'): - """ Adds the seq to the indicated XML element. """ - if self.value: - value = '.'.join(map(str, self.value)) - xelement.SetAttribute(attribute, value) - - def __add__(self, inc): - """ Increments the seq value, returning the new value. """ - if not self.value: - value = (1,) - else: - value = self.value[:-1] + (self.value[-1] + inc,) - return SeqValue(value) - - def __cmp__(self, other): - """ Compares to another seq value. """ - return cmp(self.value, other.value) - - def __lt__(self, other): - return self.value < other.value - - def __gt__(self, other): - return self.value > other.value - - def __bool__(self): - return bool(self.value) - - def __str__(self): - return 'SeqValue%s' % (repr(self.value)) diff --git a/direct/src/p3d/__init__.py b/direct/src/p3d/__init__.py deleted file mode 100644 index e6ab93b09d..0000000000 --- a/direct/src/p3d/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -""" -This package provides the Python interface to functionality relating to -the Panda3D Runtime environment. -""" diff --git a/direct/src/p3d/coreapi.pdef b/direct/src/p3d/coreapi.pdef deleted file mode 100644 index 03612be605..0000000000 --- a/direct/src/p3d/coreapi.pdef +++ /dev/null @@ -1,124 +0,0 @@ -from panda3d.core import getModelPath, Filename, ConfigVariableFilename, DSearchPath, ExecutionEnvironment, PandaSystem - -# This file defines a number of standard "packages" that correspond to -# a Panda3D distribution. These packages are built by passing this -# file to the ppackage utility, either as a packaged application, or -# as the module direct.p3d.ppackage. - -# The packages in this file define the "Core API". This is the second -# installed piece of the three-part plugin system (the plugin, the -# core API, Panda3D). - -# These packages are downloaded directly by the plugin, from the host -# specified by the value of PANDA_PACKAGE_HOST_URL compiled into the -# plugin. Thus, these packages are inextricably tied to the -# particular plugin they have been built with. They do not have to be -# present on a server that hosts a version of Panda3D for download, -# just on the server that hosts the plugin itself. These packages do -# not need to be updated with each new version of Panda3D. - -# Also see panda3d.pdef. - -class coreapi(solo): - # The special "coreapi" package. As a "solo", this is just a - # single .dll (or dylib, or whatever). - setVer(PandaSystem.getP3dCoreapiVersionString()) - file('p3d_plugin.dll') - -class images(package): - # The default startup images are stored as their own package. - names = ['download', 'failed', 'play_click', 'play_ready', 'play_rollover', - 'auth_click', 'auth_ready', 'auth_rollover'] - configDict = {} - - # Construct a search path to look for the images. - search = DSearchPath() - - # First on the path: an explicit $PLUGIN_IMAGES env var. - if ExecutionEnvironment.hasEnvironmentVariable('PLUGIN_IMAGES'): - search.appendDirectory(Filename.expandFrom('$PLUGIN_IMAGES')) - - # Next on the path: the models/plugin_images directory within the - # current directory. - search.appendDirectory('models/plugin_images') - - # Finally on the path: models/plugin_images within the model - # search path. - for dir in getModelPath().getDirectories(): - search.appendDirectory(Filename(dir, 'plugin_images')) - - for name in names: - # Look for a png image first. - basename = '%s.png' % (name) - filename = Filename(basename) - found = filename.resolveFilename(search) - if not found: - # Then try a jpeg image. - basename = '%s.jpg' % (name) - filename = Filename(basename) - found = filename.resolveFilename(search) - - if found: - # Add the image file to the package - file(filename, newName = basename, extract = True) - - # And set the config variable to reference it. - token = '%s_img' % (name) - configDict[token] = basename - else: - print("Could not locate %s" % (filename)) - - # Also make a few special cases. We use the same default image - # for many of the states. - download = configDict.get('download_img', None) - if download: - configDict['ready_img'] = download - configDict['unauth_img'] = download - configDict['launch_img'] = download - configDict['active_img'] = download - - config(**configDict) - -class certlist(package): - # This package holds any certificates that should be considered - # pre-approved by the plugin vendor. If you build and host your - # own version of the Panda3D plugin, you can add your own - # certificates to this list. The certificates in this package - # will be assumed to have been approved by the user when he/she - # installed the plugin. - - # They should be PEM-encoded and their filenames must end in the - # ".pem" or ".crt" extension, and they should be added with the - # extract = True flag so they will be extracted to disk. - pass - - -class p3dcert(package): - # This special application, used to pop up a dialog to prompt the - # user to accept or deny unknown applications, is its own package. - config(display_name = "Authorization Dialog") - - if platform.startswith('osx'): - # On Mac, we package up a P3DCert.app bundle. This includes - # specifications in the plist file to avoid creating a dock - # icon and stuff. - - # Find p3dcert.plist in the direct source tree. - import direct - plist = Filename(direct.__path__[0], 'plugin/p3dcert.plist') - makeBundle('P3DCert.app', plist, executable = 'p3dcert') - - else: - # Anywhere else, we just ship the executable file p3dcert.exe. - file('p3dcert.exe', required = True) - - -class p3dembed(package): - # This contains the p3dembed executable, that is used by - # pdeploy to generate a self-extracting .p3d executable. - - config(platform_specific = True) - file('p3dembed.exe', required = True) - - if platform.startswith('win'): - file('p3dembedw.exe', required = True) diff --git a/direct/src/p3d/p3dWrapper.c b/direct/src/p3d/p3dWrapper.c deleted file mode 100644 index ef96e036f9..0000000000 --- a/direct/src/p3d/p3dWrapper.c +++ /dev/null @@ -1,127 +0,0 @@ -/* Filename: p3dWrapper.c - * Created by: rdb (16Jan10) - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* p3dWrapper is a small wrapper executable that locates a .p3d file - in the same directory as this executable file, with the same name - (except .p3d instead of .exe of course). It is only meant to be - used on Windows system, it is not needed on Unix-like systems. */ - -#include -#include -#include -#include -#include -#include -#include - -#define BUFFER_SIZE 1024 - -/* It makes sense to use "App Paths\panda3d.exe". However, Microsoft - decided in their infinite wisdom to disable Redirection for that - key from Windows 7 onward, so we can't rely on it producing a - result appropriate to the right architecture when both the 32-bit - and 64-bit versions of the runtime are installed. Beh. */ - -#define UNINST_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Panda3D Game Engine" - -int main (int argc, char* argv[]) { - int i; - char buffer[BUFFER_SIZE]; - char* p3dfile; - char* runtime = NULL; - DWORD size; - STARTUPINFO si; - PROCESS_INFORMATION pi; - char *cmd; - char *newcmd; - HKEY hKey = 0; - char buf[1024] = {0}; - DWORD dwType = REG_SZ; - DWORD dwBufSize = sizeof(buf); - size = GetModuleFileName(NULL, buffer, BUFFER_SIZE); - assert (size > 0); - - /* Chop off the .exe and replace it by .p3d. */ - p3dfile = (char*) _alloca(size + 1); - memcpy(p3dfile, buffer, size); - p3dfile[size] = 0; - memcpy(p3dfile + size - 3, "p3d", 3); - - /* Find the location of panda3d.exe using the registry path. */ -#ifdef _WIN64 - /* If we're on 64-bit Windows, try the 64-bit registry first. */ - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, UNINST_KEY, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS) { - if (RegQueryValueEx(hKey, "DisplayIcon", 0, &dwType, (BYTE*) buf, &dwBufSize) == ERROR_SUCCESS) { - char *slash = strrchr(buf, '\\'); - if (slash != NULL) { - strcpy(slash, "\\panda3d.exe"); - runtime = buf; - } - } - RegCloseKey(hKey); - } -#endif - - /* On 32-bit Windows, or no 64-bit Runtime installed. Try 32-bit registry. */ - if (runtime == NULL) { - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, UNINST_KEY, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS) { - if (RegQueryValueEx(hKey, "DisplayIcon", 0, &dwType, (BYTE*) buf, &dwBufSize) == ERROR_SUCCESS) { - char *slash = strrchr(buf, '\\'); - if (slash != NULL) { - strcpy(slash, "\\panda3d.exe"); - runtime = buf; - } - } - RegCloseKey(hKey); - } - } - - /* Backward compatibility: Runtime 1.0.4 and below looked for the below key, even though the - above keys should work fine, but let's just be certain. - Find the Panda3D applet\DefaultIcon key and extract the path to the runtime from there. */ - if (runtime == NULL) { - if (RegOpenKey(HKEY_CLASSES_ROOT, "Panda3D applet\\DefaultIcon", &hKey) == ERROR_SUCCESS) { - if (RegQueryValueEx(hKey, 0, 0, &dwType, (BYTE*) buf, &dwBufSize) == ERROR_SUCCESS) { - char *slash = strrchr(buf, '\\'); - if (slash != NULL) { - strcpy(slash, "\\panda3d.exe"); - runtime = buf; - } - } else { - fprintf(stderr, "Failed to read registry key. Try reinstalling the Panda3D Runtime.\n"); - return 1; - } - RegCloseKey(hKey); - } else { - fprintf(stderr, "The Panda3D Runtime does not appear to be installed!\n"); - return 1; - } - } - - if (runtime == NULL) { - fprintf(stderr, "Failed to find panda3d.exe in registry. Try reinstalling the Panda3D Runtime.\n"); - return 1; - } - - /* Build the command-line and run panda3d.exe. */ - cmd = GetCommandLine(); - newcmd = (char*) _alloca(strlen(runtime) + strlen(p3dfile) + strlen(cmd) - strlen (argv[0]) + 7); - sprintf(newcmd, "\"%s\" \"%s\" %s", runtime, p3dfile, cmd + strlen(argv[0])); - memset(&si, 0, sizeof(si)); - si.cb = sizeof(STARTUPINFO); - if (CreateProcess(runtime, newcmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { - WaitForSingleObject(pi.hProcess, INFINITE); - } - return 0; -} diff --git a/direct/src/p3d/packp3d.py b/direct/src/p3d/packp3d.py deleted file mode 100755 index dee4fa2656..0000000000 --- a/direct/src/p3d/packp3d.py +++ /dev/null @@ -1,241 +0,0 @@ -#! /usr/bin/env python - -usageText = """ - -This command will pack a Panda application, consisting of a directory -tree of .py files and models, into a p3d file for convenient -distribution. The resulting p3d file can be run by the Panda3D -runtime executable, or by the Panda3D web browser plugin. - -This command will build p3d files that reference Panda3D %s, -from host %s . - -Also see ppackage, a more powerful (but more complex) tool that can -also be used to build p3d applications, using a pdef description file. - -Usage: - - %s [opts] -o app.p3d - -Options: - - -o app.p3d - Specify the name of the p3d file to generate. This is required. - - -d application_root - Specify the root directory of the application source; this is a - directory tree that contains all of your .py files and models. - If this is omitted, the default is the current directory. - - -m main.py - Names the Python file that begins the application. This should - be a file within the root directory. If this is omitted, the - default is a file named "main.py", or if there is only one Python - file present, it is used. If this file contains a function - called main(), that function will be called after importing it - (this is preferable to having the module start itself immediately - upon importing). - - -S file.crt[,chain.crt[,file.key[,\"password\"]]] - Signs the resulting p3d with the indicated certificate. You may - specify the signing certificate, the optional authorization - chain, and the private key in three different files, or they may - all be combined in the first file. If the private key is - encrypted, the password will be required to decrypt it. - - -e ext - Adds a new extension to be processed as a generic, compressible - file type. Do not include the leading dot. Files matching this - extension found within the root directory will be automatically - added to the p3d file, in compressed form. This option may be - repeated as necessary. - - -n ext - Adds a new extension to be processed as a noncompressible file - type. Files matching this extension will be added to the p3d - file, in their original, uncompressed form. You should use this - instead of -e for files that are uncompressible by their nature - (e.g. mpg files). This option may be repeated as necessary. - - -x ext - Marks files with the given extensions of needing to be physically - extracted to disk before they can be loaded. This is used for - file types that cannot be loaded via the virtual file system, - such as .ico files on Windows. - This option is currently only implemented when deploying the - application with pdeploy. - - -p python_lib_dir - Adds a directory to search for additional Python modules. You - can use this to add your system's Python path, to allow packp3d - to find any system modules not included in the standard Panda3D - release, but your version of Python must match this one (%s). - This option may be repeated to add multiple directories. - - -c config=value - Sets the indicated config flag in the application. This option - may be repeated as necessary. - - -r package[,version[,hostURL]] - Names an additional package that this application requires at - startup time. The default package is 'panda3d'; you may repeat - this option to indicate dependencies on additional packages. - - -s search_dir - Additional directories to search for previously-built packages. - This option may be repeated as necessary. These directories may - also be specified with the pdef-path Config.prc variable. - - -D - Sets the allow_python_dev flag in the application. This enables - additional runtime debug operations, particularly the -i option - to the panda3d command, which enables a live Python prompt within - the application's environment. Setting this flag may be useful - to develop an application initially, but should not be set on an - application intended for deployment. - -""" - -import sys -import os -import getopt -import glob -from direct.p3d import Packager -from panda3d.core import * - -# Temp hack for debugging. -#from direct.p3d.AppRunner import dummyAppRunner; dummyAppRunner() - -class ArgumentError(Exception): - pass - -def makePackedApp(args): - opts, args = getopt.getopt(args, 'o:d:m:S:e:n:x:p:c:r:s:Dh') - - packager = Packager.Packager() - - appFilename = None - root = Filename('.') - main = None - configFlags = [] - requires = [] - allowPythonDev = False - - for option, value in opts: - if option == '-o': - appFilename = Filename.fromOsSpecific(value) - elif option == '-d': - root = Filename.fromOsSpecific(value) - elif option == '-m': - main = value - elif option == '-S': - tokens = value.split(',') - while len(tokens) < 4: - tokens.append('') - certificate, chain, pkey, password = tokens[:4] - packager.signParams.append((Filename.fromOsSpecific(certificate), - Filename.fromOsSpecific(chain), - Filename.fromOsSpecific(pkey), - Filename.fromOsSpecific(password))) - elif option == '-e': - packager.binaryExtensions.append(value) - elif option == '-n': - packager.uncompressibleExtensions.append(value) - elif option == '-x': - packager.extractExtensions.append(value) - elif option == '-p': - sys.path.append(value) - elif option == '-c': - configFlags.append(value.split('=', 1)) - elif option == '-r': - tokens = value.split(',') - while len(tokens) < 3: - tokens.append('') - name, version, host = tokens[:3] - requires.append((name, version, host)) - elif option == '-s': - packager.installSearch.append(Filename.fromOsSpecific(value)) - elif option == '-D': - allowPythonDev = True - elif option == '-h': - print(usageText % ( - PandaSystem.getPackageVersionString(), - PandaSystem.getPackageHostUrl(), - os.path.split(sys.argv[0])[1], - '%s.%s' % (sys.version_info[0], sys.version_info[1]))) - sys.exit(0) - - if not appFilename: - raise ArgumentError("No target app specified. Use:\n %s -o app.p3d\nUse -h to get more usage information." % (os.path.split(sys.argv[0])[1])) - - if args: - raise ArgumentError("Extra arguments on command line.") - - if appFilename.getExtension() != 'p3d': - raise ArgumentError('Application filename must end in ".p3d".') - - appDir = Filename(appFilename.getDirname()) - if not appDir: - appDir = Filename('.') - appBase = appFilename.getBasenameWoExtension() - - if main: - main = Filename.fromOsSpecific(main) - main.makeAbsolute(root) - else: - main = Filename(root, 'main.py') - if not main.exists(): - main = glob.glob(os.path.join(root.toOsSpecific(), '*.py')) - if len(main) == 0: - raise ArgumentError('No Python files in root directory.') - elif len(main) > 1: - raise ArgumentError('Multiple Python files in root directory; specify the main application with -m "main".') - - main = Filename.fromOsSpecific(os.path.split(main[0])[1]) - main.makeAbsolute(root) - - packager.installDir = appDir - packager.allowPythonDev = allowPythonDev - - # Put the root directory on the front of the model-path, so that - # any texture references in egg or bam files that reference - # textures from the top of the root directory will be properly - # resolved. - getModelPath().prependDirectory(root) - - try: - packager.setup() - packager.beginPackage(appBase, p3dApplication = True) - - # Pre-require panda3d, to give a less-confusing error message - # if one of our requirements pulls in a wrong version of - # panda3d. - if 'panda3d' not in [t[0] for t in requires]: - packager.do_require('panda3d') - - for name, version, host in requires: - packager.do_require(name, version = version, host = host) - - if configFlags: - packager.do_config(**dict(configFlags)) - - packager.do_dir(root) - packager.do_main(main) - packager.endPackage() - packager.close() - - except Packager.PackagerError: - # Just print the error message and exit gracefully. - inst = sys.exc_info()[1] - print(inst.args[0]) - sys.exit(1) - -try: - makePackedApp(sys.argv[1:]) -except ArgumentError as e: - print(e.args[0]) - sys.exit(1) - -# An explicit call to exit() is required to exit the program, when -# this module is packaged in a p3d file. -sys.exit(0) diff --git a/direct/src/p3d/panda3d.pdef b/direct/src/p3d/panda3d.pdef deleted file mode 100644 index 78e7af2cf0..0000000000 --- a/direct/src/p3d/panda3d.pdef +++ /dev/null @@ -1,518 +0,0 @@ -import sys -from panda3d.core import Filename, PandaSystem, getModelPath - -# This file defines a number of standard "packages" that correspond to -# a Panda3D distribution. These packages are built by passing this -# file to the ppackage utility, either as a packaged application, or -# as the module direct.p3d.ppackage. - -# The packages in this file define Panda3D itself. This is the third -# installed piece of the three-part plugin system (the plugin, the -# core API, Panda3D). - -# When needed, these packages are downloaded by the core API, from the -# host URL specified in a given p3d file, and not from any hardcoded -# URL. Thus, any custom version of Panda3D may be hosted on any -# server in the world, and any version of the plugin can download it. - -# Also see coreapi.pdef. - -class panda3d(package): - # The main Panda3D package. Contains Python and most of the graphics - # code in Panda3D. - - config(display_name = "Panda3D") - - # First, add the minimum startup files for a Panda3D package. - # These are files that the Panda3D runtime will explicitly look - # for by name in order to get itself bootstrapped. - setupPanda3D() - - # These are Python modules that are needed by most Panda3D - # applications. It doesn't matter too much if we miss one or two - # here, since any module imported by any of this code will - # automatically be included as well, and we end up with a pretty - # complete list that way. - module('direct.directbase.DirectStart', - # Don't want to include all files in direct.p3d, because - # that picks up the runtime scripts too, which are their - # own p3d files below. - 'direct.p3d.AppRunner', - 'direct.p3d.DWBPackageInstaller', - 'direct.actor.*', - 'direct.controls.*', - 'direct.directdevices.*', - 'direct.directnotify.*', - 'direct.directtools.*', - 'direct.directutil.*', - 'direct.distributed.*', - 'direct.filter.*', - 'direct.fsm.*', - 'direct.gui.*', - 'direct.interval.*', - 'direct.particles.*', - 'direct.showbase.*', - 'direct.showutil.*', - 'direct.stdpy.*', - 'direct.task.*') - - # Keep these modules for backward compatibility. - module('pandac.PandaModules', 'pandac.extension_native_helpers') - - module('panda3d.core', - 'panda3d.direct', - 'panda3d.fx', - 'panda3d.physics') - - # Include various standard Python encodings. The rest is in morepy. - module('encodings', 'encodings.aliases', 'encodings.undefined', - 'encodings.utf_8', 'encodings.ascii', 'encodings.mbcs', - 'encodings.latin_1', 'io') - if sys.version_info < (3, 0): - module('encodings.string_escape') - - # pandac.PandaModules pulls in other Panda3D libs automatically. - # Exclude these Panda3D libs; they are big and many applications don't - # use them. We define them as separate, optional packages, below, - # except for skel - this is useless in a shipped game anyways. - excludeModule('panda3d.egg') - excludeModule('panda3d.ode') - excludeModule('panda3d.bullet') - excludeModule('panda3d.vision') - excludeModule('panda3d.skel') - excludeModule('panda3d.physx') - excludeModule('panda3d.ai') - excludeModule('panda3d.vrpn') - - excludeModule('libpandaegg') - excludeModule('libpandaode') - excludeModule('libpandabullet') - excludeModule('libp3vision') - excludeModule('libpandaskel') - excludeModule('libpandaphysx') - excludeModule('libpandaai') - excludeModule('libp3vrpn') - - # Exclude these GUI toolkits; they're big, and many applications don't - # use them. We define them as separate, optional packages, below. - excludeModule('wx', - 'direct.showbase.WxGlobal') - - excludeModule('Tkinter', 'tkinter', 'Pmw', 'tkinter.simpledialog', - 'direct.showbase.TkGlobal', - 'direct.tkpanels', 'direct.tkwidgets', - 'tkCommonDialog', 'tkMessageBox', 'tkSimpleDialog') - - excludeModule('MySQLdb', 'MySQLdb.connections', 'MySQLdb.constants', - 'MySQLdb.converters', '_mysql') - - # Some code in distributed conditionally imports these. - excludeModule('otp.ai', 'otp.ai.AIZoneData') - - # Most of the core Panda3D DLL's will be included implicitly due to - # being referenced by the above Python code. Here we name a few more - # that are also needed, but aren't referenced by any code. Again, - # note that the .dll extension is automatically replaced with the - # platform-specific extension for an executable. - file('libpandagl.dll', 'libp3tinydisplay.dll') - if platform.startswith('win'): - file('libpandadx9.dll') - - # A basic config file is needed to lay some some fundamental runtime - # variables. - if platform.startswith('win'): - auxDisplays = """ -aux-display pandagl -aux-display pandadx9 -aux-display p3tinydisplay -""" - else: - auxDisplays = """ -aux-display pandagl -aux-display p3tinydisplay -""" - - file('Config.prc', extract = True, text = """ -plugin-path $PANDA3D_ROOT -default-model-extension .bam -cull-bin gui-popup 60 unsorted -""" + auxDisplays) - -class morepy(package): - # Additional Python modules provided by the standard Python - # library. Include this package to get the full suite of standard - # Python functionality. - - config(display_name = "Python standard library") - require('panda3d') - - module('string', 're', 'struct', 'difflib', - 'textwrap', 'codecs', 'unicodedata', 'stringprep', 'datetime', - 'calendar', 'collections', 'heapq', 'bisect', 'array', - 'sched', 'queue', 'weakref', 'types', 'copy', 'pprint', - 'numbers', 'math', 'cmath', 'decimal', 'fractions', - 'random', 'itertools', 'functools', 'operator', 'os.path', - 'fileinput', 'filecmp', 'tempfile', 'glob', 'fnmatch', 'linecache', - 'shutil', 'macpath', 'pickle', 'shelve', 'marshal', 'zlib', - 'gzip', 'bz2', 'zipfile', 'tarfile', 'csv', 'netrc', - 'xdrlib', 'plistlib', 'hashlib', 'hmac', 'os', - 'time', 'optparse', 'getopt', 'logging', 'logging.*') - module('getpass', 'curses', 'curses.textpad', 'curses.wrapper', - 'curses.ascii', 'curses.panel', 'platform', 'errno', - 'ctypes', 'select', 'threading', 'dummy_threading', 'dummy_thread', - 'multiprocessing', 'mmap', 'readline', 'rlcompleter', 'subprocess', - 'socket', 'ssl', 'signal', 'asyncore', 'asynchat', 'email', 'json', - 'mailcap', 'mailbox', 'mimetypes', 'base64', 'binhex', 'binascii', - 'quopri', 'uu', 'xml.parsers.expat', 'xml.dom', 'xml.dom.minidom', - 'xml.dom.pulldom', 'xml.sax', 'xml.sax.handler', - 'xml.sax.saxutils', 'xml.sax.xmlreader', - 'xml.etree.ElementTree', 'webbrowser', 'cgi', 'cgitb') - module('wsgiref', 'ftplib', 'poplib', 'imaplib', 'nntplib', 'smtplib', - 'smtpd', 'telnetlib', 'uuid', 'audioop', 'aifc', 'sunau', - 'wave', 'chunk', 'colorsys', 'imghdr', 'sndhdr', - 'ossaudiodev', 'gettext', 'locale', 'cmd', 'shlex', - 'pydoc', 'doctest', 'unittest', 'test', - 'bdb', 'pdb', 'timeit', 'trace', 'sys') - module('warnings', 'contextlib', 'abc', - 'atexit', 'traceback', '__future__', 'gc', 'inspect', - 'site', 'fpectl', 'code', 'codeop', 'zipimport', 'pkgutil', - 'modulefinder', 'runpy', 'parser', 'symtable', 'symbol', - 'token', 'keyword', 'tokenize', 'tabnanny', 'pyclbr', - 'py_compile', 'compileall', 'dis', 'pickletools', - 'distutils', 'msilib', 'msvcrt', 'winsound', 'posix', 'pwd', 'spwd', - 'grp', 'crypt', 'termios', 'tty', 'pty', 'fcntl', 'pipes', - 'resource', 'nis', 'syslog', 'ast') - - # Handle module name differences between Python 2 and Python 3 (see PEP3108) - if sys.version_info[0] < 3: - # Deprecated modules that were removed in Python 3 - module('posixfile', 'rfc822', 'mimetools','MimeWriter', 'mimify', - 'multifile', 'sets', 'md5', 'sha', 'imp', 'formatter') - # Mac-specific modules that were removed - module('autoGIL', 'ColorPicker', 'EasyDialogs', 'findertools', - 'FrameWork', 'ic', 'MacOS', 'macostools') - # Removed because they were hardly used - module('imputil', 'mutex', 'user', 'new') - # Removed because they were obsolete - module('Bastion', 'rexec', 'commands', 'dircache', 'dl', 'fpformat', - 'htmllib', 'imageop', 'mhlib', 'popen2', 'sgmllib', 'stat', - 'statvfs', 'thread', 'UserDict', 'UserList', 'UserString', - 'future_builtins', 'hotshot', 'bsddb') - # Renamed to fix PEP8 violations - module('_winreg', 'ConfigParser', 'copy_reg', 'SocketServer') - # C and Python implementations of the same interface were merged - module('cPickle', 'cStringIO', 'StringIO') - # Renamed because of poorly chosen names - module('repr', 'test.test_support', '__builtins__') - # Modules that got grouped under packages - module('anydbm', 'whichdb', 'dbm', 'dumbdbm', 'gdbm', 'dbhash') - module('HTMLParser', 'htmlentitydefs') - module('BaseHTTPServer', 'SimpleHTTPServer', 'cookielib', 'Cookie', - 'CGIHTTPServer', 'httplib') - module('urllib', 'urllib2', 'urlparse', 'robotparser') - module('xmlrpclib', 'SimpleXMLRPCServer', 'DocXMLRPCServer') - else: - # Renamed to fix PEP8 violations - module('winreg', 'configparser', 'copyreg', 'socketserver') - # Renamed because of poorly chosen names - module('reprlib', 'test.support', 'builtins') - # Modules that got grouped under packages - module('dbm') - module('html') - module('http') - module('urllib') - module('xmlrpc') - - # To add the multitude of standard Python string encodings. - module('encodings', 'encodings.*') - -class models(package): - # The standard models package. This is the contents of the - # "models" directory that ships with Panda; it includes a few - # default fonts, and some silly little sample models like smiley - # and teapot. - config(display_name = "Standard models") - - # We assign it the same version as the panda3d package. This - # would be assigned by default if we had a requirement on panda3d, - # but there's no real reason to declare that requirement. - config(version = PandaSystem.getPackageVersionString()) - - # Look for cmss12.egg on the model-path. Wherever this is found, - # we assume this is the models directory. - pathname = getModelPath().findFile('cmss12.egg') - if pathname: - dir(pathname.getDirname(), newDir = 'models') - - # Some people are used to loading the models without models/ prefix. - file('models.prc', extract = True, text = "model-path $MODELS_ROOT/models") - - -class fmod(package): - # This package includes the FMod audio library. This is - # full-featured and robust, but it is closed-source and the - # licensing is cost-free only for non-commercial products. - - config(display_name = "FMod audio library") - require('panda3d') - - file('libp3fmod_audio.dll', required = True) - - file('fmod.prc', extract = True, text = """ -plugin-path $FMOD_ROOT -audio-library-name p3fmod_audio -""") - -class openal(package): - # This package includes the OpenAL audio libraries. This is free - # in both senses, but there are some technical issues, especially - # on certain platforms. - - config(display_name = "OpenAL audio library") - require('panda3d') - - file('libp3openal_audio.dll', required = True) - file('OpenAL32.dll') - file('soft_oal.dll') - file('wrap_oal.dll') - - file('openal.prc', extract = True, text = """ -plugin-path $OPENAL_ROOT -audio-library-name p3openal_audio -""") - -class audio(package): - # This package includes the best audio library for the given - # platform, assuming a non-commercial application. - require('panda3d') - - # OpenAL seems to work pretty well universally now. - require('openal') - -class ffmpeg(package): - # This package includes the ffmpeg libraries and integration. - # It's a bit big, and is restricted by patents and the restrictive - # GPLv3 license, which is why it is included as a separate package. - - config(display_name = "FFMpeg multimedia decoder") - require('panda3d') - - file('libp3ffmpeg.dll', required = True) - - file('ffmpeg.prc', extract = True, text = """ -plugin-path $FFMPEG_ROOT -load-audio-type * p3ffmpeg -load-video-type * p3ffmpeg -""") - -class egg(package): - # This package contains the code for reading and operating on egg - # files and other model files. Since the Packager automatically - # converts egg files to bam files, this is not needed for most - # Panda3D applications. - - config(display_name = "Panda3D egg loader") - require('panda3d') - - module('panda3d.egg', required = True) - file('libpandaegg.dll', required = True) - file('libp3ptloader.dll', required = True) - - file('egg.prc', extract = True, text = """ -plugin-path $EGG_ROOT -load-file-type egg pandaegg -load-file-type p3ptloader - -# These are excerpted from the default Confauto.prc file. -egg-object-type-portal portal { 1 } -egg-object-type-polylight polylight { 1 } -egg-object-type-seq24 { 1 } fps { 24 } -egg-object-type-seq12 { 1 } fps { 12 } -egg-object-type-indexed indexed { 1 } -egg-object-type-seq10 { 1 } fps { 10 } -egg-object-type-seq8 { 1 } fps { 8 } -egg-object-type-seq6 { 1 } fps { 6 } -egg-object-type-seq4 { 1 } fps { 4 } -egg-object-type-seq2 { 1 } fps { 2 } - -egg-object-type-binary alpha { binary } -egg-object-type-dual alpha { dual } -egg-object-type-glass alpha { blend_no_occlude } - -egg-object-type-model { 1 } -egg-object-type-dcs { 1 } -egg-object-type-notouch { no_touch } - -egg-object-type-barrier { Polyset descend } -egg-object-type-sphere { Sphere descend } -egg-object-type-invsphere { InvSphere descend } -egg-object-type-tube { Tube descend } -egg-object-type-trigger { Polyset descend intangible } -egg-object-type-trigger-sphere { Sphere descend intangible } -egg-object-type-floor { Polyset descend level } -egg-object-type-dupefloor { Polyset keep descend level } -egg-object-type-bubble { Sphere keep descend } -egg-object-type-ghost collide-mask { 0 } -egg-object-type-glow blend { add } -egg-object-type-direct-widget collide-mask { 0x80000000 } { Polyset descend } -""") - -class ode(package): - # This package contains the code for the ODE integration. - # As not every application uses the ODE layers, and to cut down - # the download size, it is provided as separate package. - - config(display_name = "Panda3D Open Dynamics Engine integration") - require('panda3d') - - module('panda3d.ode', required = True) - file('libpandaode.dll', required = True) - -class bullet(package): - # This package contains the code for the Bullet integration. - # As not every application uses the Bullet layers, and to cut down - # the download size, it is provided as separate package. - - config(display_name = "Panda3D Bullet integration") - require('panda3d') - - module('panda3d.bullet', required = True) - file('libpandabullet.dll', required = True) - -class physx(package): - # This package contains the code for the NVIDIA PhysX integration. - # As not every application uses the NVIDIA PhysX layers, and to cut down - # the download size, it is provided as separate package. - - config(display_name = "Panda3D PhysX integration") - require('panda3d') - - module('panda3d.physx', required = True) - file('libpandaphysx.dll', required = True) - file('physxcudart_20.dll') - file('PhysXDevice.dll') - -class ai(package): - # This package contains the PandAI library for pathfinding - # and seek/flee behaviors. As some games may not need this - # functionality, it is provided as separate package to save - # on package download size. - - config(display_name = "Panda3D AI modules") - require('panda3d') - - module('panda3d.ai', required = True) - file('libpandaai.dll', required = True) - -class vision(package): - # This package contains the code for webcam support, augmented - # reality and computer vision. As many games will not need this - # functionality, it is provided as separate package to save - # on package download size. - - config(display_name = "Panda3D vision modules") - require('panda3d') - - module('panda3d.vision', required = True) - file('libp3vision.dll', required = True) - -class rocket(package): - # This package contains the code for libRocket integration. - # As not every application uses libRocket GUI, and to cut down - # the download size, it is provided as separate package. - - config(display_name = "Panda3D libRocket support") - require('panda3d') - - file('rocket.py', extract = True, text = """ -from _rocketcore import * -try: - from _rocketcontrols import * -except ImportError: - pass -""") - - module('panda3d.rocket', '_rocketcore', required = True) - module('_rocketcontrols') - file('libp3rocket.dll', required = True) - -class vrpn(package): - # This package contains the code for VRPN integration. - # Most applications don't use this, which is why it's separate. - - config(display_name = "Panda3D VRPN support") - require('panda3d') - - module('panda3d.vrpn', required = True) - file('libp3vrpn.dll', required = True) - - -class packp3d(p3d): - # This application is a command-line convenience for building a p3d - # application out of a directory hierarchy on disk. We build it here - # into its own p3d application, to allow end-users to easily build p3d - # applications using the appropriate version of Python and Panda for - # the targeted runtime. - - config(display_name = "Panda3D Application Packer", - hidden = True, platform_specific = False, - keep_user_env = True) - require('panda3d', 'egg') - - mainModule('direct.p3d.packp3d') - - file('packp3d.prc', extract = True, text = "preload-textures false") - - -class ppackage(p3d): - # As above, a packaging utility. This is the fully-general ppackage - # utility, which reads pdef files (like this one!) and creates one or - # more packages or p3d applications. - - config(display_name = "Panda3D General Package Utility", - hidden = True, platform_specific = False, - keep_user_env = True) - require('panda3d', 'egg') - - mainModule('direct.p3d.ppackage') - - file('ppackage.prc', extract = True, text = "preload-textures false") - - -class ppatcher(p3d): - # A handy utility to go along with ppackage. This builds - # patchfiles as needed in the directory structure created by - # ppackage. - - config(display_name = "Panda3D Patch Maker", - hidden = True, platform_specific = False, - keep_user_env = True) - require('panda3d') - - mainModule('direct.p3d.ppatcher') - - -class pmerge(p3d): - # Another handy utility to go along with ppackage. This - # merges multiple directory structures as created by - # ppackage into a single one. - - config(display_name = "Panda3D Package Merger", - hidden = True, platform_specific = False, - keep_user_env = True) - require('panda3d') - - mainModule('direct.p3d.pmerge') - - -class pdeploy(p3d): - # This utility can distribute a game in the form of - # a standalone executable or a graphical installer. - - config(display_name = "Panda3D Deployment Tool", - hidden = True, platform_specific = False, - keep_user_env = True) - require('panda3d', 'morepy') - - mainModule('direct.p3d.pdeploy') - diff --git a/direct/src/p3d/pdeploy.py b/direct/src/p3d/pdeploy.py deleted file mode 100644 index f98d10b65d..0000000000 --- a/direct/src/p3d/pdeploy.py +++ /dev/null @@ -1,359 +0,0 @@ -#! /usr/bin/env python - -usageText = """ - -This command will help you to distribute your Panda application, -consisting of a .p3d package, into a standalone executable, graphical -installer or an HTML webpage. It will attempt to create packages -for every platform, if possible. -Note that pdeploy requires an internet connection to run. - -When used with the 'installer' option, it is strongly advisable -to specify most if not all of the descriptive information that can -be passed on the command-line. - -Usage: - - %(prog)s [opts] app.p3d standalone|installer|html - -Modes: - - standalone - A standalone executable will be created that embeds the given - p3d file. The resulting executable will require an - internet connection in order to run properly. - - installer - In this mode, installable packages will be created for as many - platforms as possible. To create Windows installers on - non-Windows platforms, you need to have the "makensis" utility - on your system PATH environment variable. - - html - An HTML webpage will be generated that can be used to view - the provided p3d file in a browser. - -Options: - - -n your_app - Short, lowercase name of the application or game. May only - contain alphanumeric characters, underscore or dash. This - name will also define the output file(s) of the process. - If omitted, the basename of the p3d file is used. - - -N "Your Application" - Full name of the application or game. This is the - name that will be displayed to the end-user. - The 'display_name' config is used by default. If it - is missing, the short name is used. - - -v version_number - This should define the version number of your application - or game. In some deploy modes, this argument is required. - This should only contain alphanumeric characters, dots and - dashes, as otherwise the result of the deployment may be - invalid on some platforms. - - -o output_dir - Indicates the directory where the output will be stored. - Within this directory, subdirectories will be created - for every platform, unless -t is provided. - If omitted, the current working directory is assumed. - - -t token=value - Defines a web token or parameter to pass to the application. - Use this to configure how the application will be run. - You can pass as many -t options as you need. Some examples of - useful token names are width, height, log_basename, auto_start, - hidden and console_environment. - - -P platform - If this option is provided, it should specify a comma- - separated list of platforms that the p3d package will be - deployed for. If omitted, it will be built for all platforms. - This option may be specified multiple times. - Examples of valid platforms are win_i386, linux_amd64 and osx_ppc. - - -c - If this option is provided, any -P options are ignored and - the p3d package is only deployed for the current platform. - Furthermore, no per-platform subdirectories will be created - inside the output dirctory. - - -s - This option only has effect in 'installer' mode. If it is - provided, the resulting installers will be fully self-contained, - will not require an internet connection to run, and start up - much faster. Note that pdeploy will also take a very long time - to finish when -s is provided. - If it is omitted, pdeploy will finish much quicker, and the - resulting installers will be smaller, but they will require - an internet connection for the first run, and the load time - will be considerably longer. - - -l "License Name" - Specifies the name of the software license that the game - or application is licensed under. - Only relevant when generating a graphical installer. - - -L licensefile.txt - This should point to a file that contains the full text - describing the software license that the game or application - is licensed under. - Only relevant when generating a graphical installer. - - -O - Specify this option when generating a graphical installer to omit - the default checkboxes for "run this program" and "install a - desktop shortcut" on completion. - - -a com.your_company - Short identifier of the author of the application. The default - is "org.panda3d", but you will most likely want to change - it to your own name or that of your organization or company. - Only relevant when generating a graphical installer. - - -A "Your Company" - Full name of the author of the application. The default is - determined from the GECOS information of the current user if - available; if not, your username is used. - Only relevant when generating a graphical installer. - - -e "you@your_company.com" - E-mail address of the maintainer of the application. The default - is username@hostname. - Only relevant when generating a graphical installer. - - -i "path/icon32.png" -i "path/icon48.png" -i "path/icon128.png" - This option should be repeated several times with different square - image sizes. These images will then be combined to form an icon - file that will be used to represent the installed application. - To support all platforms, it is recommended to supply images of - the sizes 16x16, 32x32, 48x48, 128x128, 256x256, and 512x512. - The larger icon sizes can safely be omitted if you cannot - provide images in that resolution. - It is recommended to use .png images for correct transparency. - If no images are provided, no icon will be generated. - Only relevant when generating a graphical installer. - - -h - Display this help - -""" - -DEPLOY_MODES = ["standalone", "installer", "html"] - -import sys -import os -import getopt -from direct.p3d.DeploymentTools import Standalone, Installer, Icon -from panda3d.core import Filename, PandaSystem - -def usage(code, msg = ''): - if not msg: - sys.stderr.write(usageText % {'prog' : os.path.split(sys.argv[0])[1]}) - sys.stderr.write(msg + '\n') - sys.exit(code) - -shortname = "" -fullname = "" -version = "" -outputDir = Filename("./") -tokens = {} -platforms = [] -currentPlatform = False -licensename = "" -licensefile = Filename() -authorid = "" -authorname = "" -authoremail = "" -iconFiles = [] -includeRequires = False -omitDefaultCheckboxes = False - -try: - opts, args = getopt.getopt(sys.argv[1:], 'n:N:v:o:t:P:csOl:L:a:A:e:i:h') -except getopt.error as msg: - usage(1, msg or 'Invalid option') - -for opt, arg in opts: - if opt == '-n': - shortname = arg.strip() - elif opt == '-N': - fullname = arg.strip() - elif opt == '-v': - version = arg.strip() - elif opt == '-o': - outputDir = Filename.fromOsSpecific(arg) - elif opt == '-t': - token = arg.strip().split("=", 1) - tokens[token[0]] = token[1] - elif opt == '-P': - platforms.append(arg) - elif opt == '-c': - currentPlatform = True - elif opt == '-s': - includeRequires = True - elif opt == '-O': - omitDefaultCheckboxes = True - elif opt == '-l': - licensename = arg.strip() - elif opt == '-L': - licensefile = Filename.fromOsSpecific(arg) - elif opt == '-a': - authorid = arg.strip() - elif opt == '-A': - authorname = arg.strip() - elif opt == '-e': - authoremail = arg.strip() - elif opt == '-i': - iconFiles.append(Filename.fromOsSpecific(arg)) - - elif opt == '-h': - usage(0) - else: - msg = 'illegal option: ' + flag - print(msg) - sys.exit(1, msg) - -if not args or len(args) != 2: - msg = 'Wrong number of arguments, received %s, expected 2' % ( - len(args or [])) - usage(1, msg) - -appFilename = Filename.fromOsSpecific(args[0]) -if appFilename.getExtension().lower() != 'p3d': - print('Application filename must end in ".p3d".') - sys.exit(1) -deploy_mode = args[1].lower() - -if not appFilename.exists(): - print('Application filename does not exist!') - sys.exit(1) - -if shortname == '': - shortname = appFilename.getBasenameWoExtension() - -if shortname.lower() != shortname or ' ' in shortname: - print('\nProvided short name should be lowercase, and may not contain spaces!\n') - -if version == '' and deploy_mode == 'installer': - print('\nA version number is required in "installer" mode.\n') - sys.exit(1) - -if not outputDir: - print('\nYou must name the output directory with the -o parameter.\n') - sys.exit(1) -if not outputDir.exists(): - print('\nThe specified output directory does not exist!\n') - sys.exit(1) -elif not outputDir.isDirectory(): - print('\nThe specified output directory is a file!\n') - sys.exit(1) - -if deploy_mode == 'standalone': - s = Standalone(appFilename, tokens) - s.basename = shortname - - if currentPlatform: - platform = PandaSystem.getPlatform() - if platform.startswith("win"): - s.build(Filename(outputDir, shortname + ".exe"), platform) - else: - s.build(Filename(outputDir, shortname), platform) - elif len(platforms) == 0: - s.buildAll(outputDir) - else: - for platform in platforms: - if platform.startswith("win"): - s.build(Filename(outputDir, platform + "/" + shortname + ".exe"), platform) - else: - s.build(Filename(outputDir, platform + "/" + shortname), platform) - -elif deploy_mode == 'installer': - if includeRequires: - tokens["verify_contents"] = "never" - i = Installer(appFilename, shortname, fullname, version, tokens = tokens) - i.includeRequires = includeRequires - if omitDefaultCheckboxes: - i.offerRun = False - i.offerDesktopShortcut = False - i.licensename = licensename - i.licensefile = licensefile - if authorid: - i.authorid = authorid - if authorname: - i.authorname = authorname - if authoremail: - i.authoremail = authoremail - if not authorname or not authoremail or not authorid: - print("Using author \"%s\" <%s> with ID %s" % \ - (i.authorname, i.authoremail, i.authorid)) - - # Add the supplied icon images - if len(iconFiles) > 0: - failed = False - i.icon = Icon() - for iconFile in iconFiles: - if not i.icon.addImage(iconFile): - print('\nFailed to add icon image "%s"!\n' % iconFile) - failed = True - if failed: - sys.exit(1) - - # Now build for the requested platforms. - if currentPlatform: - platform = PandaSystem.getPlatform() - if platform.startswith("win"): - i.build(outputDir, platform) - else: - i.build(outputDir, platform) - elif len(platforms) == 0: - i.buildAll(outputDir) - else: - for platform in platforms: - output = Filename(outputDir, platform + "/") - output.makeDir() - i.build(output, platform) - - del i - -elif deploy_mode == 'html': - w, h = tokens.get("width", 800), tokens.get("height", 600) - if "data" not in tokens: - tokens["data"] = appFilename.getBasename() - - print("Creating %s.html..." % shortname) - html = open(Filename(outputDir, shortname + ".html").toOsSpecific(), "w") - html.write("\n") - html.write("\n") - html.write(" \n") - html.write(" %s\n" % fullname) - html.write(" \n") - if authorname: - html.write(" \n" % authorname.replace('"', '\\"')) - html.write(" \n") - html.write(" \n") - html.write(" ") - html.write(" \n" % (w, h)) - for key, value in tokens.items(): - html.write(" \n" % (key, value.replace('"', '\\"'))) - html.write(" \n") - html.write(" \n") - html.write(" \n") - html.write("\n") - html.close() -else: - usage(1, 'Invalid deployment mode!') - -# An explicit call to exit() is required to exit the program, when -# this module is packaged in a p3d file. -sys.exit(0) - diff --git a/direct/src/p3d/pmerge.py b/direct/src/p3d/pmerge.py deleted file mode 100755 index 99492df35b..0000000000 --- a/direct/src/p3d/pmerge.py +++ /dev/null @@ -1,106 +0,0 @@ -#! /usr/bin/env python - -usageText = """ - -This script can be used to merge together the contents of two or more -separately-built stage directories, built independently via ppackage, -or via Packager.py. This script also verifies the hash, file size, -and timestamp values in the stage directory as it runs, so it can be -run on a single standalone directory just to perform this validation. - -This script is actually a wrapper around Panda's PackageMerger.py. - -Usage: - - %(prog)s [opts] [inputdir1 .. inputdirN] - -Parameters: - - inputdir1 .. inputdirN - Specify the full path to the input directories you wish to merge. - These are the directories specified by -i on the previous - invocations of ppackage. The order is mostly unimportant. - -Options: - - -i install_dir - The full path to the final install directory. This may also - contain some pre-existing contents; if so, it is merged with all - of the input directories as well. The contents of this directory - are checked for self-consistency with regards to hashes and - timestamps. - - -p packageName[,packageName...] - Specifies one or more particular packages by name that are to be - included from the input directories. Any packages not in this - list are left unchanged in the install directory, even if there - is a newer version in one of the input directories. If no - packages are named, all packages are involved. This option may - be repeated. - - -h - Display this help - -""" - -import sys -import getopt -import os - -from direct.p3d import PackageMerger -from panda3d.core import Filename - -def usage(code, msg = ''): - sys.stderr.write(usageText % {'prog' : os.path.split(sys.argv[0])[1]}) - sys.stderr.write(msg + '\n') - sys.exit(code) - -try: - opts, args = getopt.getopt(sys.argv[1:], 'i:p:h') -except getopt.error as msg: - usage(1, msg) - -installDir = None -packageNames = [] -for opt, arg in opts: - if opt == '-i': - installDir = Filename.fromOsSpecific(arg) - elif opt == '-p': - packageNames += arg.split(',') - - elif opt == '-h': - usage(0) - else: - print('illegal option: ' + arg) - sys.exit(1) - -if not packageNames: - # No package names means allow all packages. - packageNames = None - -inputDirs = [] -for arg in args: - inputDirs.append(Filename.fromOsSpecific(arg)) - -# It's now legal to have no input files if you only want to verify -# timestamps and hashes. -## if not inputDirs: -## print "no input directories specified." -## sys.exit(1) - -try: - pm = PackageMerger.PackageMerger(installDir) - for dir in inputDirs: - pm.merge(dir, packageNames = packageNames) - pm.close() - -except PackageMerger.PackageMergerError: - # Just print the error message and exit gracefully. - inst = sys.exc_info()[1] - print(inst.args[0]) - sys.exit(1) - - -# An explicit call to exit() is required to exit the program, when -# this module is packaged in a p3d file. -sys.exit(0) diff --git a/direct/src/p3d/ppackage.py b/direct/src/p3d/ppackage.py deleted file mode 100755 index cf42ea8403..0000000000 --- a/direct/src/p3d/ppackage.py +++ /dev/null @@ -1,267 +0,0 @@ -#! /usr/bin/env python - -usageText = """ -This script can be used to produce a Panda3D downloadable "package", -which may contain arbitrary files--for instance, Python code, bam -files, and/or compiled DLL's--and which may be downloaded by -application code to extend an application at runtime. - -In addition to packages, this script can also be used to build -standalone p3d applications, that is, packaged Python code in a p3d -file, for execution by the Panda3D plugin or runtime. (But also see -packp3d, which is designed to be a simpler interface for building -applications.) - -This command will build p3d files that reference Panda3D %(version)s, -from host %(host)s . - -This script is actually a wrapper around Panda's Packager.py, which -can be invoked directly by Python code that requires a programmatic -interface to building packages. - -Usage: - - %(prog)s [opts] package.pdef [packageName1 .. packageNameN] - -Parameters: - - package.pdef - The config file that describes the contents of the package file(s) - to be built, in excruciating detail. See the Panda3D manual for - the syntax of this file. - - packageName1 .. packageNameN - Specify the names of the package(s) you wish to build out of the - package.pdef file. This allows you to build only a subset of the - packages defined in this file. If you omit these parameters, all - packages are built, and packages that cannot be built are silently - ignored. - -Options: - - -i install_dir - The full path to a local directory to copy the - ready-to-be-published files into. This directory structure may - contain multiple different packages from multiple different - invocations of this script. It is the user's responsibility to - copy this directory structure to a server, which will have the - URL specified by the packager.setHost() call appearing within the - pdef file. - - -p - Automatically build patches against previous versions after - generating the results. Patches are difference files that users - can download when updating a package, in lieu of redownloading - the whole package; this happens automatically if patches are - present. You should generally build patches when you are - committing to a final, public-facing release. Patches are - usually a good idea, but generating a patch for each internal - test build may needlessly generate a lot of small, inefficient - patch files instead of a few larger ones. You can also generate - patches after the fact, by running ppatcher on the install - directory. - - -s search_dir - Additional directories to search for previously-built packages. - This option may be repeated as necessary. These directories may - also be specified with the pdef-path Config.prc variable. - - -S file.crt[,chain.crt[,file.key[,\"password\"]]] - Signs any resulting p3d file(s) with the indicated certificate. - You may specify the signing certificate, the optional - authorization chain, and the private key in three different - files, or they may all be combined in the first file. If the - private key is encrypted, the password will be required to - decrypt it. - - -D - Sets the allow_python_dev flag in any applications built with - this command. This enables additional runtime debug operations, - particularly the -i option to the panda3d command, which enables - a live Python prompt within the application's environment. - Setting this flag may be useful to develop an application - initially, but should not be set on an application intended for - deployment. - - -N - If this option is set, Packager will not try to compile any Python - files to .pyc or .pyo, instead storing the original source files. - - -u - On the Mac OSX platform, this means that Panda was built with - universal binaries, and the package should be built that way as - well (that is, a version of the the package should be created for - each supported architecture). On other platforms, this option - does nothing. This is therefore safe to apply in all cases, if - you wish to take advantage of universal binaries. This is - equivalent to "-P osx_i386 -P osx_amd64" on Mac platforms. - - -P platform - Specify the platform to masquerade as. The default is whatever - platform Panda has been built for. You can use this on Mac OSX - in order to build packages for an alternate architecture if you - have built Panda with universal binaries; you may repeat this - option for each architecture you wish to support. For other - platforms, it is probably a mistake to set this. However, see - the option -u. - - -R sysroot - Specify the sysroot that these files were compiled against. This - will shadow the system shared libraries, so that alternate - versions are used instead of the system versions. If any program - references a library, say /usr/lib/libfoo.so, and - /sysroot/usr/lib/libfoo.so exists instead, that file will be used - instead of the system library. This is particularly useful for - cross-compilation. At the moment, this is supported only on OSX. - - -H - Treats a packager.setHost() call in the pdef file as if it were - merely a call to packager.addHost(). This allows producing a - package for an alternate host than its normally configured host, - which is sometimes useful in development. - - -a suffix - Appends the given suffix to the p3d filename, before the extension. - This is useful when the same packages are compiled several times - but using different settings, and you want to mark those packages - as such. This only applies to .p3d packages, not to other types - of packages! - - -v - Emit a warning for any file not recognized by the dir() command - (indicating there may be a need for addExtensions(...)). - - -h - Display this help -""" - -import sys -import getopt -import os - -from direct.p3d import Packager -from panda3d.core import * - -def usage(code, msg = ''): - sys.stderr.write(usageText % { - 'version' : PandaSystem.getPackageVersionString(), - 'host' : PandaSystem.getPackageHostUrl(), - 'prog' : os.path.split(sys.argv[0])[1] - }) - sys.stderr.write(msg + '\n') - sys.exit(code) - -installDir = None -buildPatches = False -installSearch = [] -signParams = [] -allowPythonDev = False -storePythonSource = False -universalBinaries = False -systemRoot = None -ignoreSetHost = False -verbosePrint = False -p3dSuffix = '' -platforms = [] - -try: - opts, args = getopt.getopt(sys.argv[1:], 'i:ps:S:DNuP:R:Ha:hv') -except getopt.error as msg: - usage(1, msg) - -for opt, arg in opts: - if opt == '-i': - installDir = Filename.fromOsSpecific(arg) - elif opt == '-p': - buildPatches = True - elif opt == '-s': - installSearch.append(Filename.fromOsSpecific(arg)) - elif opt == '-S': - tokens = arg.split(',') - while len(tokens) < 4: - tokens.append('') - certificate, chain, pkey, password = tokens[:4] - signParams.append((Filename.fromOsSpecific(certificate), - Filename.fromOsSpecific(chain), - Filename.fromOsSpecific(pkey), - Filename.fromOsSpecific(password))) - elif opt == '-D': - allowPythonDev = True - elif opt == '-N': - storePythonSource = True - elif opt == '-u': - universalBinaries = True - elif opt == '-P': - platforms.append(arg) - elif opt == '-R': - systemRoot = arg - elif opt == '-H': - ignoreSetHost = True - elif opt == '-a': - p3dSuffix = arg - - elif opt == '-v': - verbosePrint = True - - elif opt == '-h': - usage(0) - else: - print('illegal option: ' + arg) - sys.exit(1) - -if not args: - usage(0) - -packageDef = Filename.fromOsSpecific(args[0]) -packageNames = None -if len(args) > 1: - packageNames = args[1:] - -# Add the directory containing the pdef file itself to sys.path, to -# help the Packager locate modules where a pathname isn't specified. -dirname = packageDef.getDirname() -if dirname: - sys.path.append(Filename(dirname).toOsSpecific()) -else: - sys.path.append('.') - -if universalBinaries: - if platforms: - print('\nYou may not specify both -u and -P.\n') - sys.exit(1) - if PandaSystem.getPlatform().startswith('osx_'): - platforms = ['osx_i386', 'osx_amd64'] - -if not platforms: - platforms = [PandaSystem.getPlatform()] - -for platform in platforms: - packager = Packager.Packager(platform = platform) - packager.installDir = installDir - packager.installSearch = installSearch + packager.installSearch - if installDir is not None: - packager.installSearch = [installDir] + packager.installSearch - packager.signParams = signParams - packager.allowPythonDev = allowPythonDev - packager.storePythonSource = storePythonSource - packager.systemRoot = systemRoot - packager.ignoreSetHost = ignoreSetHost - packager.verbosePrint = verbosePrint - packager.p3dSuffix = p3dSuffix - - try: - packager.setup() - packages = packager.readPackageDef(packageDef, packageNames = packageNames) - packager.close() - if buildPatches: - packager.buildPatches(packages) - - except Packager.PackagerError: - # Just print the error message and exit gracefully. - inst = sys.exc_info()[1] - print(inst.args[0]) - sys.exit(1) - -# An explicit call to exit() is required to exit the program, when -# this module is packaged in a p3d file. -sys.exit(0) diff --git a/direct/src/p3d/ppatcher.py b/direct/src/p3d/ppatcher.py deleted file mode 100755 index 69e9689622..0000000000 --- a/direct/src/p3d/ppatcher.py +++ /dev/null @@ -1,101 +0,0 @@ -#! /usr/bin/env python - -usageText = """ - -This script generates the patches required to support incremental -download of Panda3D packages. It can be run as a post-process on a -directory hierarchy created by ppackage; it will examine the directory -hierarchy, and create any patches that appear to be missing. - -You may run ppackage on the same directory hierarchy as many times as -you like, without creating patches. You may then download and test -the resulting files--users connecting to the tree without fresh -patches will be forced to download the entire file, instead of making -an incremental download, but the entire process will work otherwise. -When you are satisfied that all of the files are ready to be released, -you may run ppackage on the directory hierarchy to generate the -required patches. - -Generating the patches just before final release is a good idea to -limit the number of trivially small patches that are created. Each -time this script is run, a patch is created from the previous version, -and these patches daisy-chain together to define a complete update -sequence. If you run this script on internal releases, you will -generate a long chain of small patches that your users must download; -this is pointless if there is no possibility of anyone having -downloaded one of the intervening versions. - -You can also generate patches with the -p option to ppackage, but that -only generates patches for the specific packages built by that -invocation of ppackage. If you use the ppatcher script instead, it -will generate patches for all packages (or the set of packages that -you name specifically). - -This script is actually a wrapper around Panda's PatchMaker.py. - -Usage: - - %(prog)s [opts] [packageName1 .. packageNameN] - -Parameters: - - packageName1 .. packageNameN - Specify the names of the package(s) you wish to generate patches - for. This allows you to build patches for only a subset of the - packages found in the tree. If you omit these parameters, patches - are built for all packages that require them. - -Options: - - -i install_dir - The full path to the install directory. This should be the same - directory named by the -i parameter to ppackage. - - -h - Display this help - -""" - -import sys -import getopt -import os - -from direct.p3d.PatchMaker import PatchMaker -from panda3d.core import Filename - -def usage(code, msg = ''): - sys.stderr.write(usageText % {'prog' : os.path.split(sys.argv[0])[1]}) - sys.stderr.write(msg + '\n') - sys.exit(code) - -try: - opts, args = getopt.getopt(sys.argv[1:], 'i:h') -except getopt.error as msg: - usage(1, msg) - -installDir = None -for opt, arg in opts: - if opt == '-i': - installDir = Filename.fromOsSpecific(arg) - - elif opt == '-h': - usage(0) - else: - print('illegal option: ' + arg) - sys.exit(1) - -packageNames = args - -if not installDir: - installDir = Filename('install') - -if not packageNames: - # "None" means all packages. - packageNames = None - -pm = PatchMaker(installDir) -pm.buildPatches(packageNames = packageNames) - -# An explicit call to exit() is required to exit the program, when -# this module is packaged in a p3d file. -sys.exit(0) diff --git a/direct/src/p3d/runp3d.py b/direct/src/p3d/runp3d.py deleted file mode 100644 index 2ab457bc3c..0000000000 --- a/direct/src/p3d/runp3d.py +++ /dev/null @@ -1,79 +0,0 @@ -#! /usr/bin/env python - -""" - -This tool will invoke the AppRunner to execute a packaged p3d -application. It requires that that the current Panda3D and Python -versions match the version expected by the application. - -Normally, you do not need to use this tool; instead, use the provided -standalone panda3d executable to invoke any p3d application. Using -panda3d will guarantee that the correct versions of Panda3D and Python -are used to run the application. However, there may be occasions when -it is useful to use this tool to run the application with the current -build instead of with its advertised version requirements. - -Usage: - - runp3d.py app.p3d [args] - -The command-line arguments following the application name are passed -into the application unchanged. - -See pack3d.p3d for an application that generates these p3d files. - -""" - -import sys -import getopt -from .AppRunner import AppRunner, ArgumentError -from direct.task.TaskManagerGlobal import taskMgr -from panda3d.core import Filename - -def parseSysArgs(): - """ Handles sys.argv, if there are any local arguments, and - returns a new argv suitable for passing into the - application. """ - - # We prefix a "+" sign, following the GNU convention, to tell - # getopt not to parse options following the first non-option - # parameter. - opts, args = getopt.getopt(sys.argv[1:], '+h') - - for option, value in opts: - if option == '-h': - print(__doc__) - sys.exit(1) - - if not args or not args[0]: - raise ArgumentError("No Panda app specified. Use:\nrunp3d.py app.p3d") - - arg0 = args[0] - p3dFilename = Filename.fromOsSpecific(arg0) - if p3dFilename.exists(): - p3dFilename.makeAbsolute() - arg0 = p3dFilename.toOsSpecific() - - return [arg0] + args[1:] - -def runPackedApp(pathname): - runner = AppRunner() - runner.gotWindow = True - try: - runner.setP3DFilename(pathname, tokens = [], argv = [], - instanceId = 0, interactiveConsole = False) - except ArgumentError as e: - print(e.args[0]) - sys.exit(1) - -if __name__ == '__main__': - runner = AppRunner() - runner.gotWindow = True - try: - argv = parseSysArgs() - runner.setP3DFilename(argv[0], tokens = [], argv = argv, - instanceId = 0, interactiveConsole = False) - except ArgumentError as e: - print(e.args[0]) - sys.exit(1) - taskMgr.run() diff --git a/direct/src/p3d/thirdparty.pdef b/direct/src/p3d/thirdparty.pdef deleted file mode 100644 index bc001e427d..0000000000 --- a/direct/src/p3d/thirdparty.pdef +++ /dev/null @@ -1,167 +0,0 @@ -# This file defines a number of standard "packages" that correspond to -# a Panda3D distribution. These packages are built by passing this -# file to the ppackage utility, either as a packaged application, or -# as the module direct.p3d.ppackage. - -# The packages in this file define the thirdparty -# packages that could be used by a .p3d archive. - -# When needed, these packages are downloaded by the core API, from the -# host URL specified in a given p3d file, and not from any hardcoded -# URL. Thus, any custom version of Panda3D may be hosted on any -# server in the world, and any version of the plugin can download it. - -# Also see panda3d.pdef. - -from panda3d.core import Filename -import sys - -class wx(package): - config(display_name = "wxPython GUI Toolkit") - #config(gui_app = True) - require('panda3d') - - module('direct.showbase.WxGlobal') - module('direct.wxwidgets') - module('direct.wxwidgets.*') - module('wx', required = True) - module('wx.*') - -class tk(package): - config(display_name = "Tk GUI Toolkit") - #config(gui_app = True) - require('panda3d') - - if sys.version_info >= (3, 0): - module('tkinter', '_tkinter', required = True) - module('tkinter.colorchooser', 'tkinter.commondialog', - 'tkinter.constants', 'tkinter.dialog', 'tkinter.dnd', - 'tkinter.filedialog', 'tkinter.font', 'tkinter.messagebox', - 'tkinter.scrolledtext', 'tkinter.simpledialog', 'tkinter.tix', - 'tkinter.ttk') - else: - module('Tkinter', '_tkinter', required = True) - module('Tkconstants', 'Tkdnd', 'Tix', 'ScrolledText', 'turtle', - 'tkColorChooser', 'tkCommonDialog', 'tkFileDialog', - 'tkFont', 'tkMessageBox', 'tkSimpleDialog') - - module('direct.showbase.TkGlobal', - 'direct.tkpanels', - 'direct.tkwidgets') - - try: - if sys.version_info >= (3, 0): - from tkinter import Tcl - else: - from Tkinter import Tcl - tcl = Tcl() - dir = Filename.fromOsSpecific(tcl.eval("info library")) - ver = tcl.eval("info tclversion") - - file(Filename(dir, "*.tcl"), newDir = 'lib/tcl' + ver, extract = True) - except ImportError: - pass - - try: - import Pmw - except ImportError: - Pmw = None - - if Pmw is not None: - Pmw = sys.modules['_Pmw'] - sys.modules['Pmw'] = Pmw - sys.modules['Pmw'].__name__ = 'Pmw' - module('Pmw', 'Pmw.Pmw_1_3.lib.*') - path = Filename.fromOsSpecific(Pmw.__path__[0]) - file(Filename(path, 'Pmw_1_3/lib/Pmw.def'), newDir = 'Pmw/Pmw_1_3/lib') - -class sqlite(package): - config(display_name = "SQLite Interface") - require('panda3d') - - module('sqlite', 'sqlite3') - -class numpy(package): - config(display_name = "NumPy") - require('panda3d') - - module('numpy', required = True) - -class pygame(package): - config(display_name = "PyGame") - require('panda3d', 'numpy') - - module('pygame', required = True) - module('pygame.*', 'pygame._view') - -class twisted(package): - config(display_name = "Twisted") - require('panda3d') - - module('twisted', 'twisted._version', required = True) - module('twisted.application', 'twisted.conch', 'twisted.cred', - 'twisted.enterprise', 'twisted.internet', 'twisted.lore', - 'twisted.mail', 'twisted.manhole', 'twisted.names', - 'twisted.news', 'twisted.pair', 'twisted.persisted', - 'twisted.plugin', 'twisted.plugins', 'twisted.python', - 'twisted.runner', 'twisted.scripts', 'twisted.spread', - 'twisted.tap', 'twisted.trial', 'twisted.vfs', - 'twisted.web', 'twisted.web2', 'twisted.words') - - module('twisted.*', 'twisted.*.*') - -class pil(package): - config(display_name = "Python Imaging Library") - require('panda3d') - - module('Image', required = True) - module('PIL', 'ArgImagePlugin', 'BdfFontFile', - 'BmpImagePlugin', 'BufrStubImagePlugin', 'ContainerIO', - 'CurImagePlugin', 'DcxImagePlugin', 'EpsImagePlugin', - 'ExifTags', 'FitsStubImagePlugin', 'FliImagePlugin', - 'FontFile', 'FpxImagePlugin', 'GbrImagePlugin', 'GdImageFile', - 'GifImagePlugin', 'GimpGradientFile', 'GimpPaletteFile', - 'GribStubImagePlugin', 'Hdf5StubImagePlugin', - 'IcnsImagePlugin', 'IcoImagePlugin', 'ImImagePlugin', - 'ImageChops', 'ImageCms', 'ImageColor', 'ImageDraw', - 'ImageDraw2', 'ImageEnhance', 'ImageFile', 'ImageFileIO', - 'ImageFilter', 'ImageFont', 'ImageGL', 'ImageGrab', - 'ImageMath', 'ImageMode', 'ImageOps', 'ImagePalette', - 'ImagePath', 'ImageQt', 'ImageSequence', 'ImageShow', - 'ImageStat', 'ImageTk', 'ImageTransform', 'ImageWin', - 'ImtImagePlugin', 'IptcImagePlugin', 'JpegImagePlugin', - 'McIdasImagePlugin', 'MicImagePlugin', 'MpegImagePlugin', - 'MspImagePlugin', 'OleFileIO', 'PSDraw', 'PaletteFile', - 'PalmImagePlugin', 'PcdImagePlugin', 'PcfFontFile', - 'PcxImagePlugin', 'PdfImagePlugin', 'PixarImagePlugin', - 'PngImagePlugin', 'PpmImagePlugin', 'PsdImagePlugin', - 'SgiImagePlugin', 'SpiderImagePlugin', 'SunImagePlugin', - 'TarIO', 'TgaImagePlugin', 'TiffImagePlugin', 'TiffTags', - 'WalImageFile', 'WmfImagePlugin', 'XVThumbImagePlugin', - 'XbmImagePlugin', 'XpmImagePlugin', '_imaging', - '_imagingmath', '_imagingtk') - -class pyopengl(package): - config(display_name = "PyOpenGL") - require('panda3d', 'numpy') - - module('OpenGL', 'OpenGL.GL', required = True) - module('OpenGL.GLU', 'OpenGL.GLUT', 'OpenGL.GLE', 'OpenGL.GLX') - -class httplib2(package): - config(display_name = "httplib2", platform_specific = False) - require('panda3d') - - module('httplib2', required = True) - -class box2d(package): - config(display_name = "Box2D") - require('panda3d') - - module('Box2D', required = True) - -class pyglet(package): - config(display_name = "pyglet", platform_specific = False) - require('panda3d', 'morepy') - - module('pyglet', required = True) diff --git a/direct/src/plugin/binaryXml.cxx b/direct/src/plugin/binaryXml.cxx deleted file mode 100644 index 7dc4a60268..0000000000 --- a/direct/src/plugin/binaryXml.cxx +++ /dev/null @@ -1,351 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file binaryXml.cxx - * @author drose - * @date 2009-07-13 - */ - -#include "binaryXml.h" -#include "p3d_lock.h" -#include - -using std::istream; -using std::ostream; -using std::ostringstream; -using std::string; - -static const bool debug_xml_output = false; - -static LOCK xml_lock; -static bool xml_lock_initialized = false; - -#define DO_BINARY_XML 1 - -enum NodeType { - NT_unknown, - NT_document, - NT_element, - NT_text, -}; - -// This typedef defines a 32-bit unsigned integer. It's used for passing -// values through the binary XML stream. -typedef unsigned int xml_uint32; - -// These are both prime numbers, though I don't know if that really matters. -// Mainly, they're big random numbers. -static const xml_uint32 length_nonce1 = 812311453; -static const xml_uint32 length_nonce2 = 612811373; - -/** - * Should be called before spawning any threads to ensure the lock is - * initialized. - */ -void -init_xml() { - if (!xml_lock_initialized) { - INIT_LOCK(xml_lock); - xml_lock_initialized = true; - } -} - -/** - * Recursively writes a node and all of its children to the given stream. - */ -static void -write_xml_node(ostream &out, TiXmlNode *xnode) { - const string &value = xnode->ValueStr(); - xml_uint32 value_length = value.length(); - xml_uint32 value_proof = (value_length + length_nonce1) * length_nonce2; - - // We write out not only value_length, but the same value again hashed by - // length_nonce1 and 2 (and truncated back to xml_uint32), just to prove to - // the reader that we're still on the same page. We do this only on the top - // node; we don't bother for the nested nodes. - out.write((char *)&value_length, sizeof(value_length)); - out.write((char *)&value_proof, sizeof(value_proof)); - out.write(value.data(), value_length); - - // Now write out the node type. - NodeType type = NT_element; - if (xnode->ToDocument() != nullptr) { - type = NT_document; - } else if (xnode->ToElement() != nullptr) { - type = NT_element; - } else if (xnode->ToText() != nullptr) { - type = NT_text; - } else { - type = NT_unknown; - } - - out.put((char)type); - // We don't bother to write any further data for the unknown types. - if (type == NT_unknown) { - return; - } - - if (type == NT_element) { - // Write the element attributes. - TiXmlElement *xelement = xnode->ToElement(); - assert(xelement != nullptr); - const TiXmlAttribute *xattrib = xelement->FirstAttribute(); - - while (xattrib != nullptr) { - // We have an attribute. - out.put((char)true); - - string name = xattrib->Name(); - xml_uint32 name_length = name.length(); - out.write((char *)&name_length, sizeof(name_length)); - out.write(name.data(), name_length); - - const string &value = xattrib->ValueStr(); - xml_uint32 value_length = value.length(); - out.write((char *)&value_length, sizeof(value_length)); - out.write(value.data(), value_length); - - xattrib = xattrib->Next(); - } - - // The end of the attributes list. - out.put((char)false); - } - - // Now write all of the children. - TiXmlNode *xchild = xnode->FirstChild(); - while (xchild != nullptr) { - // We have a child. - out.put((char)true); - write_xml_node(out, xchild); - xchild = xchild->NextSibling(); - } - - // The end of the children list. - out.put((char)false); -} - -/** - * Recursively reads a node and all of its children to the given stream. - * Returns the newly-allocated node. The caller is responsible for eventually - * deleting the return value. Returns NULL on error. - */ -static TiXmlNode * -read_xml_node(istream &in, char *&buffer, xml_uint32 &buffer_length, - ostream &logfile) { - xml_uint32 value_length; - in.read((char *)&value_length, sizeof(value_length)); - if (in.gcount() != sizeof(value_length)) { - return nullptr; - } - xml_uint32 value_proof_expect = (value_length + length_nonce1) * length_nonce2; - xml_uint32 value_proof; - in.read((char *)&value_proof, sizeof(value_proof)); - if (in.gcount() != sizeof(value_proof)) { - return nullptr; - } - if (value_proof != value_proof_expect) { - // Hey, we ran into garbage: the proof value didn't match our expected - // proof value. - logfile << "Garbage on XML stream!\n"; - - // Print out the garbage; maybe it will help the developer figure out - // where it came from. - logfile << "Begin garbage:\n"; - ostringstream strm; - strm.write((char *)&value_length, sizeof(value_length)); - strm.write((char *)&value_proof, sizeof(value_proof)); - logfile << strm.str(); - for (size_t i = 0; i < 100; ++i) { - int ch = in.get(); - if (ch != EOF) { - logfile.put(ch); - } - } - logfile << "\n"; - logfile << "End garbage.\n"; - return nullptr; - } - - if (value_length > buffer_length) { - delete[] buffer; - buffer_length = value_length; - buffer = new char[buffer_length]; - } - - in.read(buffer, value_length); - string value(buffer, value_length); - - // Read the node type. - NodeType type = (NodeType)in.get(); - if (type == NT_unknown) { - return nullptr; - } - - TiXmlNode *xnode = nullptr; - if (type == NT_element) { - xnode = new TiXmlElement(value); - } else if (type == NT_document) { - xnode = new TiXmlDocument; - } else if (type == NT_text) { - xnode = new TiXmlText(value); - } else { - assert(false); - } - - if (type == NT_element) { - // Read the element attributes. - TiXmlElement *xelement = xnode->ToElement(); - assert(xelement != nullptr); - bool got_attrib = (bool)(in.get() != 0); - - while (got_attrib && in && !in.eof()) { - // We have an attribute. - xml_uint32 name_length; - in.read((char *)&name_length, sizeof(name_length)); - if (in.gcount() != sizeof(name_length)) { - delete xnode; - return nullptr; - } - - if (name_length > buffer_length) { - delete[] buffer; - buffer_length = name_length; - buffer = new char[buffer_length]; - } - - in.read(buffer, name_length); - string name(buffer, name_length); - - xml_uint32 value_length; - in.read((char *)&value_length, sizeof(value_length)); - if (in.gcount() != sizeof(value_length)) { - delete xnode; - return nullptr; - } - - if (value_length > buffer_length) { - delete[] buffer; - buffer_length = value_length; - buffer = new char[buffer_length]; - } - - in.read(buffer, value_length); - string value(buffer, value_length); - - xelement->SetAttribute(name, value); - - got_attrib = (bool)(in.get() != 0); - } - } - - // Now read all of the children. - bool got_child = (bool)(in.get() != 0); - - while (got_child && in && !in.eof()) { - // We have a child. - TiXmlNode *xchild = read_xml_node(in, buffer, buffer_length, logfile); - if (xchild != nullptr) { - xnode->LinkEndChild(xchild); - } - - got_child = (bool)(in.get() != 0); - } - - return xnode; -} - - - -/** - * Writes the indicated TinyXml document to the given stream. - */ -void -write_xml(ostream &out, TiXmlDocument *doc, ostream &logfile) { - assert(xml_lock_initialized); - ACQUIRE_LOCK(xml_lock); - -#ifdef DO_BINARY_XML - // Binary write. - write_xml_node(out, doc); - -#else - // Formatted ASCII write. - - // We need a declaration to write it safely. - TiXmlDeclaration decl("1.0", "utf-8", ""); - doc->InsertBeforeChild(doc->FirstChild(), decl); - - out << *doc; -#endif - - out << flush; - - if (debug_xml_output) { - // Write via ostringstream, so it all goes in one operation, to help out - // the interleaving from multiple threads. - ostringstream logout; - logout << "sent: " << *doc << "\n"; - logfile << logout.str() << flush; - } - - RELEASE_LOCK(xml_lock); -} - -/** - * Reads a TinyXml document from the given stream, and returns it. If the - * document is not yet available, blocks until it is, or until there is an - * error condition on the input. - * - * The return value is NULL if there is an error, or the newly-allocated - * document if it is successfully read. If not NULL, the document has been - * allocated with new, and should be eventually freed by the caller with - * delete. - */ -TiXmlDocument * -read_xml(istream &in, ostream &logfile) { - // We don't acquire xml_lock while reading. We can't, because our XML - // readers are all designed to block until data is available, and they can't - // block while holding the lock. - - // Fortunately, there should be only one reader at a time, so a lock isn't - // really needed here. - -#if DO_BINARY_XML - // binary read. - xml_uint32 buffer_length = 128; - char *buffer = new char[buffer_length]; - TiXmlNode *xnode = read_xml_node(in, buffer, buffer_length, logfile); - delete[] buffer; - if (xnode == nullptr) { - return nullptr; - } - - TiXmlDocument *doc = xnode->ToDocument(); - assert(doc != nullptr); - -#else - // standard ASCII read. - TiXmlDocument *doc = new TiXmlDocument; - in >> *doc; - if (in.fail() || in.eof()) { - delete doc; - return nullptr; - } -#endif - - if (debug_xml_output) { - // Write via ostringstream, so it all goes in one operation, to help out - // the interleaving from multiple threads. - ostringstream logout; - logout << "received: " << *doc << "\n"; - logfile << logout.str() << flush; - } - - return doc; -} diff --git a/direct/src/plugin/binaryXml.h b/direct/src/plugin/binaryXml.h deleted file mode 100644 index 477c51e83f..0000000000 --- a/direct/src/plugin/binaryXml.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file binaryXml.h - * @author drose - * @date 2009-07-13 - */ - -#ifndef BINARYXML_H -#define BINARYXML_H - -#include "get_tinyxml.h" -#include "handleStream.h" -#include - -// A pair of functions to input and output the TinyXml constructs on the -// indicated streams. We could, of course, use the TinyXml output operators, -// but this is a smidge more efficient and gives us more control. - -void init_xml(); -void write_xml(std::ostream &out, TiXmlDocument *doc, std::ostream &logfile); -TiXmlDocument *read_xml(std::istream &in, std::ostream &logfile); - -#endif diff --git a/direct/src/plugin/failed.pgm b/direct/src/plugin/failed.pgm deleted file mode 100644 index c470d8fb6f79da275a3a9ee4fa22740979f47b85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2304 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 diff --git a/direct/src/plugin/fhandle.h b/direct/src/plugin/fhandle.h deleted file mode 100644 index 90459efbe1..0000000000 --- a/direct/src/plugin/fhandle.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file fhandle.h - * @author drose - * @date 2009-08-29 - */ - -#ifndef FHANDLE_H -#define FHANDLE_H - -// This header file simply defines the FHandle type, which is used to pass -// around a handle to an open file object. - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -typedef HANDLE FHandle; -static const HANDLE invalid_fhandle = INVALID_HANDLE_VALUE; -#else -// On POSIX, we use a file descriptor as a "handle". -typedef int FHandle; -static const int invalid_fhandle = -1; -#endif - -#endif diff --git a/direct/src/plugin/fileSpec.I b/direct/src/plugin/fileSpec.I deleted file mode 100644 index 22e6f26f81..0000000000 --- a/direct/src/plugin/fileSpec.I +++ /dev/null @@ -1,102 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file fileSpec.I - * @author drose - * @date 2009-06-29 - */ - -/** - * Returns the relative path to this file on disk, within the package root - * directory. - */ -inline const std::string &FileSpec:: -get_filename() const { - return _filename; -} - -/** - * Changes the relative path to this file on disk, within the package root - * directory. - */ -inline void FileSpec:: -set_filename(const std::string &filename) { - _filename = filename; -} - -/** - * Returns the full path to this file on disk. - */ -inline std::string FileSpec:: -get_pathname(const std::string &package_dir) const { - return package_dir + "/" + _filename; -} - -/** - * Returns the expected size of this file on disk, in bytes. - */ -inline size_t FileSpec:: -get_size() const { - return _size; -} - -/** - * Returns the expected last-modify timestamp of this file on disk. - */ -inline time_t FileSpec:: -get_timestamp() const { - return _timestamp; -} - -/** - * Returns true if we have successfully read a hash value, false otherwise. - */ -inline bool FileSpec:: -has_hash() const { - return _got_hash; -} - -/** - * After a call to quick_verify() or full_verify(), this method *may* return a - * pointer to a FileSpec that represents the actual data read on disk, or it - * may return NULL. If this returns a non-NULL value, you may use it to - * extract the md5 hash of the existing file, thus saving the effort of - * performing the hash twice. - */ -inline const FileSpec *FileSpec:: -get_actual_file() const { - return _actual_file; -} - -/** - * Returns the integer value corresponding to the indicated hex digit. - * Returns -1 if it is not a hex digit. - */ -inline int FileSpec:: -decode_hexdigit(char c) { - if (isdigit(c)) { - return c - '0'; - } - c = tolower(c); - if (c >= 'a' && c <= 'f') { - return c - 'a' + 10; - } - - return -1; -} - -/** - * Returns the hex digit corresponding to the indicated integer value. - */ -inline char FileSpec:: -encode_hexdigit(int c) { - if (c >= 10) { - return c - 10 + 'a'; - } - return c + '0'; -} diff --git a/direct/src/plugin/fileSpec.cxx b/direct/src/plugin/fileSpec.cxx deleted file mode 100644 index fd7169c4d1..0000000000 --- a/direct/src/plugin/fileSpec.cxx +++ /dev/null @@ -1,486 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file fileSpec.cxx - * @author drose - * @date 2009-06-29 - */ - -#include "fileSpec.h" -#include "wstring_encode.h" -#include - -#include -#include -#include - -#include -#include -#include - -#ifdef _WIN32 -#include -#include -#define utimbuf _utimbuf - -#else -#include - -#endif - -using std::istream; -using std::ostream; -using std::string; -using std::wstring; - -/** - * - */ -FileSpec:: -FileSpec() { - _size = 0; - _timestamp = 0; - memset(_hash, 0, hash_size); - _got_hash = false; - _actual_file = nullptr; -} - -/** - * - */ -FileSpec:: -FileSpec(const FileSpec ©) : - _filename(copy._filename), - _size(copy._size), - _timestamp(copy._timestamp), - _got_hash(copy._got_hash) -{ - memcpy(_hash, copy._hash, hash_size); - _actual_file = nullptr; -} - -/** - * - */ -void FileSpec:: -operator = (const FileSpec ©) { - _filename = copy._filename; - _size = copy._size; - _timestamp = copy._timestamp; - memcpy(_hash, copy._hash, hash_size); - _got_hash = copy._got_hash; -} - -/** - * - */ -FileSpec:: -~FileSpec() { - if (_actual_file != nullptr) { - delete _actual_file; - } -} - -/** - * Reads the data from the indicated XML file. - */ -void FileSpec:: -load_xml(TiXmlElement *xelement) { - const char *filename = xelement->Attribute("filename"); - if (filename != nullptr) { - _filename = filename; - } - - const char *size = xelement->Attribute("size"); - if (size != nullptr) { - char *endptr; - _size = strtoul(size, &endptr, 10); - } - - const char *timestamp = xelement->Attribute("timestamp"); - if (timestamp != nullptr) { - char *endptr; - _timestamp = strtoul(timestamp, &endptr, 10); - } - - _got_hash = false; - const char *hash = xelement->Attribute("hash"); - if (hash != nullptr && strlen(hash) == (hash_size * 2)) { - // Decode the hex hash string. - _got_hash = decode_hex(_hash, hash, hash_size); - } -} - -/** - * Stores the data to the indicated XML file. - */ -void FileSpec:: -store_xml(TiXmlElement *xelement) { - if (!_filename.empty()) { - xelement->SetAttribute("filename", _filename); - } - if (_size != 0) { - xelement->SetAttribute("size", _size); - } - if (_timestamp != 0) { - xelement->SetAttribute("timestamp", (int)_timestamp); - } - if (_got_hash) { - char hash[hash_size * 2 + 1]; - encode_hex(hash, _hash, hash_size); - hash[hash_size * 2] = '\0'; - xelement->SetAttribute("hash", hash); - } -} - -/** - * Performs a quick test to ensure the file has not been modified. This test - * is vulnerable to people maliciously attempting to fool the program (by - * setting datestamps etc.). - * - * Returns true if it is intact, false if it needs to be redownloaded. - */ -bool FileSpec:: -quick_verify(const string &package_dir) { - return quick_verify_pathname(get_pathname(package_dir)); -} - -/** - * Works like quick_verify(), above, with an explicit pathname. Useful for - * verifying the copy of a file in a temporary location. - */ -bool FileSpec:: -quick_verify_pathname(const string &pathname) { - if (_actual_file != nullptr) { - delete _actual_file; - _actual_file = nullptr; - } - - int result = 1; -#ifdef _WIN32 - struct _stat st; - wstring pathname_w; - if (string_to_wstring(pathname_w, pathname)) { - result = _wstat(pathname_w.c_str(), &st); - } -#else // _WIN32 - struct stat st; - result = stat(pathname.c_str(), &st); -#endif // _WIN32 - - if (result != 0) { - // cerr << "file not found: " << _filename << "\n"; - return false; - } - - if (st.st_size != _size) { - // If the size is wrong, the file fails. cerr << "size wrong: " << - // _filename << "\n"; - return false; - } - - if (st.st_mtime == _timestamp) { - // If the size is right and the timestamp is right, the file passes. cerr - // << "file ok: " << _filename << "\n"; - return true; - } - - // cerr << "modification time wrong: " << _filename << "\n"; - - // If the size is right but the timestamp is wrong, the file soft-fails. We - // follow this up with a hash check. - if (!priv_check_hash(pathname, &st)) { - // Hard fail, the hash is wrong. cerr << "hash check wrong: " << - // _filename << "\n"; - return false; - } - - // cerr << "hash check ok: " << _filename << "\n"; - - // The hash is OK after all. Change the file's timestamp back to what we - // expect it to be, so we can quick-verify it successfully next time. - utimbuf utb; - utb.actime = st.st_atime; - utb.modtime = _timestamp; - -#ifdef _WIN32 - _wutime(pathname_w.c_str(), &utb); -#else // _WIN32 - utime(pathname.c_str(), &utb); -#endif // _WIN32 - - return true; -} - -/** - * Performs a more thorough test to ensure the file has not been modified. - * This test is less vulnerable to malicious attacks, since it reads and - * verifies the entire file. - * - * Returns true if it is intact, false if it needs to be redownloaded. - */ -bool FileSpec:: -full_verify(const string &package_dir) { - if (_actual_file != nullptr) { - delete _actual_file; - _actual_file = nullptr; - } - - string pathname = get_pathname(package_dir); - int result = 1; -#ifdef _WIN32 - struct _stat st; - wstring pathname_w; - if (string_to_wstring(pathname_w, pathname)) { - result = _wstat(pathname_w.c_str(), &st); - } -#else // _WIN32 - struct stat st; - result = stat(pathname.c_str(), &st); -#endif // _WIN32 - - if (result != 0) { - // cerr << "file not found: " << _filename << "\n"; - return false; - } - - if (st.st_size != _size) { - // If the size is wrong, the file fails. cerr << "size wrong: " << - // _filename << "\n"; - return false; - } - - if (!priv_check_hash(pathname, &st)) { - // Hard fail, the hash is wrong. cerr << "hash check wrong: " << - // _filename << "\n"; - return false; - } - - // cerr << "hash check ok: " << _filename << "\n"; - - // The hash is OK. If the timestamp is wrong, change it back to what we - // expect it to be, so we can quick-verify it successfully next time. - - if (st.st_mtime != _timestamp) { - utimbuf utb; - utb.actime = st.st_atime; - utb.modtime = _timestamp; -#ifdef _WIN32 - _wutime(pathname_w.c_str(), &utb); -#else // _WIN32 - utime(pathname.c_str(), &utb); -#endif // _WIN32 - } - - return true; -} - -/** - * Returns a FileSpec that represents the actual data read on disk. This will - * read the disk to determine the data if necessary. - */ -const FileSpec *FileSpec:: -force_get_actual_file(const string &pathname) { - if (_actual_file == nullptr) { -#ifdef _WIN32 - struct _stat st; - wstring pathname_w; - if (string_to_wstring(pathname_w, pathname)) { - _wstat(pathname_w.c_str(), &st); - } -#else // _WIN32 - struct stat st; - stat(pathname.c_str(), &st); -#endif // _WIN32 - - priv_check_hash(pathname, &st); - } - - return _actual_file; -} - -/** - * Returns true if the file has the expected md5 hash, false otherwise. - */ -bool FileSpec:: -check_hash(const string &pathname) const { - FileSpec other; - if (!other.read_hash(pathname)) { - return false; - } - - return (memcmp(_hash, other._hash, hash_size) == 0); -} - -/** - * Computes the hash from the indicated pathname and stores it within the - * FileSpec. - */ -bool FileSpec:: -read_hash(const string &pathname) { - memset(_hash, 0, hash_size); - _got_hash = false; - - ifstream stream; -#ifdef _WIN32 - wstring pathname_w; - if (string_to_wstring(pathname_w, pathname)) { - stream.open(pathname_w.c_str(), std::ios::in | std::ios::binary); - } -#else // _WIN32 - stream.open(pathname.c_str(), std::ios::in | std::ios::binary); -#endif // _WIN32 - - if (!stream) { - // cerr << "unable to read " << pathname << "\n"; - return false; - } - - MD5_CTX ctx; - MD5_Init(&ctx); - - static const int buffer_size = 4096; - char buffer[buffer_size]; - - stream.read(buffer, buffer_size); - size_t count = stream.gcount(); - while (count != 0) { - MD5_Update(&ctx, buffer, count); - stream.read(buffer, buffer_size); - count = stream.gcount(); - } - - MD5_Final(_hash, &ctx); - _got_hash = true; - - return true; -} - -/** - * Reads the hash from the next 16 bytes on the indicated istream, in the same - * unusual order observed by Panda's HashVal::read_stream() method. - */ -bool FileSpec:: -read_hash_stream(istream &in) { - for (int i = 0; i < hash_size; i += 4) { - unsigned int a = in.get(); - unsigned int b = in.get(); - unsigned int c = in.get(); - unsigned int d = in.get(); - _hash[i + 0] = d; - _hash[i + 1] = c; - _hash[i + 2] = b; - _hash[i + 3] = a; - } - - return !in.fail(); -} - -/** - * Returns < 0 if this hash sorts before the other hash, > 0 if it sorts - * after, 0 if they are the same. - */ -int FileSpec:: -compare_hash(const FileSpec &other) const { - return memcmp(_hash, other._hash, hash_size); -} - -/** - * Describes the data in the FileSpec. - */ -void FileSpec:: -write(ostream &out) const { - out << "filename: " << _filename << ", " << _size << " bytes, " - << asctime(localtime(&_timestamp)); - // asctime includes a newline. - out << "hash: "; - stream_hex(out, _hash, hash_size); - out << "\n"; -} - -/** - * Writes just the hash code. - */ -void FileSpec:: -output_hash(ostream &out) const { - stream_hex(out, _hash, hash_size); -} - -/** - * Returns true if the file has the expected md5 hash, false otherwise. - * Updates _actual_file with the data read from disk, including the hash, for - * future reference. - * - * The parameter stp is a pointer to a stat structure. It's declared as a - * void * to get around issues with the nonstandard declaration of this - * structure in Windows. - */ -bool FileSpec:: -priv_check_hash(const string &pathname, void *stp) { - const struct stat &st = *(const struct stat *)stp; - assert(_actual_file == nullptr); - _actual_file = new FileSpec; - _actual_file->_filename = pathname; - _actual_file->_size = st.st_size; - _actual_file->_timestamp = st.st_mtime; - - if (!_actual_file->read_hash(pathname)) { - return false; - } - - return (memcmp(_hash, _actual_file->_hash, hash_size) == 0); -} - -/** - * Decodes the hex string in source into the character array in dest. dest - * must have has least size bytes; source must have size * 2 bytes. - * - * Returns true on success, false if there was a non-hex digit in the string. - */ -bool FileSpec:: -decode_hex(unsigned char *dest, const char *source, size_t size) { - for (size_t i = 0; i < size; ++i) { - int high = decode_hexdigit(source[i * 2]); - int low = decode_hexdigit(source[i * 2 + 1]); - if (high < 0 || low < 0) { - return false; - } - dest[i] = (high << 4) | low; - } - - return true; -} - -/** - * Encodes a character array into a hex string for output. dest must have at - * least size * 2 bytes; source must have size bytes. The result is not null- - * terminated. - */ -void FileSpec:: -encode_hex(char *dest, const unsigned char *source, size_t size) { - for (size_t i = 0; i < size; ++i) { - int high = (source[i] >> 4) & 0xf; - int low = source[i] & 0xf; - dest[2 * i] = encode_hexdigit(high); - dest[2 * i + 1] = encode_hexdigit(low); - } -} - -/** - * Writes the indicated buffer as a string of hex characters to the given - * ostream. - */ -void FileSpec:: -stream_hex(ostream &out, const unsigned char *source, size_t size) { - for (size_t i = 0; i < size; ++i) { - int high = (source[i] >> 4) & 0xf; - int low = source[i] & 0xf; - out.put(encode_hexdigit(high)); - out.put(encode_hexdigit(low)); - } -} diff --git a/direct/src/plugin/fileSpec.h b/direct/src/plugin/fileSpec.h deleted file mode 100644 index 3a661ab603..0000000000 --- a/direct/src/plugin/fileSpec.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file fileSpec.h - * @author drose - * @date 2009-06-29 - */ - -#ifndef FILESPEC_H -#define FILESPEC_H - -#include "get_tinyxml.h" -#include - -/** - * This simple class is used both within the core API in this module, as well - * as within the plugin_npapi plugin implementation, to represent a file on - * disk that may need to be verified or (re)downloaded. - */ -class FileSpec { -public: - FileSpec(); - FileSpec(const FileSpec ©); - void operator = (const FileSpec ©); - ~FileSpec(); - - void load_xml(TiXmlElement *xelement); - void store_xml(TiXmlElement *xelement); - - inline const std::string &get_filename() const; - inline void set_filename(const std::string &filename); - inline std::string get_pathname(const std::string &package_dir) const; - inline size_t get_size() const; - inline time_t get_timestamp() const; - inline bool has_hash() const; - - bool quick_verify(const std::string &package_dir); - bool quick_verify_pathname(const std::string &pathname); - bool full_verify(const std::string &package_dir); - inline const FileSpec *get_actual_file() const; - const FileSpec *force_get_actual_file(const std::string &pathname); - - bool check_hash(const std::string &pathname) const; - bool read_hash(const std::string &pathname); - bool read_hash_stream(std::istream &in); - int compare_hash(const FileSpec &other) const; - - void write(std::ostream &out) const; - void output_hash(std::ostream &out) const; - -private: - bool priv_check_hash(const std::string &pathname, void *stp); - static inline int decode_hexdigit(char c); - static inline char encode_hexdigit(int c); - - static bool decode_hex(unsigned char *dest, const char *source, size_t size); - static void encode_hex(char *dest, const unsigned char *source, size_t size); - static void stream_hex(std::ostream &out, const unsigned char *source, size_t size); - - enum { hash_size = 16 }; - - std::string _filename; - size_t _size; - time_t _timestamp; - unsigned char _hash[hash_size]; - bool _got_hash; - - FileSpec *_actual_file; -}; - -#include "fileSpec.I" - -#endif diff --git a/direct/src/plugin/find_root_dir.cxx b/direct/src/plugin/find_root_dir.cxx deleted file mode 100644 index 7d20461aa9..0000000000 --- a/direct/src/plugin/find_root_dir.cxx +++ /dev/null @@ -1,311 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file find_root_dir.cxx - * @author drose - * @date 2009-06-29 - */ - -#include "find_root_dir.h" -#include "mkdir_complete.h" -#include "get_tinyxml.h" -#include "wstring_encode.h" - -#ifdef _WIN32 -#include -#include -#else -#include -#include -#include -#include -#include -#endif - -using std::cerr; -using std::string; -using std::wstring; - -#ifdef _WIN32 -// From KnownFolders.h (part of Vista SDK): -#define DEFINE_KNOWN_FOLDER(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } -DEFINE_KNOWN_FOLDER(FOLDERID_LocalAppData, 0xF1B32785, 0x6FBA, 0x4FCF, 0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91); -DEFINE_KNOWN_FOLDER(FOLDERID_LocalAppDataLow, 0xA520A1A4, 0x1780, 0x4FF6, 0xBD, 0x18, 0x16, 0x73, 0x43, 0xC5, 0xAF, 0x16); -DEFINE_KNOWN_FOLDER(FOLDERID_InternetCache, 0x352481E8, 0x33BE, 0x4251, 0xBA, 0x85, 0x60, 0x07, 0xCA, 0xED, 0xCF, 0x9D); -#endif // _WIN32 - - -#ifdef _WIN32 -/** - * A wrapper around SHGetSpecialFolderPath(), to return the Panda3D directory - * under the indicated CSIDL folder. - */ -static wstring -get_csidl_dir_w(int csidl) { - static const int buffer_size = MAX_PATH; - wchar_t buffer[buffer_size]; - if (SHGetSpecialFolderPathW(nullptr, buffer, csidl, true)) { - wstring root = buffer; - root += wstring(L"/Panda3D"); - - if (mkdir_complete_w(root, cerr)) { - return root; - } - } - - // Something went wrong. - return wstring(); -} -#endif // _WIN32 - -#ifdef _WIN32 -/** - * Wide-character implementation of find_root_dir_default(), only needed for - * Windows. - */ -static wstring -find_root_dir_default_w() { - // First, use IEIsProtectedModeProcess() to determine if we are running in - // IE's "protected mode" under Vista. - - wstring root; - bool is_protected = false; - HMODULE ieframe = LoadLibrary("ieframe.dll"); - if (ieframe != nullptr) { - typedef HRESULT STDAPICALLTYPE IEIsProtectedModeProcess(BOOL *pbResult); - IEIsProtectedModeProcess *func = (IEIsProtectedModeProcess *)GetProcAddress(ieframe, "IEIsProtectedModeProcess"); - if (func != nullptr) { - BOOL result = false; - HRESULT hr = (*func)(&result); - if (hr == S_OK) { - is_protected = (result != 0); - } - // Any other return value means some error, especially E_NOTIMPL, which - // means we're not running under Vista. In this case we can assume - // we're not running in protected mode. - } - - if (is_protected) { - // If we *are* running in protected mode, we need to use - // FOLDERID_LocalAppDataLow. - - // We should be able to use IEGetWriteableFolderPath() to query this - // folder, but for some reason, that function returns E_ACCESSDENIED on - // FOLDERID_LocalAppDataLow, even though this is certainly a folder we - // have write access to. - - // Well, SHGetKnownFolderPath() does work. This function only exists on - // Vista and above, though, so we still have to pull it out of the DLL - // instead of hard-linking it. - - HMODULE shell32 = LoadLibrary("shell32.dll"); - if (shell32 != nullptr) { - typedef HRESULT STDAPICALLTYPE SHGetKnownFolderPath(REFGUID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath); - SHGetKnownFolderPath *func = (SHGetKnownFolderPath *)GetProcAddress(shell32, "SHGetKnownFolderPath"); - if (func != nullptr) { - LPWSTR cache_path = nullptr; - HRESULT hr = (*func)(FOLDERID_LocalAppDataLow, 0, nullptr, &cache_path); - - if (SUCCEEDED(hr)) { - root = cache_path; - CoTaskMemFree(cache_path); - - root += wstring(L"/Panda3D"); - if (mkdir_complete_w(root, cerr)) { - FreeLibrary(shell32); - FreeLibrary(ieframe); - return root; - } - } - } - FreeLibrary(shell32); - } - - // Couldn't get FOLDERID_LocalAppDataLow for some reason. We're in - // fallback mode now. Use IEGetWriteableFolderPath to get the standard - // cache folder. - typedef HRESULT STDAPICALLTYPE IEGetWriteableFolderPath(REFGUID clsidFolderID, LPWSTR* lppwstrPath); - IEGetWriteableFolderPath *func = (IEGetWriteableFolderPath *)GetProcAddress(ieframe, "IEGetWriteableFolderPath"); - if (func != nullptr) { - LPWSTR cache_path = nullptr; - - // Since we're here, we'll start by asking for LocalAppDataLow, even - // though I know it doesn't work. - HRESULT hr = (*func)(FOLDERID_LocalAppDataLow, &cache_path); - if (FAILED(hr)) { - // This one should work. - hr = (*func)(FOLDERID_InternetCache, &cache_path); - } - - if (SUCCEEDED(hr)) { - root = cache_path; - CoTaskMemFree(cache_path); - root += wstring(L"/Panda3D"); - if (mkdir_complete_w(root, cerr)) { - FreeLibrary(ieframe); - return root; - } - } - } - } - - FreeLibrary(ieframe); - } - - // All right, here we are in the normal, unprotected mode. This is also the - // normal XP codepath. - - // e.g., c:Documents and SettingsLocal SettingsApplication - // DataPanda3D - root = get_csidl_dir_w(CSIDL_LOCAL_APPDATA); - if (!root.empty()) { - return root; - } - - // For some crazy reason, we can't get CSIDL_LOCAL_APPDATA. Fall back to - // the cache folder. - - // e.g. c:Documents and SettingsLocal SettingsTemporary Internet - // FilesPanda3D - root = get_csidl_dir_w(CSIDL_INTERNET_CACHE); - if (!root.empty()) { - return root; - } - - // If we couldn't get any of those folders, huh. Punt and try for the old - // standby GetTempPath, for lack of anything better. - static const int buffer_size = MAX_PATH; - wchar_t buffer[buffer_size]; - if (GetTempPathW(buffer_size, buffer) != 0) { - root = buffer; - root += wstring(L"Panda3D"); - if (mkdir_complete_w(root, cerr)) { - return root; - } - } - - return wstring(); -} -#endif // _WIN32 - - -/** - * Returns the path to the system-default for the root directory. This is - * where we look first. - */ -static string -find_root_dir_default() { -#ifdef _WIN32 - wstring root_w = find_root_dir_default_w(); - if (!root_w.empty()) { - string root; - if (wstring_to_string(root, root_w)) { - return root; - } - } - -#elif defined(__APPLE__) - // e.g., UsersLibraryCachesPanda3D - string root = find_osx_root_dir(); - if (!root.empty()) { - return root; - } - -#else // The Linux/*BSD case - // e.g., home.panda3d - - string root; - const passwd *pwdata = getpwuid(getuid()); - if (pwdata == nullptr) { - char *home = getenv("HOME"); - if (home == nullptr) { - // Beh. Let's hope it never gets to this point. - return "."; - } else { - root = home; - } - } else { - root = pwdata->pw_dir; - } - - root += "/.panda3d"; - if (mkdir(root.c_str(), 0700) == 0 || errno == EEXIST) { - return root; - } - -#endif - - // Couldn't find a directory. Punt. - return "."; -} - - -/** - * Returns the path to the installable Panda3D directory on the user's - * machine. - */ -static string -find_root_dir_actual() { - string root = find_root_dir_default(); - - // Now look for a config.xml file in that directory, which might redirect us - // elsewhere. - string config_filename = root + "/config.xml"; - TiXmlDocument doc(config_filename); - if (!doc.LoadFile()) { - // No config.xml found, or not valid xml. - return root; - } - - TiXmlElement *xconfig = doc.FirstChildElement("config"); - if (xconfig == nullptr) { - // No element within config.xml. - return root; - } - - const char *new_root = xconfig->Attribute("root_dir"); - if (new_root == nullptr || *new_root == '\0') { - // No root_dir specified. - return root; - } - - if (!mkdir_complete(new_root, cerr)) { - // The specified root_dir wasn't valid. - return root; - } - - // We've been redirected to another location. Respect that. - return new_root; -} - -/** - * This is the public interface to the above functions. - */ -string -find_root_dir() { - string root = find_root_dir_actual(); - -#ifdef _WIN32 - // Now map that (possibly utf-8) filename into its 8.3 equivalent, so we can - // safely pass it around to Python and other tools that might not understand - // Unicode filenames. Silly Windows, creating an entirely new and - // incompatible kind of filename. - wstring root_w; - string_to_wstring(root_w, root); - - DWORD length = GetShortPathNameW(root_w.c_str(), nullptr, 0); - wchar_t *short_name = new wchar_t[length]; - GetShortPathNameW(root_w.c_str(), short_name, length); - - wstring_to_string(root, short_name); - delete[] short_name; -#endif // _WIN32 - - return root; -} diff --git a/direct/src/plugin/find_root_dir.h b/direct/src/plugin/find_root_dir.h deleted file mode 100644 index e76be59af3..0000000000 --- a/direct/src/plugin/find_root_dir.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file find_root_dir.h - * @author drose - * @date 2009-06-29 - */ - -#ifndef FIND_ROOT_DIR_H -#define FIND_ROOT_DIR_H - -#include -#include - -std::string find_root_dir(); - -#ifdef __APPLE__ -std::string find_osx_root_dir(); -#endif // __APPLE__ - -#endif diff --git a/direct/src/plugin/find_root_dir_assist.mm b/direct/src/plugin/find_root_dir_assist.mm deleted file mode 100644 index f27693d147..0000000000 --- a/direct/src/plugin/find_root_dir_assist.mm +++ /dev/null @@ -1,87 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file find_root_dir_assist.mm - * @author drose - * @date 2009-04-13 - */ - -#include "find_root_dir.h" - -#ifdef __APPLE__ - -#include -#include - -/** - * Copy the Objective-C string to a C++ string. - */ -static string -NSString_to_cpp_string(NSString *str) { - size_t length = [str length]; - string result; - for (size_t i = 0; i < length; ++i) { - result += (char)[str characterAtIndex: i]; - } - - return result; -} - -/** - * - */ -static string -call_NSSearchPathForDirectories(NSSearchPathDirectory dirkey, NSSearchPathDomainMask domain) { - // Ensure that Carbon has been initialized, and that we have an auto-release - // pool. - NSApplicationLoad(); - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NSArray *paths = NSSearchPathForDirectoriesInDomains(dirkey, domain, YES); - string result; - if ([paths count] != 0) { - result = NSString_to_cpp_string([paths objectAtIndex:0]); - } - [pool release]; - - return result; -} - -/** - * - */ -static string -get_osx_home_directory() { - NSApplicationLoad(); - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NSString *dir = NSHomeDirectory(); - string result = NSString_to_cpp_string(dir); - [pool release]; - - return result; -} - -/** - * - */ -std::string -find_osx_root_dir() { - string result = call_NSSearchPathForDirectories(NSCachesDirectory, NSUserDomainMask); - if (!result.empty()) { - return result + "/Panda3D"; - } - result = get_osx_home_directory(); - if (!result.empty()) { - return result + "/Panda3D"; - } - - return string(); -} - -#endif // __APPLE__ diff --git a/direct/src/plugin/get_tinyxml.h b/direct/src/plugin/get_tinyxml.h deleted file mode 100644 index 12f12f054d..0000000000 --- a/direct/src/plugin/get_tinyxml.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file get_tinyxml.h - * @author drose - * @date 2009-07-01 - */ - -#ifndef GET_TINYXML_H -#define GET_TINYXML_H - -// This header file exists just to include tinyxml.h safely. We need this -// since tinyxml.h requires having the symbol TIXML_USE_STL already defined -// before you include it. - -#ifndef TIXML_USE_STL -#define TIXML_USE_STL -#endif - -#include - -#endif diff --git a/direct/src/plugin/get_twirl_data.cxx b/direct/src/plugin/get_twirl_data.cxx deleted file mode 100644 index 8d1bbd73fd..0000000000 --- a/direct/src/plugin/get_twirl_data.cxx +++ /dev/null @@ -1,963 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file get_twirl_data.cxx - * @author drose - * @date 2011-08-24 - */ - -#include "get_twirl_data.h" -#include - -struct twirl_flip { - int _index; - bool _flip_x; - bool _flip_y; - bool _exchange; -}; - -static twirl_flip twirl_flip_table[twirl_num_steps + 1] = { - { 0, false, false, false }, // 0 - { 1, false, false, false }, // 30 - { 2, false, false, false }, // 60 - { 0, false, true, true }, // 90 - { 1, false, true, true }, // 120 - { 2, false, true, true }, // 150 - { 0, true, true, false }, // 180 - { 1, true, true, false }, // 210 - { 2, true, true, false }, // 240 - { 0, true, false, true }, // 270 - { 1, true, false, true }, // 300 - { 2, true, false, true }, // 330 - { 3, false, false, false } // the "failed" icon -}; - -// These tables are the raw data for the twirl icon data. They're extracted -// with bin2c from the three layers of twirl.xcf, in this directory. -static const unsigned char twirl_0_data[] = { - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, - 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xe4, 0xe4, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xff, 0xfe, 0xfd, 0xff, 0xa5, 0x1f, 0x1f, 0xa5, 0xff, 0xfd, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xff, 0xd7, 0x16, 0x00, 0x00, - 0x16, 0xd7, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xff, 0xeb, 0xba, 0xe6, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0x91, 0x00, 0x05, 0x05, 0x00, 0x91, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xff, 0xfd, 0xfa, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xd7, 0x2f, 0x06, 0x23, 0xa6, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x66, 0x00, 0x04, 0x04, 0x00, 0x66, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0xec, 0xe8, 0xed, 0xfb, 0xff, 0xff, - 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x80, 0x00, - 0x0a, 0x04, 0x0c, 0xb0, 0xff, 0xfe, 0xff, 0xfb, 0x5c, 0x00, 0x03, - 0x03, 0x00, 0x5c, 0xfb, 0xff, 0xfe, 0xff, 0xf9, 0xe9, 0xe8, 0xe8, - 0xe8, 0xf3, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0x7c, 0x08, 0x11, 0x14, 0x03, 0x30, 0xe6, 0xff, 0xff, - 0xfb, 0x5c, 0x00, 0x03, 0x03, 0x00, 0x5c, 0xfb, 0xff, 0xff, 0xfd, - 0xed, 0xe8, 0xe9, 0xe9, 0xe8, 0xf3, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xab, 0x0a, 0x0f, 0x15, 0x13, - 0x07, 0x79, 0xff, 0xff, 0xfd, 0x62, 0x00, 0x03, 0x03, 0x00, 0x61, - 0xfd, 0xff, 0xff, 0xf4, 0xe8, 0xe9, 0xea, 0xe9, 0xe9, 0xf7, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xf1, - 0x2c, 0x0a, 0x14, 0x15, 0x0d, 0x1e, 0xcb, 0xff, 0xff, 0x79, 0x00, - 0x04, 0x04, 0x00, 0x79, 0xff, 0xff, 0xfb, 0xeb, 0xe9, 0xea, 0xe9, - 0xe9, 0xeb, 0xfd, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0x97, 0x04, 0x14, 0x15, 0x18, 0x00, 0x82, - 0xff, 0xff, 0x99, 0x00, 0x03, 0x03, 0x00, 0x99, 0xff, 0xff, 0xf4, - 0xe7, 0xea, 0xea, 0xe9, 0xe8, 0xf5, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xf2, 0x42, 0x03, - 0x17, 0x16, 0x0b, 0x39, 0xe9, 0xff, 0xb5, 0x01, 0x00, 0x00, 0x01, - 0xb6, 0xff, 0xfd, 0xee, 0xe9, 0xea, 0xea, 0xe8, 0xed, 0xfd, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xff, 0xff, 0xdd, 0x8b, 0x84, 0xad, 0xee, 0xff, 0xff, - 0xff, 0xff, 0xc2, 0x18, 0x0b, 0x15, 0x13, 0x09, 0xbf, 0xff, 0xda, - 0x25, 0x00, 0x00, 0x25, 0xd9, 0xff, 0xf9, 0xe9, 0xe9, 0xea, 0xe9, - 0xe9, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf0, 0xe7, 0xe8, 0xf8, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x48, 0x17, 0x1f, - 0x20, 0x3b, 0x98, 0xee, 0xff, 0xff, 0xff, 0xa2, 0x0f, 0x0e, 0x15, - 0x05, 0x7a, 0xff, 0xff, 0x54, 0x00, 0x00, 0x53, 0xff, 0xff, 0xf3, - 0xe8, 0xea, 0xe9, 0xe9, 0xf5, 0xff, 0xfe, 0xff, 0xfc, 0xec, 0xd9, - 0xd3, 0xd2, 0xd1, 0xd9, 0xfb, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xcc, 0x1f, 0x20, 0x28, 0x26, 0x22, 0x1a, 0x4c, 0xbf, 0xff, 0xff, - 0xff, 0x86, 0x02, 0x0e, 0x09, 0x41, 0xfa, 0xff, 0x8d, 0x00, 0x00, - 0x8d, 0xff, 0xfa, 0xee, 0xe8, 0xe9, 0xe8, 0xf3, 0xff, 0xff, 0xff, - 0xf4, 0xdd, 0xd2, 0xd3, 0xd3, 0xd4, 0xd3, 0xd2, 0xf2, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xf0, 0x3f, 0x1a, 0x2a, 0x2b, 0x2a, 0x2a, - 0x1c, 0x28, 0xa1, 0xff, 0xff, 0xff, 0x76, 0x02, 0x04, 0x1e, 0xee, - 0xff, 0xd7, 0x07, 0x07, 0xd7, 0xff, 0xfc, 0xeb, 0xe8, 0xe8, 0xf1, - 0xff, 0xff, 0xff, 0xee, 0xd5, 0xd1, 0xd4, 0xd4, 0xd5, 0xd4, 0xd1, - 0xd7, 0xfa, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xba, 0x28, - 0x1a, 0x28, 0x2b, 0x2a, 0x2d, 0x24, 0x23, 0x87, 0xff, 0xff, 0xff, - 0x80, 0x01, 0x0b, 0xc5, 0xff, 0xff, 0x24, 0x24, 0xff, 0xff, 0xfa, - 0xe9, 0xe7, 0xf2, 0xfe, 0xff, 0xff, 0xe9, 0xd4, 0xd3, 0xd5, 0xd5, - 0xd5, 0xd4, 0xd1, 0xd3, 0xef, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfe, - 0xfe, 0xff, 0xff, 0xc0, 0x4a, 0x1f, 0x22, 0x2e, 0x2c, 0x2b, 0x25, - 0x18, 0x79, 0xfb, 0xff, 0xff, 0x97, 0x0b, 0x7b, 0xff, 0xff, 0x9b, - 0x9b, 0xff, 0xff, 0xf4, 0xe8, 0xf4, 0xff, 0xff, 0xff, 0xe6, 0xd1, - 0xd3, 0xd5, 0xd5, 0xd5, 0xd3, 0xd2, 0xda, 0xf1, 0xff, 0xff, 0xfe, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xef, 0x8e, 0x38, - 0x17, 0x21, 0x29, 0x2b, 0x26, 0x17, 0x81, 0xff, 0xff, 0xff, 0xa0, - 0x94, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xf5, 0xf5, 0xff, 0xff, - 0xff, 0xe8, 0xd1, 0xd3, 0xd5, 0xd4, 0xd3, 0xd1, 0xd7, 0xe7, 0xfa, - 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfe, 0xff, - 0xfe, 0xff, 0xff, 0xd6, 0x95, 0x53, 0x22, 0x1c, 0x20, 0x1c, 0x15, - 0x96, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, - 0xfe, 0xff, 0xff, 0xff, 0xec, 0xd1, 0xd1, 0xd2, 0xd2, 0xd2, 0xdb, - 0xe9, 0xf6, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xee, 0xca, - 0x8d, 0x58, 0x35, 0x24, 0x1e, 0x9f, 0xff, 0xfb, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xed, 0xd3, 0xd3, 0xd6, - 0xdc, 0xe7, 0xf3, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xff, 0xfe, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf3, 0xd1, 0x8f, 0x9c, 0xfc, - 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, - 0xec, 0xe7, 0xf5, 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xe1, 0xac, - 0x8d, 0x85, 0x85, 0x89, 0x9b, 0xb3, 0xc8, 0xe3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf5, - 0xec, 0xe5, 0xdd, 0xd7, 0xd6, 0xd6, 0xd9, 0xe3, 0xf5, 0xff, 0xff, - 0xff, 0xbb, 0x50, 0x30, 0x2f, 0x33, 0x33, 0x32, 0x2f, 0x30, 0x41, - 0x5b, 0x7e, 0xaa, 0xe1, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xf5, 0xe3, 0xd4, 0xc8, 0xbf, 0xb9, 0xb9, 0xba, 0xba, 0xba, 0xb9, - 0xba, 0xc4, 0xe8, 0xff, 0xeb, 0x57, 0x31, 0x44, 0x42, 0x42, 0x42, - 0x42, 0x43, 0x42, 0x3e, 0x38, 0x30, 0x36, 0x45, 0x5c, 0xb4, 0xff, - 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xe6, 0xc8, 0xc0, 0xbb, 0xb9, 0xbc, 0xbe, 0xbf, 0xc0, - 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xb9, 0xc7, 0xf8, 0xeb, 0x57, 0x31, - 0x44, 0x42, 0x42, 0x42, 0x42, 0x43, 0x42, 0x3e, 0x38, 0x30, 0x36, - 0x46, 0x5c, 0xb4, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xe6, 0xc8, 0xc0, 0xbb, 0xb9, - 0xbc, 0xbe, 0xbf, 0xc0, 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xb9, 0xc7, - 0xf8, 0xff, 0xbb, 0x50, 0x30, 0x2f, 0x33, 0x33, 0x32, 0x2f, 0x30, - 0x41, 0x5b, 0x7e, 0xaa, 0xe1, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xff, 0xf5, 0xe3, 0xd4, 0xc8, 0xbf, 0xb9, 0xb9, 0xba, 0xba, 0xba, - 0xb9, 0xba, 0xc4, 0xe8, 0xff, 0xff, 0xff, 0xe1, 0xac, 0x8d, 0x85, - 0x85, 0x89, 0x9b, 0xb3, 0xc8, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xec, 0xe5, - 0xdd, 0xd7, 0xd6, 0xd6, 0xd9, 0xe3, 0xf5, 0xff, 0xff, 0xfe, 0xfd, - 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfb, 0xf2, 0xd5, 0x9f, 0xb2, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xd7, 0xd2, 0xed, 0xfa, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xef, 0xd0, 0x9f, 0x74, 0x5b, 0x4e, 0x4d, 0xba, 0xff, 0xfc, - 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xd9, - 0xa5, 0xa7, 0xae, 0xbc, 0xd1, 0xea, 0xf8, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, - 0xfe, 0xff, 0xff, 0xda, 0xa4, 0x6f, 0x4c, 0x49, 0x4c, 0x48, 0x46, - 0xb3, 0xff, 0xff, 0xff, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xd5, 0xa1, 0xa4, 0xa5, 0xa4, 0xa6, 0xb9, - 0xd4, 0xef, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xed, 0x9e, 0x5c, 0x44, 0x4e, 0x53, - 0x55, 0x50, 0x47, 0xa3, 0xff, 0xff, 0xff, 0xbc, 0xba, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xcf, 0xd4, 0xff, 0xff, 0xff, 0xcd, 0xa2, - 0xa8, 0xaa, 0xa9, 0xa6, 0xa1, 0xaf, 0xd2, 0xf8, 0xff, 0xff, 0xfe, - 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xc5, 0x69, 0x4b, - 0x4f, 0x57, 0x56, 0x55, 0x50, 0x47, 0x9c, 0xff, 0xff, 0xff, 0xb5, - 0x61, 0xb0, 0xff, 0xff, 0xcd, 0xcd, 0xff, 0xff, 0xc3, 0x90, 0xd0, - 0xff, 0xff, 0xfd, 0xc9, 0xa2, 0xa7, 0xaa, 0xaa, 0xab, 0xa6, 0xa5, - 0xb6, 0xe5, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xbe, 0x4f, 0x48, 0x53, 0x55, 0x55, 0x56, 0x4e, 0x50, 0xa7, 0xff, - 0xff, 0xfc, 0xa6, 0x5b, 0x65, 0xde, 0xff, 0xff, 0x92, 0x92, 0xff, - 0xff, 0xe5, 0x90, 0x8c, 0xc6, 0xff, 0xff, 0xff, 0xcf, 0xa6, 0xa7, - 0xaa, 0xa9, 0xaa, 0xa9, 0xa3, 0xa9, 0xe3, 0xff, 0xff, 0xfe, 0xfe, - 0xfe, 0xff, 0xff, 0xed, 0x5f, 0x48, 0x54, 0x55, 0x54, 0x54, 0x47, - 0x57, 0xbb, 0xff, 0xff, 0xff, 0xa1, 0x5c, 0x5f, 0x72, 0xf7, 0xff, - 0xeb, 0x83, 0x83, 0xeb, 0xff, 0xf7, 0x99, 0x8d, 0x8c, 0xc1, 0xff, - 0xff, 0xff, 0xd9, 0xa9, 0xa4, 0xa9, 0xa9, 0xaa, 0xa9, 0xa3, 0xb2, - 0xf9, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xcd, 0x4a, 0x4d, 0x52, - 0x50, 0x4d, 0x49, 0x76, 0xd3, 0xff, 0xff, 0xff, 0xab, 0x5c, 0x66, - 0x62, 0x8a, 0xfd, 0xff, 0xc7, 0x79, 0x79, 0xc7, 0xff, 0xfd, 0xa8, - 0x8f, 0x92, 0x8c, 0xc8, 0xff, 0xff, 0xff, 0xe6, 0xb7, 0xa3, 0xa6, - 0xa7, 0xa8, 0xa5, 0xa5, 0xeb, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xf0, 0x67, 0x45, 0x4b, 0x4d, 0x65, 0xb3, 0xf5, 0xff, 0xff, 0xff, - 0xbd, 0x64, 0x66, 0x6a, 0x5f, 0xaf, 0xff, 0xff, 0xa9, 0x75, 0x75, - 0xa9, 0xff, 0xff, 0xc3, 0x8d, 0x95, 0x91, 0x92, 0xd5, 0xff, 0xff, - 0xff, 0xf8, 0xd5, 0xb0, 0xa5, 0xa5, 0xa2, 0xb5, 0xfa, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xe2, 0xa3, 0xa0, 0xc2, 0xf5, 0xff, - 0xff, 0xff, 0xff, 0xd2, 0x68, 0x65, 0x6a, 0x68, 0x64, 0xd9, 0xff, - 0xed, 0x92, 0x7a, 0x7a, 0x92, 0xed, 0xff, 0xe2, 0x90, 0x94, 0x95, - 0x90, 0x96, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xde, 0xcd, 0xd0, - 0xf1, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xf3, 0x81, 0x5f, 0x6b, 0x6b, - 0x63, 0x86, 0xf3, 0xff, 0xda, 0x81, 0x7f, 0x7f, 0x81, 0xda, 0xff, - 0xf5, 0xa5, 0x90, 0x95, 0x96, 0x8c, 0xa9, 0xf9, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xff, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xb7, - 0x5e, 0x69, 0x69, 0x6c, 0x5b, 0xb4, 0xff, 0xff, 0xcc, 0x75, 0x81, - 0x81, 0x75, 0xcc, 0xff, 0xff, 0xc6, 0x8a, 0x96, 0x95, 0x94, 0x8d, - 0xcf, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xf3, 0x75, 0x63, 0x69, 0x6a, 0x64, 0x73, 0xe2, 0xff, - 0xff, 0xbc, 0x75, 0x81, 0x81, 0x75, 0xbc, 0xff, 0xff, 0xe7, 0x99, - 0x91, 0x95, 0x94, 0x90, 0x9f, 0xf8, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xc5, 0x62, 0x66, 0x6a, 0x68, - 0x62, 0xb0, 0xff, 0xff, 0xfe, 0xb0, 0x77, 0x81, 0x81, 0x77, 0xb0, - 0xfe, 0xff, 0xff, 0xc2, 0x8e, 0x94, 0x95, 0x92, 0x90, 0xd9, 0xff, - 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xa9, - 0x61, 0x68, 0x69, 0x5e, 0x80, 0xf4, 0xff, 0xff, 0xfd, 0xae, 0x77, - 0x81, 0x81, 0x77, 0xae, 0xfd, 0xff, 0xff, 0xf4, 0xa1, 0x8d, 0x94, - 0x93, 0x8f, 0xc4, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xad, 0x5c, 0x62, 0x5e, 0x68, 0xd3, 0xff, 0xfe, - 0xff, 0xfd, 0xae, 0x77, 0x81, 0x81, 0x77, 0xae, 0xfd, 0xff, 0xfe, - 0xff, 0xdb, 0x91, 0x8d, 0x90, 0x8b, 0xc5, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xe7, 0x7f, 0x62, 0x78, - 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb3, 0x75, 0x81, 0x81, 0x75, - 0xb3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd6, 0x9b, 0x8e, 0xa0, 0xed, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xff, - 0xff, 0xf6, 0xdc, 0xf4, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xc8, - 0x75, 0x82, 0x82, 0x75, 0xc8, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xf4, 0xe0, 0xf6, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xfe, 0xff, 0xeb, 0x8a, 0x76, 0x76, 0x8a, 0xeb, 0xff, 0xfe, - 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xd2, 0x8f, 0x8f, - 0xd2, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xf1, 0xf1, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff -}; - -static const unsigned char twirl_30_data[] = { - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, - 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xe7, 0xe7, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xff, 0xfe, 0xfd, 0xff, 0xac, 0x31, 0x31, 0xac, 0xff, 0xfd, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xff, 0xda, 0x28, 0x02, 0x02, - 0x28, 0xda, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xff, 0xed, 0xc1, 0xe9, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0x9a, 0x02, 0x1a, 0x1a, 0x02, 0x9a, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xff, 0xed, 0xc2, 0xef, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xdb, 0x42, 0x1d, 0x37, 0xae, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x73, 0x01, 0x18, 0x18, 0x01, 0x73, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xab, 0x18, 0x00, 0x23, 0xd7, 0xff, 0xff, - 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x8c, 0x18, - 0x21, 0x1b, 0x23, 0xb7, 0xff, 0xfe, 0xff, 0xfb, 0x6a, 0x05, 0x17, - 0x17, 0x05, 0x6a, 0xfb, 0xff, 0xfe, 0xff, 0xb4, 0x00, 0x00, 0x00, - 0x00, 0x73, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0x88, 0x1f, 0x28, 0x2a, 0x1b, 0x44, 0xe8, 0xff, 0xff, - 0xfb, 0x6a, 0x05, 0x17, 0x17, 0x05, 0x6a, 0xfb, 0xff, 0xff, 0xec, - 0x25, 0x00, 0x00, 0x00, 0x00, 0x6b, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xb4, 0x21, 0x25, 0x2b, 0x29, - 0x1e, 0x86, 0xff, 0xff, 0xfd, 0x6e, 0x04, 0x17, 0x17, 0x04, 0x6e, - 0xfd, 0xff, 0xff, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xf3, - 0x3f, 0x21, 0x2a, 0x2b, 0x24, 0x34, 0xd0, 0xff, 0xff, 0x85, 0x00, - 0x18, 0x18, 0x00, 0x84, 0xff, 0xff, 0xce, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x13, 0xea, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xa1, 0x1b, 0x2a, 0x2b, 0x2e, 0x16, 0x8e, - 0xff, 0xff, 0xa2, 0x01, 0x18, 0x18, 0x01, 0xa2, 0xff, 0xff, 0x7f, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x83, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xf3, 0x54, 0x1b, - 0x2d, 0x2c, 0x22, 0x4b, 0xeb, 0xff, 0xbc, 0x16, 0x13, 0x13, 0x16, - 0xbc, 0xff, 0xea, 0x2f, 0x00, 0x02, 0x02, 0x00, 0x28, 0xeb, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xff, 0xff, 0xe0, 0x96, 0x91, 0xb5, 0xf0, 0xff, 0xff, - 0xff, 0xff, 0xc8, 0x2e, 0x22, 0x2b, 0x29, 0x20, 0xc5, 0xff, 0xdd, - 0x37, 0x0b, 0x0b, 0x36, 0xdd, 0xff, 0xc0, 0x00, 0x00, 0x01, 0x00, - 0x00, 0xb2, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xf7, 0xf3, 0xf3, 0xfb, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x5a, 0x2e, 0x35, - 0x36, 0x4e, 0xa2, 0xf0, 0xff, 0xff, 0xff, 0xab, 0x26, 0x24, 0x2b, - 0x1c, 0x87, 0xff, 0xff, 0x62, 0x02, 0x02, 0x61, 0xff, 0xff, 0x76, - 0x00, 0x00, 0x00, 0x00, 0x8d, 0xff, 0xff, 0xff, 0xfd, 0xf6, 0xec, - 0xe8, 0xe8, 0xe8, 0xec, 0xfd, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xd1, 0x35, 0x36, 0x3d, 0x3b, 0x38, 0x31, 0x5d, 0xc5, 0xff, 0xff, - 0xff, 0x91, 0x1a, 0x25, 0x20, 0x52, 0xfb, 0xff, 0x97, 0x09, 0x09, - 0x97, 0xff, 0xfc, 0x36, 0x00, 0x00, 0x00, 0x6f, 0xff, 0xff, 0xff, - 0xf9, 0xee, 0xe8, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xf9, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xf2, 0x52, 0x31, 0x3f, 0x40, 0x3f, 0x3f, - 0x32, 0x3d, 0xaa, 0xff, 0xff, 0xff, 0x83, 0x19, 0x1b, 0x33, 0xef, - 0xff, 0xdb, 0x1c, 0x1c, 0xdb, 0xff, 0xf1, 0x0d, 0x00, 0x00, 0x5e, - 0xff, 0xff, 0xff, 0xf7, 0xea, 0xe8, 0xe9, 0xe9, 0xea, 0xe9, 0xe8, - 0xeb, 0xfd, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xc0, 0x3d, - 0x30, 0x3d, 0x40, 0x3f, 0x41, 0x39, 0x38, 0x93, 0xff, 0xff, 0xff, - 0x8c, 0x19, 0x22, 0xcb, 0xff, 0xff, 0x36, 0x37, 0xff, 0xff, 0xc8, - 0x00, 0x00, 0x68, 0xfb, 0xff, 0xff, 0xf4, 0xe9, 0xe9, 0xea, 0xea, - 0xea, 0xe9, 0xe8, 0xe9, 0xf7, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfe, - 0xfe, 0xff, 0xff, 0xc7, 0x5c, 0x35, 0x38, 0x42, 0x41, 0x40, 0x3b, - 0x2f, 0x86, 0xfb, 0xff, 0xff, 0xa1, 0x22, 0x88, 0xff, 0xff, 0xa3, - 0xa3, 0xff, 0xff, 0x77, 0x00, 0x81, 0xff, 0xff, 0xfe, 0xf2, 0xe8, - 0xe9, 0xea, 0xea, 0xea, 0xe9, 0xe8, 0xec, 0xf8, 0xff, 0xff, 0xfe, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xf0, 0x99, 0x4c, - 0x2e, 0x37, 0x3e, 0x40, 0x3b, 0x2e, 0x8e, 0xff, 0xff, 0xff, 0xa9, - 0x9e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x89, 0x8b, 0xff, 0xff, - 0xff, 0xf3, 0xe8, 0xe9, 0xea, 0xe9, 0xe9, 0xe8, 0xeb, 0xf3, 0xfd, - 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfe, 0xff, - 0xfe, 0xff, 0xff, 0xda, 0x9f, 0x63, 0x38, 0x32, 0x36, 0x32, 0x2c, - 0xa0, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, - 0xfc, 0xff, 0xff, 0xff, 0xf5, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xed, - 0xf4, 0xfa, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xcf, - 0x99, 0x69, 0x4a, 0x3a, 0x34, 0xa9, 0xff, 0xfb, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xfc, 0xff, 0xf6, 0xe9, 0xe9, 0xea, - 0xee, 0xf3, 0xf9, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xff, 0xfe, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xf4, 0xd5, 0x9a, 0xa6, 0xfc, - 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, - 0xf5, 0xf3, 0xf9, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xe4, 0xb5, - 0x99, 0x93, 0x92, 0x96, 0xa6, 0xbb, 0xce, 0xe6, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0xf2, 0xee, 0xe8, 0xe5, 0xe4, 0xe4, 0xe6, 0xed, 0xf8, 0xff, 0xff, - 0xff, 0xc3, 0x63, 0x47, 0x46, 0x49, 0x49, 0x49, 0x46, 0x46, 0x56, - 0x6d, 0x8d, 0xb3, 0xe4, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xf8, 0xec, 0xe2, 0xdb, 0xd5, 0xd1, 0xd1, 0xd2, 0xd2, 0xd2, 0xd1, - 0xd1, 0xd8, 0xf0, 0xff, 0xed, 0x6a, 0x47, 0x58, 0x57, 0x57, 0x57, - 0x57, 0x57, 0x57, 0x53, 0x4e, 0x47, 0x4c, 0x5a, 0x6d, 0xbc, 0xff, - 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xee, 0xdb, 0xd6, 0xd2, 0xd1, 0xd3, 0xd4, 0xd5, 0xd5, - 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd1, 0xda, 0xfa, 0xed, 0x69, 0x47, - 0x58, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x53, 0x4e, 0x47, 0x4c, - 0x5a, 0x6d, 0xbc, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xee, 0xdb, 0xd6, 0xd2, 0xd1, - 0xd3, 0xd4, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd1, 0xda, - 0xfa, 0xff, 0xc3, 0x63, 0x47, 0x46, 0x49, 0x49, 0x49, 0x46, 0x46, - 0x56, 0x6d, 0x8d, 0xb3, 0xe4, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xff, 0xf8, 0xec, 0xe2, 0xdb, 0xd5, 0xd1, 0xd1, 0xd2, 0xd2, 0xd2, - 0xd1, 0xd1, 0xd8, 0xf0, 0xff, 0xff, 0xff, 0xe4, 0xb5, 0x99, 0x93, - 0x92, 0x96, 0xa6, 0xbb, 0xce, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf2, 0xee, - 0xe8, 0xe5, 0xe4, 0xe4, 0xe6, 0xed, 0xf8, 0xff, 0xff, 0xfe, 0xfd, - 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0xf4, 0xda, 0xab, 0xbb, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xe1, 0xdd, 0xf1, 0xfb, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf1, 0xd6, 0xaa, 0x86, 0x6f, 0x63, 0x63, 0xc2, 0xff, 0xfc, - 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xe2, - 0xbb, 0xbd, 0xc2, 0xcd, 0xdd, 0xef, 0xf9, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, - 0xfe, 0xff, 0xff, 0xde, 0xb0, 0x80, 0x62, 0x60, 0x62, 0x5f, 0x5d, - 0xbd, 0xff, 0xff, 0xff, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xdf, 0xb8, 0xba, 0xbb, 0xba, 0xbc, 0xca, - 0xdf, 0xf3, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xef, 0xaa, 0x70, 0x5b, 0x64, 0x69, - 0x6a, 0x66, 0x5e, 0xae, 0xff, 0xff, 0xff, 0xc5, 0xc4, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xd8, 0xdc, 0xff, 0xff, 0xff, 0xd9, 0xb9, - 0xbd, 0xbf, 0xbe, 0xbc, 0xb8, 0xc3, 0xdd, 0xfa, 0xff, 0xff, 0xfe, - 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xcd, 0x7b, 0x61, - 0x65, 0x6c, 0x6b, 0x6a, 0x65, 0x5e, 0xa8, 0xff, 0xff, 0xff, 0xc0, - 0x78, 0xbc, 0xff, 0xff, 0xd5, 0xd5, 0xff, 0xff, 0xcf, 0xa6, 0xd9, - 0xff, 0xff, 0xfd, 0xd6, 0xb9, 0xbd, 0xbf, 0xbf, 0xc0, 0xbc, 0xbb, - 0xc8, 0xec, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xc6, 0x64, 0x5e, 0x68, 0x6a, 0x6a, 0x6b, 0x64, 0x66, 0xb2, 0xff, - 0xff, 0xfc, 0xb3, 0x73, 0x7c, 0xe4, 0xff, 0xff, 0xa4, 0xa4, 0xff, - 0xff, 0xea, 0xa6, 0xa2, 0xd1, 0xff, 0xff, 0xff, 0xdb, 0xbc, 0xbc, - 0xbf, 0xbf, 0xbf, 0xbe, 0xb9, 0xbe, 0xe9, 0xff, 0xff, 0xfe, 0xfe, - 0xfe, 0xff, 0xff, 0xf0, 0x72, 0x5f, 0x69, 0x6a, 0x69, 0x69, 0x5e, - 0x6c, 0xc4, 0xff, 0xff, 0xff, 0xae, 0x74, 0x77, 0x86, 0xf8, 0xff, - 0xee, 0x98, 0x98, 0xee, 0xff, 0xf9, 0xad, 0xa3, 0xa3, 0xce, 0xff, - 0xff, 0xff, 0xe2, 0xbe, 0xba, 0xbe, 0xbe, 0xbf, 0xbe, 0xba, 0xc5, - 0xfa, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xd3, 0x60, 0x63, 0x67, - 0x66, 0x63, 0x5f, 0x87, 0xd8, 0xff, 0xff, 0xff, 0xb7, 0x74, 0x7d, - 0x79, 0x9b, 0xfd, 0xff, 0xd0, 0x8f, 0x8f, 0xd0, 0xff, 0xfd, 0xba, - 0xa5, 0xa7, 0xa3, 0xd3, 0xff, 0xff, 0xff, 0xec, 0xc9, 0xba, 0xbc, - 0xbd, 0xbe, 0xbb, 0xbb, 0xef, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xf2, 0x7a, 0x5c, 0x62, 0x63, 0x78, 0xbd, 0xf7, 0xff, 0xff, 0xff, - 0xc6, 0x7b, 0x7d, 0x80, 0x77, 0xbb, 0xff, 0xff, 0xb7, 0x8c, 0x8c, - 0xb7, 0xff, 0xff, 0xcf, 0xa4, 0xaa, 0xa7, 0xa7, 0xdd, 0xff, 0xff, - 0xff, 0xfa, 0xe0, 0xc4, 0xbb, 0xbb, 0xb9, 0xc8, 0xfb, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xe6, 0xae, 0xab, 0xca, 0xf6, 0xff, - 0xff, 0xff, 0xff, 0xd8, 0x7e, 0x7b, 0x80, 0x7f, 0x7b, 0xdf, 0xff, - 0xef, 0xa4, 0x90, 0x90, 0xa4, 0xef, 0xff, 0xe8, 0xa6, 0xa9, 0xaa, - 0xa6, 0xab, 0xe9, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xe6, 0xda, 0xdb, - 0xf5, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xf5, 0x94, 0x77, 0x81, 0x81, - 0x7a, 0x97, 0xf5, 0xff, 0xe0, 0x95, 0x94, 0x94, 0x95, 0xe0, 0xff, - 0xf7, 0xb7, 0xa6, 0xaa, 0xaa, 0xa3, 0xba, 0xfa, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xff, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xc1, - 0x76, 0x7f, 0x7f, 0x81, 0x74, 0xbf, 0xff, 0xff, 0xd5, 0x8c, 0x96, - 0x96, 0x8c, 0xd5, 0xff, 0xff, 0xd1, 0xa1, 0xab, 0xaa, 0xa9, 0xa4, - 0xd9, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xf5, 0x89, 0x7a, 0x7f, 0x80, 0x7b, 0x88, 0xe6, 0xff, - 0xff, 0xc7, 0x8b, 0x96, 0x96, 0x8b, 0xc7, 0xff, 0xff, 0xec, 0xad, - 0xa7, 0xaa, 0xa9, 0xa6, 0xb2, 0xfa, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xce, 0x79, 0x7d, 0x80, 0x7e, - 0x79, 0xbb, 0xff, 0xff, 0xfe, 0xbd, 0x8d, 0x96, 0x96, 0x8d, 0xbd, - 0xfe, 0xff, 0xff, 0xce, 0xa5, 0xa9, 0xaa, 0xa7, 0xa6, 0xe1, 0xff, - 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xb5, - 0x78, 0x7e, 0x7f, 0x75, 0x92, 0xf5, 0xff, 0xff, 0xfd, 0xbb, 0x8d, - 0x96, 0x96, 0x8d, 0xbb, 0xfd, 0xff, 0xff, 0xf6, 0xb4, 0xa3, 0xa9, - 0xa8, 0xa5, 0xcf, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xb9, 0x74, 0x79, 0x76, 0x7e, 0xda, 0xff, 0xfe, - 0xff, 0xfd, 0xbb, 0x8d, 0x96, 0x96, 0x8d, 0xbb, 0xfd, 0xff, 0xfe, - 0xff, 0xe2, 0xa7, 0xa3, 0xa6, 0xa2, 0xd1, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xeb, 0x91, 0x78, 0x8c, - 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x8b, 0x96, 0x96, 0x8b, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xaf, 0xa4, 0xb3, 0xf0, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xff, - 0xff, 0xf7, 0xe0, 0xf6, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xd1, - 0x8c, 0x97, 0x97, 0x8c, 0xd1, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xf6, 0xe6, 0xf8, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xfe, 0xff, 0xee, 0x9e, 0x8c, 0x8c, 0x9e, 0xee, 0xff, 0xfe, - 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xd9, 0xa2, 0xa2, - 0xd9, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xf4, 0xf4, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff -}; - -static const unsigned char twirl_60_data[] = { - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, - 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xe9, 0xe9, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xff, 0xfe, 0xfd, 0xff, 0xb4, 0x45, 0x45, 0xb4, 0xff, 0xfd, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xff, 0xde, 0x3d, 0x1a, 0x1a, - 0x3d, 0xde, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xff, 0xef, 0xc7, 0xeb, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xa3, 0x1a, 0x2f, 0x2f, 0x1a, 0xa3, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xff, 0xee, 0xc7, 0xf0, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xdf, 0x55, 0x34, 0x4b, 0xb6, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x2e, 0x2e, 0x18, 0x80, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xb2, 0x2c, 0x07, 0x35, 0xda, 0xff, 0xff, - 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x97, 0x2e, - 0x37, 0x32, 0x39, 0xbe, 0xff, 0xfe, 0xff, 0xfc, 0x78, 0x1c, 0x2d, - 0x2d, 0x1c, 0x78, 0xfc, 0xff, 0xfe, 0xff, 0xba, 0x12, 0x03, 0x09, - 0x00, 0x7e, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0x94, 0x35, 0x3d, 0x3f, 0x31, 0x57, 0xeb, 0xff, 0xff, - 0xfb, 0x77, 0x1c, 0x2d, 0x2d, 0x1c, 0x77, 0xfb, 0xff, 0xff, 0xed, - 0x37, 0x02, 0x14, 0x12, 0x07, 0x78, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xbb, 0x37, 0x3b, 0x40, 0x3e, - 0x34, 0x92, 0xff, 0xff, 0xfd, 0x7c, 0x1c, 0x2d, 0x2d, 0x1c, 0x7c, - 0xfd, 0xff, 0xff, 0x83, 0x08, 0x12, 0x15, 0x0f, 0x09, 0xa4, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xf4, - 0x52, 0x37, 0x3f, 0x40, 0x39, 0x47, 0xd5, 0xff, 0xff, 0x90, 0x18, - 0x2e, 0x2e, 0x18, 0x90, 0xff, 0xff, 0xd2, 0x24, 0x0b, 0x15, 0x14, - 0x0b, 0x26, 0xec, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xa9, 0x32, 0x3f, 0x40, 0x43, 0x2d, 0x9a, - 0xff, 0xff, 0xab, 0x19, 0x2e, 0x2e, 0x19, 0xab, 0xff, 0xff, 0x8a, - 0x00, 0x18, 0x14, 0x14, 0x03, 0x8d, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xf4, 0x65, 0x31, - 0x41, 0x41, 0x38, 0x5d, 0xed, 0xff, 0xc2, 0x2c, 0x29, 0x29, 0x2c, - 0xc2, 0xff, 0xec, 0x40, 0x0a, 0x17, 0x17, 0x04, 0x39, 0xed, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xff, 0xff, 0xe4, 0xa2, 0x9c, 0xbd, 0xf1, 0xff, 0xff, - 0xff, 0xff, 0xcd, 0x42, 0x38, 0x40, 0x3e, 0x36, 0xca, 0xff, 0xe0, - 0x49, 0x22, 0x22, 0x49, 0xe0, 0xff, 0xc4, 0x0b, 0x13, 0x16, 0x0d, - 0x12, 0xb8, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xa4, 0x70, 0x74, 0xd4, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x6d, 0x45, 0x4b, - 0x4c, 0x61, 0xac, 0xf1, 0xff, 0xff, 0xff, 0xb3, 0x3b, 0x3a, 0x40, - 0x33, 0x93, 0xff, 0xff, 0x70, 0x1a, 0x1a, 0x70, 0xff, 0xff, 0x81, - 0x04, 0x15, 0x0f, 0x0c, 0x97, 0xff, 0xff, 0xff, 0xf1, 0x8e, 0x19, - 0x00, 0x00, 0x00, 0x1c, 0xe9, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xd6, 0x4b, 0x4c, 0x52, 0x50, 0x4e, 0x47, 0x6f, 0xcc, 0xff, 0xff, - 0xff, 0x9c, 0x31, 0x3b, 0x36, 0x64, 0xfb, 0xff, 0xa0, 0x20, 0x20, - 0xa0, 0xff, 0xfc, 0x47, 0x09, 0x10, 0x00, 0x7b, 0xff, 0xff, 0xff, - 0xbc, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xf3, 0x65, 0x47, 0x54, 0x55, 0x54, 0x54, - 0x49, 0x53, 0xb3, 0xff, 0xff, 0xff, 0x90, 0x30, 0x32, 0x47, 0xf1, - 0xff, 0xde, 0x31, 0x31, 0xde, 0xff, 0xf2, 0x21, 0x05, 0x00, 0x6b, - 0xff, 0xff, 0xff, 0x99, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0f, 0xe5, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xc7, 0x53, - 0x47, 0x53, 0x55, 0x54, 0x56, 0x4f, 0x4e, 0x9f, 0xff, 0xff, 0xff, - 0x97, 0x30, 0x38, 0xd0, 0xff, 0xff, 0x4a, 0x4a, 0xff, 0xff, 0xcc, - 0x0e, 0x00, 0x74, 0xfa, 0xff, 0xff, 0x7b, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x9e, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfe, - 0xfe, 0xff, 0xff, 0xcd, 0x6e, 0x4b, 0x4e, 0x57, 0x56, 0x55, 0x50, - 0x46, 0x93, 0xfc, 0xff, 0xff, 0xaa, 0x38, 0x93, 0xff, 0xff, 0xac, - 0xac, 0xff, 0xff, 0x83, 0x06, 0x8b, 0xff, 0xff, 0xff, 0x6a, 0x00, - 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x1e, 0xa8, 0xff, 0xff, 0xfe, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xf2, 0xa4, 0x60, - 0x44, 0x4d, 0x53, 0x55, 0x51, 0x45, 0x9a, 0xff, 0xff, 0xff, 0xb1, - 0xa8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x92, 0x95, 0xff, 0xff, - 0xff, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x6d, 0xe4, - 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfe, 0xff, - 0xfe, 0xff, 0xff, 0xde, 0xa9, 0x74, 0x4e, 0x49, 0x4c, 0x49, 0x43, - 0xab, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, - 0xfc, 0xff, 0xff, 0xff, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, - 0x77, 0xc7, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xd4, - 0xa4, 0x79, 0x5d, 0x4f, 0x4b, 0xb2, 0xff, 0xfc, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xfa, 0xff, 0x98, 0x00, 0x00, 0x0a, - 0x2f, 0x6e, 0xb9, 0xe7, 0xff, 0xff, 0xfd, 0xfd, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xfc, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xf5, 0xda, 0xa5, 0xb0, 0xfd, - 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, - 0x8b, 0x70, 0xc0, 0xee, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xe8, 0xbe, - 0xa5, 0xa0, 0xa0, 0xa3, 0xb1, 0xc4, 0xd4, 0xe9, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0xf9, 0xf6, 0xf4, 0xf2, 0xf1, 0xf1, 0xf2, 0xf6, 0xfb, 0xff, 0xff, - 0xff, 0xca, 0x76, 0x5e, 0x5d, 0x5f, 0x60, 0x5f, 0x5d, 0x5d, 0x6b, - 0x7f, 0x9b, 0xbd, 0xe7, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xfc, 0xf6, 0xf1, 0xed, 0xea, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, - 0xe8, 0xeb, 0xf7, 0xff, 0xef, 0x7c, 0x5e, 0x6d, 0x6c, 0x6b, 0x6b, - 0x6b, 0x6c, 0x6c, 0x69, 0x63, 0x5e, 0x62, 0x6e, 0x7f, 0xc4, 0xff, - 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xf6, 0xed, 0xea, 0xe9, 0xe8, 0xe9, 0xe9, 0xea, 0xea, - 0xea, 0xea, 0xea, 0xea, 0xea, 0xe8, 0xec, 0xfd, 0xef, 0x7c, 0x5e, - 0x6d, 0x6c, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x69, 0x63, 0x5e, 0x62, - 0x6e, 0x7f, 0xc4, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xf6, 0xed, 0xea, 0xe9, 0xe8, - 0xe9, 0xe9, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xe8, 0xec, - 0xfd, 0xff, 0xca, 0x76, 0x5e, 0x5d, 0x5f, 0x60, 0x5f, 0x5d, 0x5d, - 0x6b, 0x7f, 0x9b, 0xbd, 0xe7, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xff, 0xfc, 0xf6, 0xf1, 0xed, 0xea, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, - 0xe8, 0xe8, 0xeb, 0xf7, 0xff, 0xff, 0xff, 0xe8, 0xbe, 0xa5, 0xa0, - 0xa0, 0xa3, 0xb1, 0xc4, 0xd4, 0xe9, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf9, 0xf6, - 0xf4, 0xf2, 0xf1, 0xf1, 0xf2, 0xf6, 0xfb, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xff, 0xff, 0xfd, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0xf6, 0xdf, 0xb7, 0xc5, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xeb, 0xe8, 0xf6, 0xfd, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf3, 0xdc, 0xb7, 0x98, 0x85, 0x7a, 0x7a, 0xcb, 0xff, 0xfd, - 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xec, - 0xd2, 0xd3, 0xd7, 0xde, 0xe8, 0xf4, 0xfb, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, - 0xfe, 0xff, 0xff, 0xe3, 0xbc, 0x94, 0x7a, 0x77, 0x79, 0x76, 0x75, - 0xc7, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xea, 0xd0, 0xd2, 0xd2, 0xd2, 0xd3, 0xdc, - 0xea, 0xf7, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xf1, 0xb6, 0x85, 0x73, 0x7a, 0x7f, - 0x80, 0x7c, 0x75, 0xba, 0xff, 0xff, 0xff, 0xcf, 0xcd, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xe2, 0xe5, 0xff, 0xff, 0xff, 0xe6, 0xd1, - 0xd4, 0xd5, 0xd4, 0xd3, 0xd1, 0xd8, 0xe8, 0xfb, 0xff, 0xff, 0xfe, - 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xd4, 0x8f, 0x78, - 0x7b, 0x82, 0x80, 0x80, 0x7c, 0x76, 0xb5, 0xff, 0xff, 0xff, 0xcb, - 0x8e, 0xc7, 0xff, 0xff, 0xde, 0xde, 0xff, 0xff, 0xda, 0xbc, 0xe3, - 0xff, 0xff, 0xfe, 0xe4, 0xd1, 0xd3, 0xd5, 0xd5, 0xd5, 0xd3, 0xd2, - 0xdb, 0xf2, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xcf, 0x7b, 0x76, 0x7e, 0x80, 0x80, 0x81, 0x7b, 0x7d, 0xbd, 0xff, - 0xff, 0xfd, 0xc0, 0x8a, 0x91, 0xe8, 0xff, 0xff, 0xb6, 0xb6, 0xff, - 0xff, 0xef, 0xbc, 0xb9, 0xdc, 0xff, 0xff, 0xff, 0xe7, 0xd3, 0xd3, - 0xd5, 0xd4, 0xd5, 0xd4, 0xd1, 0xd4, 0xf1, 0xff, 0xff, 0xfe, 0xfe, - 0xfe, 0xff, 0xff, 0xf2, 0x87, 0x76, 0x7f, 0x80, 0x7f, 0x7f, 0x76, - 0x81, 0xcc, 0xff, 0xff, 0xff, 0xbc, 0x8b, 0x8d, 0x9a, 0xf9, 0xff, - 0xf1, 0xac, 0xac, 0xf1, 0xff, 0xfa, 0xc1, 0xba, 0xb9, 0xda, 0xff, - 0xff, 0xff, 0xec, 0xd4, 0xd2, 0xd4, 0xd4, 0xd5, 0xd4, 0xd1, 0xd9, - 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xda, 0x78, 0x7a, 0x7e, - 0x7c, 0x7a, 0x76, 0x98, 0xdd, 0xff, 0xff, 0xff, 0xc3, 0x8b, 0x92, - 0x8f, 0xab, 0xfd, 0xff, 0xd9, 0xa5, 0xa5, 0xd9, 0xff, 0xfd, 0xcb, - 0xbb, 0xbd, 0xba, 0xde, 0xff, 0xff, 0xff, 0xf2, 0xdb, 0xd1, 0xd3, - 0xd4, 0xd4, 0xd2, 0xd2, 0xf5, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xf4, 0x8e, 0x74, 0x79, 0x7a, 0x8c, 0xc7, 0xf8, 0xff, 0xff, 0xff, - 0xcf, 0x90, 0x92, 0x95, 0x8d, 0xc6, 0xff, 0xff, 0xc6, 0xa3, 0xa3, - 0xc6, 0xff, 0xff, 0xda, 0xba, 0xbf, 0xbd, 0xbd, 0xe5, 0xff, 0xff, - 0xff, 0xfb, 0xea, 0xd8, 0xd2, 0xd2, 0xd1, 0xda, 0xfc, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xea, 0xba, 0xb8, 0xd1, 0xf7, 0xff, - 0xff, 0xff, 0xff, 0xdf, 0x93, 0x91, 0x95, 0x94, 0x91, 0xe5, 0xff, - 0xf3, 0xb6, 0xa6, 0xa6, 0xb6, 0xf3, 0xff, 0xed, 0xbb, 0xbe, 0xbf, - 0xbc, 0xbf, 0xee, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xee, 0xe6, 0xe8, - 0xf8, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xf6, 0xa5, 0x8d, 0x96, 0x95, - 0x90, 0xa8, 0xf6, 0xff, 0xe6, 0xaa, 0xa9, 0xa9, 0xaa, 0xe6, 0xff, - 0xf9, 0xc9, 0xbc, 0xbf, 0xbf, 0xba, 0xcb, 0xfb, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xff, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xcc, - 0x8d, 0x94, 0x94, 0x96, 0x8a, 0xc9, 0xff, 0xff, 0xdd, 0xa2, 0xab, - 0xab, 0xa2, 0xdd, 0xff, 0xff, 0xdd, 0xb9, 0xc0, 0xbf, 0xbe, 0xba, - 0xe2, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xf6, 0x9c, 0x90, 0x94, 0x95, 0x90, 0x9b, 0xea, 0xff, - 0xff, 0xd3, 0xa2, 0xab, 0xab, 0xa2, 0xd3, 0xff, 0xff, 0xf1, 0xc1, - 0xbc, 0xbf, 0xbe, 0xbc, 0xc5, 0xfb, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xd6, 0x8f, 0x92, 0x95, 0x93, - 0x8f, 0xc6, 0xff, 0xff, 0xfe, 0xca, 0xa4, 0xab, 0xab, 0xa4, 0xca, - 0xfe, 0xff, 0xff, 0xda, 0xbb, 0xbe, 0xbf, 0xbd, 0xbc, 0xe8, 0xff, - 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xc1, - 0x8f, 0x93, 0x94, 0x8c, 0xa4, 0xf7, 0xff, 0xff, 0xfd, 0xc8, 0xa4, - 0xaa, 0xaa, 0xa4, 0xc8, 0xfd, 0xff, 0xff, 0xf8, 0xc6, 0xba, 0xbe, - 0xbe, 0xbb, 0xdb, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xc5, 0x8b, 0x8f, 0x8c, 0x93, 0xe0, 0xff, 0xfe, - 0xff, 0xfd, 0xc9, 0xa4, 0xab, 0xab, 0xa4, 0xc9, 0xfd, 0xff, 0xfe, - 0xff, 0xe9, 0xbc, 0xba, 0xbb, 0xb9, 0xdc, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xee, 0xa3, 0x8f, 0x9f, - 0xdc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xa2, 0xab, 0xab, 0xa2, - 0xcc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xbb, 0xc6, 0xf4, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xff, - 0xff, 0xf8, 0xe5, 0xf7, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xda, - 0xa3, 0xab, 0xab, 0xa3, 0xda, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xf8, 0xec, 0xf9, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, - 0xff, 0xfe, 0xff, 0xf1, 0xb1, 0xa3, 0xa3, 0xb1, 0xf1, 0xff, 0xfe, - 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xe1, 0xb4, 0xb4, - 0xe1, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xf6, 0xf6, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff -}; - -// Also, the "failed" icon. -const unsigned char failed_data[] = { - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, - 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfb, 0xfb, 0xfe, 0xff, 0xfe, - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, - 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfd, 0xff, 0xfa, 0x91, 0x93, 0xfd, 0xff, 0xfd, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xfe, 0xfc, 0xff, 0x8c, 0x00, 0x00, 0x8f, 0xff, - 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xcf, 0x0f, - 0x00, 0x00, 0x0f, 0xcf, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xff, 0x51, 0x00, 0x01, 0x01, 0x00, 0x51, 0xff, 0xff, 0xfe, - 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xa4, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xef, 0x1e, 0x00, - 0x00, 0x55, 0x54, 0x00, 0x00, 0x1f, 0xf0, 0xff, 0xfe, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, - 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0x6a, 0x00, 0x00, 0x1c, 0xbf, 0xbe, 0x1c, 0x00, 0x00, 0x68, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xfe, 0xfb, 0xff, 0xbb, 0x03, 0x00, 0x00, 0x7d, 0xd2, 0xd2, - 0x7e, 0x00, 0x00, 0x03, 0xbc, 0xff, 0xfb, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xf7, 0x3c, 0x00, 0x00, - 0x3f, 0xc6, 0xc4, 0xc4, 0xc6, 0x3e, 0x00, 0x00, 0x3d, 0xf8, 0xff, - 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, - 0x8b, 0x00, 0x00, 0x0c, 0xa1, 0xcd, 0xc0, 0xc0, 0xcd, 0xa1, 0x0c, - 0x00, 0x00, 0x89, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xcf, 0x09, 0x00, 0x00, 0x6c, 0xd4, 0xc2, 0xc0, - 0xc0, 0xc2, 0xd4, 0x6d, 0x00, 0x00, 0x09, 0xd0, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, - 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x4a, 0x00, 0x00, 0x29, - 0xc3, 0xca, 0xc7, 0xd0, 0xd0, 0xc7, 0xca, 0xc3, 0x29, 0x00, 0x00, - 0x4a, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xa5, - 0x00, 0x00, 0x00, 0x90, 0xd1, 0xc7, 0xb2, 0x52, 0x52, 0xb2, 0xc7, - 0xd1, 0x91, 0x00, 0x00, 0x00, 0xa6, 0xff, 0xfe, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfc, 0xff, 0xeb, 0x25, 0x00, 0x00, 0x53, 0xc9, 0xc4, 0xd2, 0x6b, - 0x00, 0x00, 0x6b, 0xd2, 0xc4, 0xc9, 0x53, 0x00, 0x00, 0x25, 0xec, - 0xff, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0x69, 0x00, 0x00, 0x20, 0xb3, - 0xcb, 0xbe, 0xd5, 0x58, 0x00, 0x00, 0x58, 0xd5, 0xbe, 0xcb, 0xb3, - 0x21, 0x00, 0x00, 0x69, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xb7, 0x01, - 0x00, 0x00, 0x7e, 0xd3, 0xc0, 0xbf, 0xd4, 0x5d, 0x00, 0x00, 0x5d, - 0xd4, 0xbf, 0xc0, 0xd3, 0x7f, 0x00, 0x00, 0x01, 0xb8, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xf5, 0x36, 0x00, 0x00, 0x3f, 0xc9, 0xc5, 0xc2, 0xbf, 0xd4, - 0x5d, 0x00, 0x00, 0x5d, 0xd4, 0xbf, 0xc2, 0xc5, 0xca, 0x3f, 0x00, - 0x00, 0x37, 0xf6, 0xff, 0xfe, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0x87, 0x00, 0x00, 0x07, 0xa6, 0xcd, - 0xc2, 0xc3, 0xbf, 0xd4, 0x5d, 0x00, 0x00, 0x5d, 0xd4, 0xbf, 0xc3, - 0xc2, 0xcd, 0xa6, 0x07, 0x00, 0x00, 0x85, 0xff, 0xff, 0xfe, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, - 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xff, 0xd4, 0x06, 0x00, - 0x00, 0x6c, 0xd3, 0xc5, 0xc2, 0xc3, 0xbf, 0xd4, 0x5d, 0x00, 0x00, - 0x5d, 0xd4, 0xbf, 0xc2, 0xc2, 0xc5, 0xd3, 0x6d, 0x00, 0x00, 0x06, - 0xd5, 0xff, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, - 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0x4e, 0x00, 0x00, 0x2e, 0xbe, 0xcd, 0xc2, 0xc2, 0xc2, 0xbf, - 0xd4, 0x5d, 0x00, 0x00, 0x5d, 0xd4, 0xbf, 0xc3, 0xc2, 0xc2, 0xcd, - 0xbe, 0x2e, 0x00, 0x00, 0x4f, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xfe, 0xfb, 0xff, 0xa2, 0x00, 0x00, 0x02, 0x8f, 0xcf, 0xc3, - 0xc2, 0xc2, 0xc2, 0xbf, 0xd4, 0x5d, 0x00, 0x00, 0x5d, 0xd4, 0xbf, - 0xc3, 0xc2, 0xc2, 0xc3, 0xcf, 0x8f, 0x02, 0x00, 0x00, 0xa1, 0xff, - 0xfb, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfd, 0xff, 0xe6, 0x27, 0x00, 0x00, - 0x53, 0xcb, 0xc2, 0xc2, 0xc3, 0xc2, 0xc3, 0xbf, 0xd4, 0x5c, 0x00, - 0x00, 0x5c, 0xd4, 0xbf, 0xc3, 0xc2, 0xc3, 0xc2, 0xc1, 0xcc, 0x54, - 0x00, 0x00, 0x27, 0xe8, 0xff, 0xfd, 0xfe, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0x66, 0x00, 0x00, 0x20, 0xb7, 0xcc, 0xc1, 0xc3, 0xc2, 0xc2, 0xc3, - 0xbf, 0xd4, 0x59, 0x00, 0x00, 0x59, 0xd4, 0xbf, 0xc3, 0xc2, 0xc2, - 0xc3, 0xc1, 0xcc, 0xb7, 0x20, 0x00, 0x00, 0x66, 0xff, 0xff, 0xfe, - 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xfe, 0xff, 0xff, 0xb7, 0x00, 0x00, 0x00, 0x83, 0xd3, 0xc2, 0xc3, - 0xc3, 0xc2, 0xc2, 0xc2, 0xc0, 0xce, 0x86, 0x01, 0x01, 0x86, 0xce, - 0xc0, 0xc3, 0xc2, 0xc2, 0xc2, 0xc3, 0xc2, 0xd3, 0x84, 0x00, 0x00, - 0x00, 0xb8, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfc, 0x30, 0x00, 0x00, 0x3e, - 0xca, 0xc8, 0xc2, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc3, - 0x90, 0x90, 0xc3, 0xc3, 0xc2, 0xc3, 0xc2, 0xc2, 0xc2, 0xc3, 0xc2, - 0xc8, 0xca, 0x3d, 0x00, 0x00, 0x31, 0xfd, 0xff, 0xfe, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8a, - 0x00, 0x00, 0x0a, 0xa2, 0xcf, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, - 0xc3, 0xc3, 0xc2, 0xc3, 0xd3, 0xd3, 0xc3, 0xc2, 0xc3, 0xc3, 0xc2, - 0xc2, 0xc3, 0xc3, 0xc3, 0xc3, 0xcf, 0xa2, 0x0a, 0x00, 0x00, 0x8a, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, - 0xfc, 0xff, 0xcf, 0x0e, 0x00, 0x00, 0x6b, 0xd0, 0xc5, 0xc2, 0xc2, - 0xc3, 0xc3, 0xc2, 0xc2, 0xc3, 0xc3, 0xc1, 0xc9, 0xc5, 0xc5, 0xc9, - 0xc1, 0xc3, 0xc3, 0xc2, 0xc2, 0xc3, 0xc3, 0xc2, 0xc2, 0xc5, 0xd1, - 0x6e, 0x00, 0x00, 0x0e, 0xcf, 0xff, 0xfb, 0xff, 0xfe, 0xfe, 0xfe, - 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0x4e, 0x00, 0x00, 0x31, 0xbf, - 0xc8, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc9, - 0xab, 0x52, 0x52, 0xab, 0xc9, 0xc1, 0xc3, 0xc2, 0xc2, 0xc2, 0xc3, - 0xc2, 0xc2, 0xc2, 0xc8, 0xc0, 0x30, 0x00, 0x00, 0x4f, 0xff, 0xff, - 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xa0, 0x00, - 0x00, 0x04, 0x93, 0xd1, 0xc0, 0xc2, 0xc2, 0xc2, 0xc2, 0xc3, 0xc2, - 0xc2, 0xc2, 0xc0, 0xcf, 0x4c, 0x00, 0x00, 0x4c, 0xcf, 0xc0, 0xc3, - 0xc2, 0xc2, 0xc2, 0xc3, 0xc2, 0xc2, 0xc2, 0xc0, 0xd1, 0x92, 0x04, - 0x00, 0x00, 0x9e, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xe5, 0x1e, 0x00, 0x00, 0x54, 0xcd, 0xc3, 0xc3, 0xc3, 0xc2, - 0xc2, 0xc3, 0xc3, 0xc2, 0xc2, 0xc3, 0xc0, 0xd0, 0x4e, 0x00, 0x00, - 0x4e, 0xd0, 0xc0, 0xc3, 0xc2, 0xc2, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, - 0xc3, 0xc3, 0xce, 0x56, 0x00, 0x00, 0x20, 0xe6, 0xff, 0xfe, 0xfe, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0x60, 0x00, 0x00, 0x1b, 0xba, 0xcc, - 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1, - 0xc7, 0xae, 0x4c, 0x4c, 0xae, 0xc7, 0xc1, 0xc2, 0xc2, 0xc2, 0xc2, - 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xcc, 0xbb, 0x19, 0x00, 0x00, - 0x61, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xbd, 0x00, 0x00, - 0x00, 0x85, 0xd6, 0xc7, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, - 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, 0xcb, 0xd2, 0xd2, 0xcb, 0xc5, 0xc6, - 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc7, - 0xd6, 0x84, 0x00, 0x00, 0x00, 0xbb, 0xff, 0xfe, 0xff, 0xfd, 0xff, - 0xf7, 0x38, 0x00, 0x00, 0x42, 0xbf, 0xc6, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbf, - 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xc6, 0xc0, 0x42, 0x00, 0x00, 0x38, 0xf9, - 0xff, 0xfd, 0xfc, 0xff, 0x83, 0x00, 0x00, 0x00, 0x16, 0x24, 0x20, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x24, 0x16, - 0x00, 0x00, 0x00, 0x82, 0xff, 0xfd, 0xff, 0xfa, 0x34, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0xf7, 0xff, 0xfe, - 0xff, 0x86, 0x12, 0x11, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x12, 0x18, - 0x8a, 0xff, 0xfe, 0xfe, 0xff, 0xfd, 0xd2, 0xc4, 0xc8, 0xc8, 0xc8, - 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, - 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, - 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, - 0xc8, 0xc8, 0xc5, 0xd8, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, - 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, - 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, - 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, - 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff -}; - -static const unsigned char * const twirl_data[4] = { - twirl_0_data, - twirl_30_data, - twirl_60_data, - failed_data -}; - - -/** - * Fills the indicated data array with a string of twirl_width * twirl_height - * * 3 bytes, representing the RGB pixel values of the twirl_width x - * twirl_height image at frame number step of twirl_num_steps frames. The - * specified fg and bg colors are applied to the array appropriately. - * - * Returns true on success, false on failure. On false, the array is - * initialized with zero. - * - * You must pass data_length = twirl_width * twirl_height * 3; this value is - * passed as a sanity check on array size. You should pass step so that 0 <= - * step < twirl_num_steps + 1. (The special value of step == twirl_num_steps - * returns the "failed" icon.) - */ -bool -get_twirl_data(unsigned char data[], size_t data_length, int step, - int fg_r, int fg_g, int fg_b, - int bg_r, int bg_g, int bg_b) { - - if (step < 0 || step >= twirl_num_steps + 1) { - memset(data, 0, data_length); - return false; - } - if (data_length != twirl_width * twirl_height) { - memset(data, 0, data_length); - return false; - } - - twirl_flip &flip = twirl_flip_table[step]; - const unsigned char *in_data = twirl_data[flip._index]; - - for (int yi = 0; yi < twirl_height; ++yi) { - const unsigned char *sp = &in_data[yi * twirl_width]; - for (int xi = 0; xi < twirl_width; ++xi) { - int xo = xi; - int yo = yi; - if (flip._flip_x) { - xo = twirl_width - 1 - xo; - } - if (flip._flip_y) { - yo = twirl_width - 1 - yo; - } - if (flip._exchange) { - int t = xo; - xo = yo; - yo = t; - } - unsigned char *dp = &data[yo * twirl_width * 3]; - dp += 3 * xo; - - double t = (double)(*sp) / 255.0; - ++sp; - - dp[0] = (unsigned char)(fg_r + t * (bg_r - fg_r)); - dp[1] = (unsigned char)(fg_g + t * (bg_g - fg_g)); - dp[2] = (unsigned char)(fg_b + t * (bg_b - fg_b)); - } - } - - return true; -} diff --git a/direct/src/plugin/get_twirl_data.h b/direct/src/plugin/get_twirl_data.h deleted file mode 100644 index 3b021a01e4..0000000000 --- a/direct/src/plugin/get_twirl_data.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file get_twirl_data.h - * @author drose - * @date 2011-08-24 - */ - -#ifndef GET_TWIRL_DATA_H -#define GET_TWIRL_DATA_H - -#include - -static const int twirl_width = 48; -static const int twirl_height = 48; -static const int twirl_num_steps = 12; - -bool get_twirl_data(unsigned char data[], size_t data_length, int step, - int fg_r, int fg_g, int fg_b, - int bg_r, int bg_g, int bg_b); - -#endif diff --git a/direct/src/plugin/handleStream.I b/direct/src/plugin/handleStream.I deleted file mode 100644 index 60021cee96..0000000000 --- a/direct/src/plugin/handleStream.I +++ /dev/null @@ -1,88 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file handleStream.I - * @author drose - * @date 2009-06-05 - */ - -/** - * - */ -inline HandleStream:: -HandleStream() : std::iostream(&_buf) { -} - -/** - * - */ -inline HandleStream:: -~HandleStream() { - close(); -} - -/** - * Attempts to open the given handle for input. The stream may not be - * simultaneously open for input and output. - */ -inline void HandleStream:: -open_read(FHandle handle) { - clear((std::ios::iostatetate)0); - _buf.open_read(handle); - if (!_buf.is_open_read()) { - clear(std::ios::failbit); - } -} - -/** - * Attempts to open the given handle for output. The stream may not be - * simultaneously open for input and output. - */ -inline void HandleStream:: -open_write(FHandle handle) { - clear((std::ios::iostatetate)0); - _buf.open_write(handle); - if (!_buf.is_open_write()) { - clear(std::ios::failbit); - } -} - -/** - * - */ -inline void HandleStream:: -close() { - _buf.close(); -} - -/** - * Closes the underlying handle, *without* attempting to flush the stream. - */ -inline void HandleStream:: -close_handle() { - _buf.close_handle(); -} - -/** - * Returns the handle that was passed to open_read() or open_write(). - */ -inline FHandle HandleStream:: -get_handle() const { - return _buf.get_handle(); -} - -/** - * Returns true if there is data in the stream's "get" buffer, meaning that at - * least one character can be extracted from the stream without making an OS - * read() call. Returns false if the get buffer is empty, meaning the next - * read call will hit the OS. - */ -inline bool HandleStream:: -has_gdata() const { - return _buf.has_gdata(); -} diff --git a/direct/src/plugin/handleStream.cxx b/direct/src/plugin/handleStream.cxx deleted file mode 100644 index 5d6580f493..0000000000 --- a/direct/src/plugin/handleStream.cxx +++ /dev/null @@ -1,14 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file handleStream.cxx - * @author drose - * @date 2009-06-05 - */ - -#include "handleStream.h" diff --git a/direct/src/plugin/handleStream.h b/direct/src/plugin/handleStream.h deleted file mode 100644 index b28dec5f6a..0000000000 --- a/direct/src/plugin/handleStream.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file handleStream.h - * @author drose - * @date 2009-06-05 - */ - -#ifndef HANDLESTREAM_H -#define HANDLESTREAM_H - -#include "handleStreamBuf.h" - -/** - * Implements a C++ stream object suitable for reading from and writing to - * Windows' HANDLE objects, or Posix file descriptors. This is necessary to - * map low-level pipes into an iostream for tinyxml. - */ -class HandleStream : public std::iostream { -public: - inline HandleStream(); - inline ~HandleStream(); - - inline void open_read(FHandle handle); - inline void open_write(FHandle handle); - inline void close(); - inline void close_handle(); - - inline FHandle get_handle() const; - inline bool has_gdata() const; - -private: - HandleStreamBuf _buf; -}; - -#include "handleStream.I" - -#endif diff --git a/direct/src/plugin/handleStreamBuf.I b/direct/src/plugin/handleStreamBuf.I deleted file mode 100644 index 24036ee9d3..0000000000 --- a/direct/src/plugin/handleStreamBuf.I +++ /dev/null @@ -1,31 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file handleStreamBuf.I - * @author drose - * @date 2009-06-05 - */ - -/** - * Returns the handle that was passed to open_read() or open_write(). - */ -inline FHandle HandleStreamBuf:: -get_handle() const { - return _handle; -} - -/** - * Returns true if there is data in the stream's "get" buffer, meaning that at - * least one character can be extracted from the stream without making an OS - * read() call. Returns false if the get buffer is empty, meaning the next - * read call will hit the OS. - */ -inline bool HandleStreamBuf:: -has_gdata() const { - return (egptr() != gptr()); -} diff --git a/direct/src/plugin/handleStreamBuf.cxx b/direct/src/plugin/handleStreamBuf.cxx deleted file mode 100644 index 55e74977b5..0000000000 --- a/direct/src/plugin/handleStreamBuf.cxx +++ /dev/null @@ -1,342 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file handleStreamBuf.cxx - * @author drose - * @date 2009-06-05 - */ - -#include "handleStreamBuf.h" - -#include -#include - -#ifndef _WIN32 -#include -#include -#include -#include -#include -#endif // _WIN32 - -#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__FreeBSD__) -#include -#endif // !_WIN32 && !__APPLE__ && !__FreeBSD__ - -using std::cerr; -using std::dec; -using std::hex; - -static const size_t handle_buffer_size = 4096; - -/** - * - */ -HandleStreamBuf:: -HandleStreamBuf() { - _is_open_read = false; - _is_open_write = false; - - _handle = invalid_fhandle; - - INIT_LOCK(_lock); - - _buffer = new char[handle_buffer_size]; - char *ebuf = _buffer + handle_buffer_size; - setg(_buffer, ebuf, ebuf); - setp(_buffer, ebuf); -} - -/** - * - */ -HandleStreamBuf:: -~HandleStreamBuf() { - close(); - - delete[] _buffer; - - DESTROY_LOCK(_lock); -} - -/** - * Attempts to open the given handle for input. The stream may not be - * simultaneously open for input and output. - */ -void HandleStreamBuf:: -open_read(FHandle handle) { - close(); - - _handle = handle; - _is_open_read = true; -} - -/** - * Attempts to open the given handle for output. The stream may not be - * simultaneously open for input and output. - */ -void HandleStreamBuf:: -open_write(FHandle handle) { - close(); - - _handle = handle; - _is_open_write = true; -} - -/** - * Returns true if the file is open for input, false otherwise. - */ -bool HandleStreamBuf:: -is_open_read() const { - return _is_open_read; -} - -/** - * Returns true if the file is open for output, false otherwise. - */ -bool HandleStreamBuf:: -is_open_write() const { - return _is_open_write; -} - -/** - * Empties the buffer and closes the file. - */ -void HandleStreamBuf:: -close() { - // Make sure the write buffer is flushed. - sync(); - - close_handle(); - - pbump(pbase() - pptr()); - gbump(egptr() - gptr()); -} - -/** - * Closes the underlying handle, *without* attempting to flush the stream. - */ -void HandleStreamBuf:: -close_handle() { -#ifdef _WIN32 - if (_handle != nullptr) { - CloseHandle(_handle); - } - _handle = nullptr; -#else - if (_handle != -1) { - ::close(_handle); - } - _handle = -1; -#endif // _WIN32 - - _is_open_read = false; - _is_open_write = false; -} - -/** - * Called by the system ostream implementation when its internal buffer is - * filled, plus one character. - */ -int HandleStreamBuf:: -overflow(int ch) { - ACQUIRE_LOCK(_lock); - - bool okflag = true; - - assert(pptr() >= pbase()); - size_t n = pptr() - pbase(); - if (n != 0) { - size_t wrote = write_chars(pbase(), n); - assert(wrote <= n); - pbump(-(int)wrote); - if (wrote != n) { - okflag = false; - } - } - - if (okflag && ch != EOF) { - if (pptr() != epptr()) { - // Store the extra character back in the buffer. - *(pptr()) = ch; - pbump(1); - } else { - // No room to store ch. - okflag = false; - } - } - - RELEASE_LOCK(_lock); - - if (!okflag) { - return EOF; - } - return 0; -} - -/** - * Called by the system iostream implementation to implement a flush - * operation. - */ -int HandleStreamBuf:: -sync() { - ACQUIRE_LOCK(_lock); - assert(pptr() >= pbase()); - size_t n = pptr() - pbase(); - - size_t wrote = write_chars(pbase(), n); - assert(wrote <= n); - pbump(-(int)wrote); - - RELEASE_LOCK(_lock); - - if (n != wrote) { - return EOF; - } - return 0; -} - -/** - * Called by the system istream implementation when its internal buffer needs - * more characters. - */ -int HandleStreamBuf:: -underflow() { - ACQUIRE_LOCK(_lock); - // Sometimes underflow() is called even if the buffer is not empty. - if (gptr() >= egptr()) { - // Mark the buffer filled (with buffer_size bytes). - size_t buffer_size = egptr() - eback(); - gbump(-(int)buffer_size); - - size_t num_bytes = buffer_size; - size_t read_count = read_chars(gptr(), buffer_size); - - if (read_count != num_bytes) { - // Oops, we didn't read what we thought we would. - if (read_count == 0) { - gbump(num_bytes); - RELEASE_LOCK(_lock); - return EOF; - } - - // Slide what we did read to the top of the buffer. - assert(read_count < num_bytes); - size_t delta = num_bytes - read_count; - memmove(gptr() + delta, gptr(), read_count); - gbump(delta); - } - } - - unsigned char next = *gptr(); - RELEASE_LOCK(_lock); - - return next; -} - -/** - * Attempts to extract the indicated number of characters from the current - * file position. Returns the number of characters extracted. - */ -size_t HandleStreamBuf:: -read_chars(char *start, size_t length) { - if (length == 0 || !_is_open_read) { - // Trivial no-op. - return 0; - } - - // Make sure the write buffer is flushed. - sync(); - - if (length == 0) { - return 0; - } - -#ifdef _WIN32 - // Windows case. - DWORD bytes_read = 0; - BOOL success = ReadFile(_handle, start, length, &bytes_read, nullptr); - if (!success) { - DWORD error = GetLastError(); - if (error != ERROR_HANDLE_EOF && error != ERROR_BROKEN_PIPE) { - cerr << "Error reading " << length - << " bytes, windows error code 0x" << hex - << error << dec << ".\n"; - return 0; - } - } - - length = bytes_read; - -#else - // Posix case. - ssize_t result = ::read(_handle, start, length); - if (result < 0) { - cerr << "Error reading " << length << " bytes\n"; - return 0; - } - - length = result; -#endif // _WIN32 - - return length; -} - -/** - * Outputs the indicated stream of characters to the current file position. - */ -size_t HandleStreamBuf:: -write_chars(const char *start, size_t length) { - if (length == 0) { - // Trivial no-op. - return 0; - } - - // Make sure the read buffer is flushed. - size_t n = egptr() - gptr(); - gbump(n); - - if (length == 0 || !_is_open_write) { - return 0; - } - -#ifdef _WIN32 - // Windows case. - DWORD bytes_written = 0; - BOOL success = WriteFile(_handle, start, length, &bytes_written, nullptr); - if (!success) { - assert(bytes_written <= length); - DWORD error = GetLastError(); - if (error != ERROR_NO_DATA && error != ERROR_BROKEN_PIPE) { - cerr << "Error writing " << length - << " bytes, windows error code 0x" << hex - << error << dec << ".\n"; - } - return bytes_written; - } - assert(bytes_written == length); - -#else - // Posix case. - size_t remaining = length; - while (remaining > 0) { - ssize_t result = ::write(_handle, start, remaining); - if (result < 0) { - if (errno != EPIPE) { - cerr << "Error writing " << remaining << " bytes\n"; - } - return length - remaining; - } - - start += result; - remaining -= result; - } -#endif // _WIN32 - - return length; -} diff --git a/direct/src/plugin/handleStreamBuf.h b/direct/src/plugin/handleStreamBuf.h deleted file mode 100644 index da3448d4d3..0000000000 --- a/direct/src/plugin/handleStreamBuf.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file handleStreamBuf.h - * @author drose - * @date 2009-06-05 - */ - -#ifndef HANDLESTREAMBUF_H -#define HANDLESTREAMBUF_H - -#include "fhandle.h" -#include "p3d_lock.h" -#include - -/** - * - */ -class HandleStreamBuf : public std::streambuf { -public: - HandleStreamBuf(); - virtual ~HandleStreamBuf(); - - void open_read(FHandle handle); - void open_write(FHandle handle); - bool is_open_read() const; - bool is_open_write() const; - void close(); - void close_handle(); - - inline FHandle get_handle() const; - inline bool has_gdata() const; - -protected: - virtual int overflow(int c); - virtual int sync(); - virtual int underflow(); - -private: - size_t read_chars(char *start, size_t length); - size_t write_chars(const char *start, size_t length); - -private: - bool _is_open_read; - bool _is_open_write; - - FHandle _handle; - LOCK _lock; - - char *_buffer; -}; - -#include "handleStreamBuf.I" - -#endif diff --git a/direct/src/plugin/is_pathsep.I b/direct/src/plugin/is_pathsep.I deleted file mode 100644 index 3dd35068b8..0000000000 --- a/direct/src/plugin/is_pathsep.I +++ /dev/null @@ -1,29 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file is_pathsep.I - * @author drose - * @date 2009-07-07 - */ - -/** - * Returns true if the indicated character is a path separator character (e.g. - * slash or backslash), false otherwise. - */ -inline bool -is_pathsep(int ch) { - if (ch == '/') { - return true; - } -#ifdef _WIN32 - if (ch == '\\') { - return true; - } -#endif - return false; -} diff --git a/direct/src/plugin/is_pathsep.h b/direct/src/plugin/is_pathsep.h deleted file mode 100644 index d1e326ee2d..0000000000 --- a/direct/src/plugin/is_pathsep.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file is_pathsep.h - * @author drose - * @date 2009-07-07 - */ - -#ifndef IS_PATHSEP_H -#define IS_PATHSEP_H - -inline bool -is_pathsep(int ch); - -#include "is_pathsep.I" - -#endif diff --git a/direct/src/plugin/load_plugin.cxx b/direct/src/plugin/load_plugin.cxx deleted file mode 100644 index a1575ff087..0000000000 --- a/direct/src/plugin/load_plugin.cxx +++ /dev/null @@ -1,476 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file load_plugin.cxx - * @author drose - * @date 2009-06-19 - */ - -#include "load_plugin.h" -#include "p3d_plugin_config.h" -#include "is_pathsep.h" -#include "wstring_encode.h" - -#include - -#include - -#ifndef _WIN32 -#include -#endif - -using std::string; - -#ifdef _WIN32 -static const string dll_ext = ".dll"; -#elif defined(__APPLE__) -static const string dll_ext = ".dylib"; -#else -static const string dll_ext = ".so"; -#endif - -static const string default_plugin_filename = "p3d_plugin"; - -P3D_initialize_func *P3D_initialize_ptr; -P3D_finalize_func *P3D_finalize_ptr; -P3D_set_plugin_version_func *P3D_set_plugin_version_ptr; -P3D_set_super_mirror_func *P3D_set_super_mirror_ptr; -P3D_new_instance_func *P3D_new_instance_ptr; -P3D_instance_start_func *P3D_instance_start_ptr; -P3D_instance_start_stream_func *P3D_instance_start_stream_ptr; -P3D_instance_finish_func *P3D_instance_finish_ptr; -P3D_instance_setup_window_func *P3D_instance_setup_window_ptr; - -P3D_object_get_type_func *P3D_object_get_type_ptr; -P3D_object_get_bool_func *P3D_object_get_bool_ptr; -P3D_object_get_int_func *P3D_object_get_int_ptr; -P3D_object_get_float_func *P3D_object_get_float_ptr; -P3D_object_get_string_func *P3D_object_get_string_ptr; -P3D_object_get_repr_func *P3D_object_get_repr_ptr; -P3D_object_get_property_func *P3D_object_get_property_ptr; -P3D_object_set_property_func *P3D_object_set_property_ptr; -P3D_object_has_method_func *P3D_object_has_method_ptr; -P3D_object_call_func *P3D_object_call_ptr; -P3D_object_eval_func *P3D_object_eval_ptr; -P3D_object_incref_func *P3D_object_incref_ptr; -P3D_object_decref_func *P3D_object_decref_ptr; - -P3D_make_class_definition_func *P3D_make_class_definition_ptr; -P3D_new_undefined_object_func *P3D_new_undefined_object_ptr; -P3D_new_none_object_func *P3D_new_none_object_ptr; -P3D_new_bool_object_func *P3D_new_bool_object_ptr; -P3D_new_int_object_func *P3D_new_int_object_ptr; -P3D_new_float_object_func *P3D_new_float_object_ptr; -P3D_new_string_object_func *P3D_new_string_object_ptr; -P3D_instance_get_panda_script_object_func *P3D_instance_get_panda_script_object_ptr; -P3D_instance_set_browser_script_object_func *P3D_instance_set_browser_script_object_ptr; - -P3D_instance_get_request_func *P3D_instance_get_request_ptr; -P3D_check_request_func *P3D_check_request_ptr; -P3D_request_finish_func *P3D_request_finish_ptr; -P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream_ptr; -P3D_instance_handle_event_func *P3D_instance_handle_event_ptr; - -#ifdef _WIN32 -static HMODULE module = nullptr; -#else -static void *module = nullptr; -#endif - -static bool plugin_loaded = false; -static bool dso_needs_unload = false; - - -/** - * Returns the default plugin filename, without any directory path (but - * including the extension appropriate to this platform). - */ -string -get_plugin_basename() { - return default_plugin_filename + dll_ext; -} - -/** - * Returns the position in the string of the dot before the filename - * extension; that is, the position of the rightmost dot that is right of the - * rightmost slash (or backslash, on Windows). Returns string::npos if there - * is no extension. - */ -static size_t -find_extension_dot(const string &filename) { - size_t p = filename.length(); - while (p > 0 && !is_pathsep(filename[p - 1])) { - --p; - if (filename[p] == '.') { - return p; - } - } - - return string::npos; -} - -// Forward reference for function defined below. -static void unload_dso(); - -/** - * Loads the plugin and assigns all of the function pointers. Returns true on - * success, false on failure. If load_plugin() has already been called - * successfully, this returns true immediately, without parsing any - * parameters. - * - * If p3d_plugin_filename is empty, the module is assumed to be already loaded - * (or statically linked in), and the symbols are located within the current - * address space. - */ -bool -load_plugin(const string &p3d_plugin_filename, - const string &contents_filename, const string &host_url, - P3D_verify_contents verify_contents, const string &platform, - const string &log_directory, const string &log_basename, - bool trusted_environment, bool console_environment, - const string &root_dir, const string &host_dir, - const string &start_dir, std::ostream &logfile) { - if (plugin_loaded) { - return true; - } - string filename = p3d_plugin_filename; - -#ifdef _WIN32 - assert(module == nullptr); - - if (filename.empty()) { - // If no filename is supplied, look within our existing address space. - module = GetModuleHandle(nullptr); - dso_needs_unload = false; - - } else { - // If a filename is supplied, attempt to load it as a dynamic library. - - // On Windows, the filename passed to LoadLibrary() must have an - // extension, or a default ".DLL" will be implicitly added. If the file - // actually has no extension, we must add "." to avoid this. - - // Check whether the filename has an extension. - size_t extension_dot = find_extension_dot(filename); - if (extension_dot == string::npos) { - // No extension. - filename += "."; - } - - SetErrorMode(0); - std::wstring filename_w; - if (string_to_wstring(filename_w, filename)) { - module = LoadLibraryW(filename_w.c_str()); - } - dso_needs_unload = true; - } - - if (module == nullptr) { - // Couldn't load the DLL. - logfile - << "Couldn't load " << filename << ", error = " - << GetLastError() << "\n"; - return false; - } - - #define get_func GetProcAddress - -#else // _WIN32 - // Posix case. - assert(module == nullptr); - if (filename.empty()) { - module = dlopen(nullptr, RTLD_LAZY | RTLD_LOCAL); - } else { - module = dlopen(filename.c_str(), RTLD_LAZY | RTLD_LOCAL); - } - if (module == nullptr) { - // Couldn't load the .so. - const char *message = dlerror(); - if (message == nullptr) { - message = "No error"; - } - logfile << "Couldn't load " << filename << ": " << message << "\n"; - - return false; - } - dso_needs_unload = true; - - #define get_func dlsym - -#endif // _WIN32 - - // Now get all of the function pointers. - P3D_initialize_ptr = (P3D_initialize_func *)get_func(module, "P3D_initialize"); - P3D_finalize_ptr = (P3D_finalize_func *)get_func(module, "P3D_finalize"); - P3D_set_plugin_version_ptr = (P3D_set_plugin_version_func *)get_func(module, "P3D_set_plugin_version"); - P3D_set_super_mirror_ptr = (P3D_set_super_mirror_func *)get_func(module, "P3D_set_super_mirror"); - P3D_new_instance_ptr = (P3D_new_instance_func *)get_func(module, "P3D_new_instance"); - P3D_instance_start_ptr = (P3D_instance_start_func *)get_func(module, "P3D_instance_start"); - P3D_instance_start_stream_ptr = (P3D_instance_start_stream_func *)get_func(module, "P3D_instance_start_stream"); - P3D_instance_finish_ptr = (P3D_instance_finish_func *)get_func(module, "P3D_instance_finish"); - P3D_instance_setup_window_ptr = (P3D_instance_setup_window_func *)get_func(module, "P3D_instance_setup_window"); - - P3D_object_get_type_ptr = (P3D_object_get_type_func *)get_func(module, "P3D_object_get_type"); - P3D_object_get_bool_ptr = (P3D_object_get_bool_func *)get_func(module, "P3D_object_get_bool"); - P3D_object_get_int_ptr = (P3D_object_get_int_func *)get_func(module, "P3D_object_get_int"); - P3D_object_get_float_ptr = (P3D_object_get_float_func *)get_func(module, "P3D_object_get_float"); - P3D_object_get_string_ptr = (P3D_object_get_string_func *)get_func(module, "P3D_object_get_string"); - P3D_object_get_repr_ptr = (P3D_object_get_repr_func *)get_func(module, "P3D_object_get_repr"); - P3D_object_get_property_ptr = (P3D_object_get_property_func *)get_func(module, "P3D_object_get_property"); - P3D_object_set_property_ptr = (P3D_object_set_property_func *)get_func(module, "P3D_object_set_property"); - P3D_object_has_method_ptr = (P3D_object_has_method_func *)get_func(module, "P3D_object_has_method"); - P3D_object_call_ptr = (P3D_object_call_func *)get_func(module, "P3D_object_call"); - P3D_object_eval_ptr = (P3D_object_eval_func *)get_func(module, "P3D_object_eval"); - P3D_object_incref_ptr = (P3D_object_incref_func *)get_func(module, "P3D_object_incref"); - P3D_object_decref_ptr = (P3D_object_decref_func *)get_func(module, "P3D_object_decref"); - P3D_make_class_definition_ptr = (P3D_make_class_definition_func *)get_func(module, "P3D_make_class_definition"); - P3D_new_undefined_object_ptr = (P3D_new_undefined_object_func *)get_func(module, "P3D_new_undefined_object"); - P3D_new_none_object_ptr = (P3D_new_none_object_func *)get_func(module, "P3D_new_none_object"); - P3D_new_bool_object_ptr = (P3D_new_bool_object_func *)get_func(module, "P3D_new_bool_object"); - P3D_new_int_object_ptr = (P3D_new_int_object_func *)get_func(module, "P3D_new_int_object"); - P3D_new_float_object_ptr = (P3D_new_float_object_func *)get_func(module, "P3D_new_float_object"); - P3D_new_string_object_ptr = (P3D_new_string_object_func *)get_func(module, "P3D_new_string_object"); - P3D_instance_get_panda_script_object_ptr = (P3D_instance_get_panda_script_object_func *)get_func(module, "P3D_instance_get_panda_script_object"); - P3D_instance_set_browser_script_object_ptr = (P3D_instance_set_browser_script_object_func *)get_func(module, "P3D_instance_set_browser_script_object"); - - P3D_instance_get_request_ptr = (P3D_instance_get_request_func *)get_func(module, "P3D_instance_get_request"); - P3D_check_request_ptr = (P3D_check_request_func *)get_func(module, "P3D_check_request"); - P3D_request_finish_ptr = (P3D_request_finish_func *)get_func(module, "P3D_request_finish"); - P3D_instance_feed_url_stream_ptr = (P3D_instance_feed_url_stream_func *)get_func(module, "P3D_instance_feed_url_stream"); - P3D_instance_handle_event_ptr = (P3D_instance_handle_event_func *)get_func(module, "P3D_instance_handle_event"); - - #undef get_func - - // Successfully loaded. - plugin_loaded = true; - - if (!init_plugin(contents_filename, host_url, - verify_contents, platform, - log_directory, log_basename, - trusted_environment, console_environment, - root_dir, host_dir, start_dir, logfile)) { - unload_dso(); - return false; - } - - return true; -} - -/** - * Ensures all the required function pointers have been set, and then calls - * P3D_initialize() on the recently-loaded plugin. Returns true on success, - * false on failure. - * - * It is not necessary to call this after calling load_plugin(); it is called - * implicitly. - */ -bool -init_plugin(const string &contents_filename, const string &host_url, - P3D_verify_contents verify_contents, const string &platform, - const string &log_directory, const string &log_basename, - bool trusted_environment, bool console_environment, - const string &root_dir, const string &host_dir, - const string &start_dir, std::ostream &logfile) { - - // Ensure that all of the function pointers have been found. - if (P3D_initialize_ptr == nullptr || - P3D_finalize_ptr == nullptr || - P3D_set_plugin_version_ptr == nullptr || - P3D_set_super_mirror_ptr == nullptr || - P3D_new_instance_ptr == nullptr || - P3D_instance_start_ptr == nullptr || - P3D_instance_start_stream_ptr == nullptr || - P3D_instance_finish_ptr == nullptr || - P3D_instance_setup_window_ptr == nullptr || - - P3D_object_get_type_ptr == nullptr || - P3D_object_get_bool_ptr == nullptr || - P3D_object_get_int_ptr == nullptr || - P3D_object_get_float_ptr == nullptr || - P3D_object_get_string_ptr == nullptr || - P3D_object_get_repr_ptr == nullptr || - P3D_object_get_property_ptr == nullptr || - P3D_object_set_property_ptr == nullptr || - P3D_object_has_method_ptr == nullptr || - P3D_object_call_ptr == nullptr || - P3D_object_eval_ptr == nullptr || - P3D_object_incref_ptr == nullptr || - P3D_object_decref_ptr == nullptr || - - P3D_make_class_definition_ptr == nullptr || - P3D_new_undefined_object_ptr == nullptr || - P3D_new_none_object_ptr == nullptr || - P3D_new_bool_object_ptr == nullptr || - P3D_new_int_object_ptr == nullptr || - P3D_new_float_object_ptr == nullptr || - P3D_new_string_object_ptr == nullptr || - P3D_instance_get_panda_script_object_ptr == nullptr || - P3D_instance_set_browser_script_object_ptr == nullptr || - - P3D_instance_get_request_ptr == nullptr || - P3D_check_request_ptr == nullptr || - P3D_request_finish_ptr == nullptr || - P3D_instance_feed_url_stream_ptr == nullptr || - P3D_instance_handle_event_ptr == nullptr) { - - logfile - << "Some function pointers not found:" - << "\nP3D_initialize_ptr = " << P3D_initialize_ptr - << "\nP3D_finalize_ptr = " << P3D_finalize_ptr - << "\nP3D_set_plugin_version_ptr = " << P3D_set_plugin_version_ptr - << "\nP3D_set_super_mirror_ptr = " << P3D_set_super_mirror_ptr - << "\nP3D_new_instance_ptr = " << P3D_new_instance_ptr - << "\nP3D_instance_start_ptr = " << P3D_instance_start_ptr - << "\nP3D_instance_start_stream_ptr = " << P3D_instance_start_stream_ptr - << "\nP3D_instance_finish_ptr = " << P3D_instance_finish_ptr - << "\nP3D_instance_setup_window_ptr = " << P3D_instance_setup_window_ptr - - << "\nP3D_object_get_type_ptr = " << P3D_object_get_type_ptr - << "\nP3D_object_get_bool_ptr = " << P3D_object_get_bool_ptr - << "\nP3D_object_get_int_ptr = " << P3D_object_get_int_ptr - << "\nP3D_object_get_float_ptr = " << P3D_object_get_float_ptr - << "\nP3D_object_get_string_ptr = " << P3D_object_get_string_ptr - << "\nP3D_object_get_repr_ptr = " << P3D_object_get_repr_ptr - << "\nP3D_object_get_property_ptr = " << P3D_object_get_property_ptr - << "\nP3D_object_set_property_ptr = " << P3D_object_set_property_ptr - << "\nP3D_object_has_method_ptr = " << P3D_object_has_method_ptr - << "\nP3D_object_call_ptr = " << P3D_object_call_ptr - << "\nP3D_object_eval_ptr = " << P3D_object_eval_ptr - << "\nP3D_object_incref_ptr = " << P3D_object_incref_ptr - << "\nP3D_object_decref_ptr = " << P3D_object_decref_ptr - - << "\nP3D_make_class_definition_ptr = " << P3D_make_class_definition_ptr - << "\nP3D_new_undefined_object_ptr = " << P3D_new_undefined_object_ptr - << "\nP3D_new_none_object_ptr = " << P3D_new_none_object_ptr - << "\nP3D_new_bool_object_ptr = " << P3D_new_bool_object_ptr - << "\nP3D_new_int_object_ptr = " << P3D_new_int_object_ptr - << "\nP3D_new_float_object_ptr = " << P3D_new_float_object_ptr - << "\nP3D_new_string_object_ptr = " << P3D_new_string_object_ptr - << "\nP3D_instance_get_panda_script_object_ptr = " << P3D_instance_get_panda_script_object_ptr - << "\nP3D_instance_set_browser_script_object_ptr = " << P3D_instance_set_browser_script_object_ptr - - << "\nP3D_instance_get_request_ptr = " << P3D_instance_get_request_ptr - << "\nP3D_check_request_ptr = " << P3D_check_request_ptr - << "\nP3D_request_finish_ptr = " << P3D_request_finish_ptr - << "\nP3D_instance_feed_url_stream_ptr = " << P3D_instance_feed_url_stream_ptr - << "\nP3D_instance_handle_event_ptr = " << P3D_instance_handle_event_ptr - << "\n"; - return false; - } - - // A bit of extra hand-hacked compatibility for using newer plug-ins with an - // older version of the core API. - int api_version = P3D_API_VERSION; - if (api_version == 17 && start_dir.empty()) { - api_version = 16; - if (host_dir.empty()) { - api_version = 15; - } - } - - if (!P3D_initialize_ptr(api_version, contents_filename.c_str(), - host_url.c_str(), verify_contents, platform.c_str(), - log_directory.c_str(), log_basename.c_str(), - trusted_environment, console_environment, - root_dir.c_str(), host_dir.c_str(), - start_dir.c_str())) { - // Oops, failure to initialize. - logfile - << "Failed to initialize plugin (passed API version " - << api_version << ")\n"; - return false; - } - - return true; -} - -/** - * Calls finalize, then removes the plugin from memory space and clears all of - * the pointers. - */ -void -unload_plugin(std::ostream &logfile) { - if (!plugin_loaded) { - return; - } - - P3D_finalize_ptr(); - unload_dso(); -} - -/** - * Removes the plugin from memory space and clears all of the pointers. This - * is only intended to be called by load_plugin(), above, in the specific case - * that the plugin loaded but could not successfully initialize itself. All - * user code should call unload_plugin(), above, which first calls - * P3D_finalize(). - */ -static void -unload_dso() { - if (dso_needs_unload) { - assert(module != nullptr); -#ifdef _WIN32 - FreeLibrary(module); -#else - dlclose(module); -#endif - module = nullptr; - dso_needs_unload = false; - } - - P3D_initialize_ptr = nullptr; - P3D_finalize_ptr = nullptr; - P3D_set_plugin_version_ptr = nullptr; - P3D_set_super_mirror_ptr = nullptr; - P3D_new_instance_ptr = nullptr; - P3D_instance_start_ptr = nullptr; - P3D_instance_start_stream_ptr = nullptr; - P3D_instance_finish_ptr = nullptr; - P3D_instance_setup_window_ptr = nullptr; - - P3D_object_get_type_ptr = nullptr; - P3D_object_get_bool_ptr = nullptr; - P3D_object_get_int_ptr = nullptr; - P3D_object_get_float_ptr = nullptr; - P3D_object_get_string_ptr = nullptr; - P3D_object_get_repr_ptr = nullptr; - P3D_object_get_property_ptr = nullptr; - P3D_object_set_property_ptr = nullptr; - P3D_object_has_method_ptr = nullptr; - P3D_object_call_ptr = nullptr; - P3D_object_eval_ptr = nullptr; - P3D_object_incref_ptr = nullptr; - P3D_object_decref_ptr = nullptr; - - P3D_make_class_definition_ptr = nullptr; - P3D_new_undefined_object_ptr = nullptr; - P3D_new_none_object_ptr = nullptr; - P3D_new_bool_object_ptr = nullptr; - P3D_new_int_object_ptr = nullptr; - P3D_new_float_object_ptr = nullptr; - P3D_new_string_object_ptr = nullptr; - P3D_instance_get_panda_script_object_ptr = nullptr; - P3D_instance_set_browser_script_object_ptr = nullptr; - - P3D_instance_get_request_ptr = nullptr; - P3D_check_request_ptr = nullptr; - P3D_request_finish_ptr = nullptr; - P3D_instance_feed_url_stream_ptr = nullptr; - P3D_instance_handle_event_ptr = nullptr; - - plugin_loaded = false; -} - -/** - * Returns true if the plugin has been loaded successfully by a previous call - * to load_plugin(), false otherwise. - */ -bool -is_plugin_loaded() { - return plugin_loaded; -} diff --git a/direct/src/plugin/load_plugin.h b/direct/src/plugin/load_plugin.h deleted file mode 100644 index 2e462ed9cd..0000000000 --- a/direct/src/plugin/load_plugin.h +++ /dev/null @@ -1,81 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file load_plugin.h - * @author drose - * @date 2009-06-19 - */ - -#ifndef LOAD_PLUGIN_H -#define LOAD_PLUGIN_H - -#include "p3d_plugin.h" - -#include - -extern P3D_initialize_func *P3D_initialize_ptr; -extern P3D_finalize_func *P3D_finalize_ptr; -extern P3D_set_plugin_version_func *P3D_set_plugin_version_ptr; -extern P3D_set_super_mirror_func *P3D_set_super_mirror_ptr; -extern P3D_new_instance_func *P3D_new_instance_ptr; -extern P3D_instance_start_func *P3D_instance_start_ptr; -extern P3D_instance_start_stream_func *P3D_instance_start_stream_ptr; -extern P3D_instance_finish_func *P3D_instance_finish_ptr; -extern P3D_instance_setup_window_func *P3D_instance_setup_window_ptr; - -extern P3D_object_get_type_func *P3D_object_get_type_ptr; -extern P3D_object_get_bool_func *P3D_object_get_bool_ptr; -extern P3D_object_get_int_func *P3D_object_get_int_ptr; -extern P3D_object_get_float_func *P3D_object_get_float_ptr; -extern P3D_object_get_string_func *P3D_object_get_string_ptr; -extern P3D_object_get_repr_func *P3D_object_get_repr_ptr; -extern P3D_object_get_property_func *P3D_object_get_property_ptr; -extern P3D_object_set_property_func *P3D_object_set_property_ptr; -extern P3D_object_has_method_func *P3D_object_has_method_ptr; -extern P3D_object_call_func *P3D_object_call_ptr; -extern P3D_object_eval_func *P3D_object_eval_ptr; -extern P3D_object_incref_func *P3D_object_incref_ptr; -extern P3D_object_decref_func *P3D_object_decref_ptr; - -extern P3D_make_class_definition_func *P3D_make_class_definition_ptr; -extern P3D_new_undefined_object_func *P3D_new_undefined_object_ptr; -extern P3D_new_none_object_func *P3D_new_none_object_ptr; -extern P3D_new_bool_object_func *P3D_new_bool_object_ptr; -extern P3D_new_int_object_func *P3D_new_int_object_ptr; -extern P3D_new_float_object_func *P3D_new_float_object_ptr; -extern P3D_new_string_object_func *P3D_new_string_object_ptr; -extern P3D_instance_get_panda_script_object_func *P3D_instance_get_panda_script_object_ptr; -extern P3D_instance_set_browser_script_object_func *P3D_instance_set_browser_script_object_ptr; - -extern P3D_instance_get_request_func *P3D_instance_get_request_ptr; -extern P3D_check_request_func *P3D_check_request_ptr; -extern P3D_request_finish_func *P3D_request_finish_ptr; -extern P3D_instance_feed_url_stream_func *P3D_instance_feed_url_stream_ptr; -extern P3D_instance_handle_event_func *P3D_instance_handle_event_ptr; - -std::string get_plugin_basename(); -bool -load_plugin(const std::string &p3d_plugin_filename, - const std::string &contents_filename, const std::string &host_url, - P3D_verify_contents verify_contents, const std::string &platform, - const std::string &log_directory, const std::string &log_basename, - bool trusted_environment, bool console_environment, - const std::string &root_dir, const std::string &host_dir, - const std::string &start_dir, std::ostream &logfile); -bool -init_plugin(const std::string &contents_filename, const std::string &host_url, - P3D_verify_contents verify_contents, const std::string &platform, - const std::string &log_directory, const std::string &log_basename, - bool trusted_environment, bool console_environment, - const std::string &root_dir, const std::string &host_dir, - const std::string &start_dir, std::ostream &logfile); - -void unload_plugin(std::ostream &logfile); -bool is_plugin_loaded(); - -#endif diff --git a/direct/src/plugin/mkdir_complete.cxx b/direct/src/plugin/mkdir_complete.cxx deleted file mode 100644 index 6689584198..0000000000 --- a/direct/src/plugin/mkdir_complete.cxx +++ /dev/null @@ -1,224 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mkdir_complete.cxx - * @author drose - * @date 2009-06-29 - */ - -#include "mkdir_complete.h" -#include "is_pathsep.h" -#include "wstring_encode.h" - -#ifdef _WIN32 -#include -#include // chmod() -#else -#include -#include // for mkdir() -#include -#include // strerror() -#include -#endif - -using std::ostream; -using std::string; -using std::wstring; - -/** - * Returns the directory component of the indicated pathname, or the empty - * string if there is no directory prefix. - */ -static string -get_dirname(const string &filename) { - size_t p = filename.length(); - while (p > 0) { - --p; - if (is_pathsep(filename[p])) { - return filename.substr(0, p); - } - } - - return string(); -} - -#ifdef _WIN32 -/** - * The wide-character implementation of get_dirname(). Only implemented (and - * needed) on Windows. - */ -static wstring -get_dirname_w(const wstring &filename) { - size_t p = filename.length(); - while (p > 0) { - --p; - if (is_pathsep(filename[p])) { - return filename.substr(0, p); - } - } - - return wstring(); -} -#endif // _WIN32 - - - -/** - * Creates a new directory, with normal access privileges. Returns true on - * success, false on failure. Will create intervening directories if - * necessary. - */ -bool -mkdir_complete(const string &dirname, ostream &logfile) { -#ifdef _WIN32 - wstring dirname_w; - if (!string_to_wstring(dirname_w, dirname)) { - return false; - } - return mkdir_complete_w(dirname_w, logfile); - -#else //_WIN32 - if (mkdir(dirname.c_str(), 0755) == 0) { - // Success! - return true; - } - - // Failed. - if (errno == EEXIST) { - // Not really an error: the directory is already there. - return true; - } - - if (errno == ENOENT || errno == EACCES) { - // We need to make the parent directory first. - string parent = get_dirname(dirname); - if (!parent.empty() && mkdir_complete(parent, logfile)) { - // Parent successfully created. Try again to make the child. - if (mkdir(dirname.c_str(), 0755) == 0) { - // Got it! - return true; - } - // Couldn't create the directory. :( - logfile - << "Couldn't create " << dirname << ": " << strerror(errno) << "\n"; - } - } - return false; - -#endif // _WIN32 -} - -/** - * Creates a new file with normal access priviledges. Returns true on - * success, false on failure. This will create intervening directories if - * needed. - */ -bool -mkfile_complete(const string &filename, ostream &logfile) { -#ifdef _WIN32 - wstring filename_w; - if (!string_to_wstring(filename_w, filename)) { - return false; - } - return mkfile_complete_w(filename_w, logfile); -#else // _WIN32 - // Make sure we delete any previously-existing file first. - unlink(filename.c_str()); - - int fd = creat(filename.c_str(), 0755); - if (fd == -1) { - // Try to make the parent directory first. - string parent = get_dirname(filename); - if (!parent.empty() && mkdir_complete(parent, logfile)) { - // Parent successfully created. Try again to make the file. - fd = creat(filename.c_str(), 0755); - } - if (fd == -1) { - logfile - << "Couldn't create " << filename << ": " << strerror(errno) << "\n"; - return false; - } - } - close(fd); - return true; - -#endif // _WIN32 -} - - -#ifdef _WIN32 -/** - * The wide-character implementation of mkdir_complete(). Only implemented - * (and needed) on Windows. - */ -bool -mkdir_complete_w(const wstring &dirname, ostream &logfile) { - if (CreateDirectoryW(dirname.c_str(), nullptr) != 0) { - // Success! - return true; - } - - // Failed. - DWORD last_error = GetLastError(); - if (last_error == ERROR_ALREADY_EXISTS) { - // Not really an error: the directory is already there. - return true; - } - - if (last_error == ERROR_PATH_NOT_FOUND) { - // We need to make the parent directory first. - wstring parent = get_dirname_w(dirname); - if (!parent.empty() && mkdir_complete_w(parent, logfile)) { - // Parent successfully created. Try again to make the child. - if (CreateDirectoryW(dirname.c_str(), nullptr) != 0) { - // Got it! - return true; - } - logfile - << "Couldn't create " << dirname << "\n"; - } - } - return false; -} -#endif // _WIN32 - -#ifdef _WIN32 -/** - * The wide-character implementation of mkfile_complete(). Only implemented - * (and needed) on Windows. - */ -bool -mkfile_complete_w(const wstring &filename, ostream &logfile) { - // Make sure we delete any previously-existing file first. - - // Windows can't delete a file if it's read-only. Weird. - _wchmod(filename.c_str(), 0644); - _wunlink(filename.c_str()); - - HANDLE file = CreateFileW(filename.c_str(), GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - if (file == INVALID_HANDLE_VALUE) { - // Try to make the parent directory first. - wstring parent = get_dirname_w(filename); - if (!parent.empty() && mkdir_complete_w(parent, logfile)) { - // Parent successfully created. Try again to make the file. - file = CreateFileW(filename.c_str(), GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - } - if (file == INVALID_HANDLE_VALUE) { - logfile - << "Couldn't create " << filename << "\n"; - return false; - } - } - CloseHandle(file); - return true; -} -#endif // _WIN32 diff --git a/direct/src/plugin/mkdir_complete.h b/direct/src/plugin/mkdir_complete.h deleted file mode 100644 index be79cf7e8e..0000000000 --- a/direct/src/plugin/mkdir_complete.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mkdir_complete.h - * @author drose - * @date 2009-06-29 - */ - -#ifndef MKDIR_COMPLETE_H -#define MKDIR_COMPLETE_H - -#include -#include - -bool mkdir_complete(const std::string &dirname, std::ostream &logfile); -bool mkfile_complete(const std::string &dirname, std::ostream &logfile); - -#ifdef _WIN32 -bool mkdir_complete_w(const std::wstring &dirname, std::ostream &logfile); -bool mkfile_complete_w(const std::wstring &dirname, std::ostream &logfile); -#endif // _WIN32 - -#endif diff --git a/direct/src/plugin/p3dAuthSession.I b/direct/src/plugin/p3dAuthSession.I deleted file mode 100644 index 0e451a8f87..0000000000 --- a/direct/src/plugin/p3dAuthSession.I +++ /dev/null @@ -1,12 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dAuthSession.I - * @author drose - * @date 2009-09-17 - */ diff --git a/direct/src/plugin/p3dAuthSession.cxx b/direct/src/plugin/p3dAuthSession.cxx deleted file mode 100644 index e76bbe0a07..0000000000 --- a/direct/src/plugin/p3dAuthSession.cxx +++ /dev/null @@ -1,456 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dAuthSession.cxx - * @author drose - * @date 2009-09-17 - */ - -#include "p3dAuthSession.h" -#include "p3dInstance.h" -#include "p3dInstanceManager.h" -#include "p3dMultifileReader.h" -#include "p3d_plugin_config.h" -#include "mkdir_complete.h" -#include "wstring_encode.h" - -#include - -#ifndef _WIN32 -#include -#include -#include -#include -#include -#include -#endif - -using std::string; - -/** - * - */ -P3DAuthSession:: -P3DAuthSession(P3DInstance *inst) : - _inst(inst) -{ - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - -#ifdef _WIN32 - _p3dcert_handle = INVALID_HANDLE_VALUE; -#else - _p3dcert_pid = -1; -#endif - _p3dcert_started = false; - _p3dcert_running = false; - _started_wait_thread = false; - INIT_THREAD(_wait_thread); - - // Write the cert chain to a temporary file. - _cert_filename = new P3DTemporaryFile(".crt"); - string filename = _cert_filename->get_filename(); - FILE *fp = fopen(filename.c_str(), "w"); - if (fp == nullptr) { - nout << "Couldn't write temporary file\n"; - return; - } - - if (inst->_mf_reader.get_num_signatures() > 0) { - const P3DMultifileReader::CertChain &cert_chain = - inst->_mf_reader.get_signature(0); - - if (cert_chain.size() > 0) { - // Save the cert_dir, this is where the p3dcert program will need to - // write the cert when it is approved. - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - _cert_dir = inst_mgr->get_cert_dir(cert_chain[0]._cert); - } - - P3DMultifileReader::CertChain::const_iterator ci; - for (ci = cert_chain.begin(); ci != cert_chain.end(); ++ci) { - X509 *c = (*ci)._cert; - PEM_write_X509(fp, c); - } - } - fclose(fp); - - start_p3dcert(); -} - - -/** - * - */ -P3DAuthSession:: -~P3DAuthSession() { - shutdown(false); - - if (_cert_filename != nullptr) { - delete _cert_filename; - } -} - -/** - * Terminates the session by killing the subprocess. - */ -void P3DAuthSession:: -shutdown(bool send_message) { - if (!send_message) { - // If we're not to send the instance the shutdown message as a result of - // this, then clear the _inst pointer now. - _inst = nullptr; - } - - if (_p3dcert_running) { - nout << "Killing p3dcert process\n"; -#ifdef _WIN32 - TerminateProcess(_p3dcert_handle, 2); - CloseHandle(_p3dcert_handle); - -#else // _WIN32 - kill(_p3dcert_pid, SIGKILL); - - // Wait a few milliseconds for the process to exit, and then get its - // return status to clean up the zombie status. If we don't wait long - // enough, don't sweat it. - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 100000; - select(0, nullptr, nullptr, nullptr, &tv); - int status; - waitpid(_p3dcert_pid, &status, WNOHANG); -#endif // _WIN32 - - _p3dcert_running = false; - } - _p3dcert_started = false; - - // Now that the process has stopped, the thread should stop itself quickly - // too. - join_wait_thread(); - - // We're no longer bound to any particular instance. - _inst = nullptr; -} - -/** - * Starts the p3dcert program running in a child process. - */ -void P3DAuthSession:: -start_p3dcert() { - if (_p3dcert_started) { - // Already started. - return; - } - - if (_inst->_p3dcert_package == nullptr) { - nout << "Couldn't start Python: no p3dcert package.\n"; - return; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - _start_dir = inst_mgr->get_start_dir(); - - string root_dir = _inst->_p3dcert_package->get_package_dir(); - mkdir_complete(_start_dir, nout); - - _p3dcert_exe = root_dir + "/p3dcert"; -#ifdef _WIN32 - _p3dcert_exe += ".exe"; -#endif -#ifdef __APPLE__ - // On OSX, run from the packaged bundle. - _p3dcert_exe = root_dir + "/P3DCert.app/Contents/MacOS/p3dcert"; -#endif - - // Populate the new process' environment. - -#ifdef _WIN32 - // These are the enviroment variables we forward from the current - // environment, if they are set. - const wchar_t *keep[] = { - L"TMP", L"TEMP", L"HOME", L"USER", - L"SYSTEMROOT", L"USERPROFILE", L"COMSPEC", - nullptr - }; - - std::wstring env_w; - - for (int ki = 0; keep[ki] != nullptr; ++ki) { - wchar_t *value = _wgetenv(keep[ki]); - if (value != nullptr) { - env_w += keep[ki]; - env_w += L"="; - env_w += value; - env_w += (wchar_t)'\0'; - } - } - - wstring_to_string(_env, env_w); - -#else // _WIN32 - - _env = string(); - - // These are the enviroment variables we forward from the current - // environment, if they are set. - const char *keep[] = { - "TMP", "TEMP", "HOME", "USER", - "LANGUAGE", "LC_ALL", "LC_MESSAGES", "LANG", -#ifdef HAVE_X11 - "DISPLAY", "XAUTHORITY", -#endif - nullptr - }; - for (int ki = 0; keep[ki] != nullptr; ++ki) { - char *value = getenv(keep[ki]); - if (value != nullptr) { - _env += keep[ki]; - _env += "="; - _env += value; - _env += '\0'; - } - } -#endif // _WIN32 - - // Define some new environment variables. - _env += "PATH="; - _env += root_dir; - _env += '\0'; - - _env += "LD_LIBRARY_PATH="; - _env += root_dir; - _env += '\0'; - - _env += "DYLD_LIBRARY_PATH="; - _env += root_dir; - _env += '\0'; - - _env += "P3DCERT_ROOT="; - _env += root_dir; - _env += '\0'; - - nout << "Setting environment:\n"; - write_env(); - - nout << "Attempting to start p3dcert from " << _p3dcert_exe << "\n"; - - bool started_p3dcert = false; -#ifdef _WIN32 - _p3dcert_handle = win_create_process(); - started_p3dcert = (_p3dcert_handle != INVALID_HANDLE_VALUE); -#else - _p3dcert_pid = posix_create_process(); - started_p3dcert = (_p3dcert_pid > 0); -#endif - if (!started_p3dcert) { - nout << "Failed to create process.\n"; - return; - } - - _p3dcert_started = true; - _p3dcert_running = true; - - spawn_wait_thread(); -} - -/** - * Starts the wait thread. This thread is responsible for waiting for the - * process to finish, and notifying the instance when it does. - */ -void P3DAuthSession:: -spawn_wait_thread() { - SPAWN_THREAD(_wait_thread, wt_thread_run, this); - _started_wait_thread = true; -} - -/** - * Waits for the wait thread to stop. - */ -void P3DAuthSession:: -join_wait_thread() { - if (!_started_wait_thread) { - return; - } - - JOIN_THREAD(_wait_thread); - _started_wait_thread = false; -} - -/** - * Writes _env, which is formatted as a string containing zero-byte-terminated - * environment defintions, to the nout stream, one definition per line. - */ -void P3DAuthSession:: -write_env() const { - size_t p = 0; - size_t zero = _env.find('\0', p); - while (zero != string::npos) { - nout << " "; - nout.write(_env.data() + p, zero - p); - nout << "\n"; - p = zero + 1; - zero = _env.find('\0', p); - } -} - -/** - * The main function for the wait thread. - */ -void P3DAuthSession:: -wt_thread_run() { - // All we do here is wait for the process to terminate. - nout << "wt_thread_run in " << this << " beginning\n"; -#ifdef _WIN32 - DWORD result = WaitForSingleObject(_p3dcert_handle, INFINITE); - if (result != 0) { - nout << "Wait for process failed: " << GetLastError() << "\n"; - } - CloseHandle(_p3dcert_handle); - _p3dcert_handle = INVALID_HANDLE_VALUE; - _p3dcert_running = false; - nout << "p3dcert process has successfully stopped.\n"; -#else - int status; - pid_t result = waitpid(_p3dcert_pid, &status, 0); - if (result == -1) { - perror("waitpid"); - } - _p3dcert_pid = -1; - _p3dcert_running = false; - - nout << "p3dcert process has successfully stopped.\n"; - if (WIFEXITED(status)) { - nout << " exited normally, status = " - << WEXITSTATUS(status) << "\n"; - } else if (WIFSIGNALED(status)) { - nout << " signalled by " << WTERMSIG(status) << ", core = " - << WCOREDUMP(status) << "\n"; - } else if (WIFSTOPPED(status)) { - nout << " stopped by " << WSTOPSIG(status) << "\n"; - } -#endif // _WIN32 - - // Notify the instance that we're done. - P3DInstance *inst = _inst; - if (inst != nullptr) { - inst->auth_finished_sub_thread(); - } - - nout << "Exiting wt_thread_run in " << this << "\n"; -} - -#ifdef _WIN32 -/** - * Creates a sub-process to run _p3dcert_exe, with the appropriate command- - * line arguments, and the environment string defined in _env. - * - * Returns the handle to the created process on success, or - * INVALID_HANDLE_VALUE on falure. - */ -HANDLE P3DAuthSession:: -win_create_process() { - // Make sure we see an error dialog if there is a missing DLL. - SetErrorMode(0); - - STARTUPINFO startup_info; - ZeroMemory(&startup_info, sizeof(startup_info)); - startup_info.cb = sizeof(startup_info); - - // Make sure the initial window is *shown* for this graphical app. - startup_info.wShowWindow = SW_SHOW; - startup_info.dwFlags |= STARTF_USESHOWWINDOW; - - const char *start_dir_cstr = _start_dir.c_str(); - - // Construct the command-line string, containing the quoted command-line - // arguments. - std::ostringstream stream; - stream << "\"" << _p3dcert_exe << "\" \"" - << _cert_filename->get_filename() << "\" \"" << _cert_dir << "\""; - - // I'm not sure why CreateProcess wants a non-const char pointer for its - // command-line string, but I'm not taking chances. It gets a non-const - // char array that it can modify. - string command_line_str = stream.str(); - char *command_line = new char[command_line_str.size() + 1]; - memcpy(command_line, command_line_str.c_str(), command_line_str.size() + 1); - - nout << "Command line: " << command_line_str << "\n"; - - // Something about p3dCert_wx tends to become crashy when we call it from - // CreateProcessW(). Something about the way wx parses the command-line - // parameters? Well, whatever, we don't really need the Unicode form - // anyway. - PROCESS_INFORMATION process_info; - BOOL result = CreateProcess - (_p3dcert_exe.c_str(), command_line, nullptr, nullptr, TRUE, - 0, (void *)_env.c_str(), - start_dir_cstr, &startup_info, &process_info); - bool started_program = (result != 0); - - delete[] command_line; - - if (!started_program) { - nout << "CreateProcess failed, error: " << GetLastError() << "\n"; - return INVALID_HANDLE_VALUE; - } - - CloseHandle(process_info.hThread); - return process_info.hProcess; -} -#endif // _WIN32 - - -#ifndef _WIN32 -/** - * Creates a sub-process to run _p3dcert_exe, with the appropriate command- - * line arguments, and the environment string defined in _env. - * - * Returns the pid of the created process on success, or -1 on falure. - */ -int P3DAuthSession:: -posix_create_process() { - // Fork and exec. - pid_t child = fork(); - if (child < 0) { - perror("fork"); - return -1; - } - - if (child == 0) { - // Here we are in the child process. - - if (chdir(_start_dir.c_str()) < 0) { - nout << "Could not chdir to " << _start_dir << "\n"; - // This is a warning, not an error. We don't actually care that much - // about the starting directory. - } - - // build up an array of char strings for the environment. - std::vector ptrs; - size_t p = 0; - size_t zero = _env.find('\0', p); - while (zero != string::npos) { - ptrs.push_back(_env.data() + p); - p = zero + 1; - zero = _env.find('\0', p); - } - ptrs.push_back(nullptr); - - execle(_p3dcert_exe.c_str(), _p3dcert_exe.c_str(), - _cert_filename->get_filename().c_str(), _cert_dir.c_str(), - (char *)0, &ptrs[0]); - nout << "Failed to exec " << _p3dcert_exe << "\n"; - _exit(1); - } - - return child; -} -#endif // _WIN32 diff --git a/direct/src/plugin/p3dAuthSession.h b/direct/src/plugin/p3dAuthSession.h deleted file mode 100644 index f37f24d9e3..0000000000 --- a/direct/src/plugin/p3dAuthSession.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dAuthSession.h - * @author drose - * @date 2009-09-17 - */ - -#ifndef P3DAUTHSESSION_H -#define P3DAUTHSESSION_H - -#include "p3d_plugin_common.h" -#include "p3dPackage.h" -#include "get_tinyxml.h" -#include "p3dTemporaryFile.h" -#include "p3dReferenceCount.h" - -class P3DInstance; - -/** - * This is an instance of a p3dcert program running in a subprocess. There's - * no communication with the process, or none of that complicated stuff the - * P3DSession has to do; all we do here is fire off the process, then wait for - * it to exit. - */ -class P3DAuthSession : public P3DReferenceCount { -public: - P3DAuthSession(P3DInstance *inst); - ~P3DAuthSession(); - - void shutdown(bool send_message); - -private: - void start_p3dcert(); - - void spawn_wait_thread(); - void join_wait_thread(); - - void write_env() const; - -private: - // These methods run only within the read thread. - THREAD_CALLBACK_DECLARATION(P3DAuthSession, wt_thread_run); - void wt_thread_run(); - -#ifdef _WIN32 - HANDLE win_create_process(); -#else - int posix_create_process(); -#endif - -private: - P3DInstance *_inst; - std::string _start_dir; - - // This information is passed to create_process(). - P3DTemporaryFile *_cert_filename; - std::string _cert_dir; - std::string _p3dcert_exe; - std::string _env; - -#ifdef _WIN32 - HANDLE _p3dcert_handle; -#else - int _p3dcert_pid; -#endif - bool _p3dcert_started; - bool _p3dcert_running; - - // The remaining members are manipulated by or for the read thread. - bool _started_wait_thread; - THREAD _wait_thread; -}; - -#include "p3dAuthSession.I" - -#endif diff --git a/direct/src/plugin/p3dBoolObject.cxx b/direct/src/plugin/p3dBoolObject.cxx deleted file mode 100644 index 7740c2f669..0000000000 --- a/direct/src/plugin/p3dBoolObject.cxx +++ /dev/null @@ -1,68 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dBoolObject.cxx - * @author drose - * @date 2009-06-30 - */ - -#include "p3dBoolObject.h" - -/** - * - */ -P3DBoolObject:: -P3DBoolObject(bool value) : _value(value) { -} - -/** - * - */ -P3DBoolObject:: -P3DBoolObject(const P3DBoolObject ©) : - P3DObject(copy), - _value(copy._value) -{ -} - -/** - * Returns the fundamental type of this kind of object. - */ -P3D_object_type P3DBoolObject:: -get_type() { - return P3D_OT_bool; -} - -/** - * Returns the object value coerced to a boolean, if possible. - */ -bool P3DBoolObject:: -get_bool() { - return _value; -} - -/** - * Returns the object value coerced to an integer, if possible. - */ -int P3DBoolObject:: -get_int() { - return _value; -} - -/** - * Fills the indicated C++ string object with the value of this object coerced - * to a string. - */ -void P3DBoolObject:: -make_string(std::string &value) { - if (_value) { - value = "True"; - } else { - value = "False"; - } -} diff --git a/direct/src/plugin/p3dBoolObject.h b/direct/src/plugin/p3dBoolObject.h deleted file mode 100644 index 85eb0a127c..0000000000 --- a/direct/src/plugin/p3dBoolObject.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dBoolObject.h - * @author drose - * @date 2009-06-30 - */ - -#ifndef P3DBOOLOBJECT_H -#define P3DBOOLOBJECT_H - -#include "p3d_plugin_common.h" -#include "p3dObject.h" - -/** - * An object type that contains a boolean value. - */ -class P3DBoolObject : public P3DObject { -public: - P3DBoolObject(bool value); - P3DBoolObject(const P3DBoolObject ©); - -public: - virtual P3D_object_type get_type(); - virtual bool get_bool(); - virtual int get_int(); - virtual void make_string(std::string &value); - -private: - bool _value; -}; - -#endif diff --git a/direct/src/plugin/p3dCInstance.I b/direct/src/plugin/p3dCInstance.I deleted file mode 100644 index 34edfd6b62..0000000000 --- a/direct/src/plugin/p3dCInstance.I +++ /dev/null @@ -1,20 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dCInstance.I - * @author drose - * @date 2009-06-08 - */ - -/** - * Returns a unique integer for each instance in the system. - */ -inline int P3DCInstance:: -get_instance_id() const { - return _instance_id; -} diff --git a/direct/src/plugin/p3dCInstance.cxx b/direct/src/plugin/p3dCInstance.cxx deleted file mode 100644 index 0f77925b22..0000000000 --- a/direct/src/plugin/p3dCInstance.cxx +++ /dev/null @@ -1,32 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dCInstance.cxx - * @author drose - * @date 2009-06-08 - */ - -#include "p3dCInstance.h" - - -/** - * Constructs a new Instance from an XML description. - */ -P3DCInstance:: -P3DCInstance(TiXmlElement *xinstance) : - _func(nullptr) -{ - xinstance->Attribute("instance_id", &_instance_id); -} - -/** - * - */ -P3DCInstance:: -~P3DCInstance() { -} diff --git a/direct/src/plugin/p3dCInstance.h b/direct/src/plugin/p3dCInstance.h deleted file mode 100644 index 8d0ebc29c2..0000000000 --- a/direct/src/plugin/p3dCInstance.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dCInstance.h - * @author drose - * @date 2009-06-08 - */ - -#ifndef P3DCINSTANCE_H -#define P3DCINSTANCE_H - -#include "pandabase.h" - -#include "p3d_plugin.h" -#include "pvector.h" -#include "get_tinyxml.h" -#include "windowHandle.h" - -class P3DSession; - -/** - * This is an instance of a Panda3D window, as seen in the child-level - * process. - */ -class P3DCInstance : public P3D_instance { -public: - P3DCInstance(TiXmlElement *xinstance); - ~P3DCInstance(); - - inline int get_instance_id() const; - -public: - PT(WindowHandle) _parent_window_handle; - -private: - P3D_request_ready_func *_func; - - int _instance_id; - - friend class P3DPythonRun; -}; - -#include "p3dCInstance.I" - -#endif diff --git a/direct/src/plugin/p3dCert.cxx b/direct/src/plugin/p3dCert.cxx deleted file mode 100644 index e6868bdb80..0000000000 --- a/direct/src/plugin/p3dCert.cxx +++ /dev/null @@ -1,742 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dCert.cxx - * @author rdb - * @date 2011-03-08 - */ - -#include "p3dCert.h" -#include "p3dCert_strings.h" -#include "wstring_encode.h" -#include "mkdir_complete.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define BUTTON_WIDTH 180 // fit the Russian text -#define BUTTON_SPACE 10 - -#include "ca_bundle_data_src.c" - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#include -#include - -#define snprintf sprintf_s -#endif - -#ifdef __APPLE__ -#include -#endif - -using std::cerr; -using std::string; -using std::wstring; - -static LanguageIndex li = LI_default; - -#if defined(_WIN32) -static LanguageIndex detect_language() { - // This function was introduced in Windows Vista; it may not be available on - // older systems. - typedef BOOL (*GUPL)(DWORD, PULONG, PZZWSTR, PULONG); - GUPL pGetUserPreferredUILanguages = (GUPL)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), - TEXT("GetUserPreferredUILanguages")); - if (pGetUserPreferredUILanguages != nullptr) { - ULONG num_langs = 0; - ULONG buffer_size = 0; - pGetUserPreferredUILanguages(8, &num_langs, nullptr, &buffer_size); - PZZWSTR buffer = (PZZWSTR)_alloca(buffer_size); - if (pGetUserPreferredUILanguages(8, &num_langs, buffer, &buffer_size)) { - for (ULONG i = 0; i < num_langs; ++i) { - size_t len = wcslen(buffer); - if (len >= 2 && (buffer[2] == 0 || buffer[2] == L'-')) { - // It may be a two-letter code; match it in our list. - for (int j = 0; j < LI_COUNT; ++j) { - const char *lang_code = language_codes[j]; - if (lang_code != nullptr && lang_code[0] == buffer[0] && - lang_code[1] == buffer[1]) { - return (LanguageIndex)j; - } - } - } - buffer += len + 1; - } - } - } - - // Fall back to the old Windows XP function. - LANGID lang = GetUserDefaultUILanguage() & 0x3ff; - if (lang == 0) { - return LI_default; - } - - for (int i = 0; i < LI_COUNT; ++i) { - if (language_ids[i] != 0 && language_ids[i] == lang) { - return (LanguageIndex)i; - } - } - return LI_default; -} - -#elif defined(__APPLE__) -static LanguageIndex detect_language() { - // Get and iterate through the list of preferred languages. - CFArrayRef langs = CFLocaleCopyPreferredLanguages(); - CFIndex num_langs = CFArrayGetCount(langs); - - for (long i = 0; i < num_langs; ++i) { - CFStringRef lang = (CFStringRef)CFArrayGetValueAtIndex(langs, i); - - CFIndex length = CFStringGetLength(lang); - if (length < 2) { - continue; - } - - CFIndex max_size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; - char *buffer = (char *)alloca(max_size); - if (!CFStringGetCString(lang, buffer, max_size, kCFStringEncodingUTF8)) { - continue; - } - - if (isalnum(buffer[2])) { - // It's not a two-letter code. - continue; - } - - // See if we support this language. - for (int j = 0; j < LI_COUNT; ++j) { - const char *lang_code = language_codes[j]; - if (lang_code != nullptr && strncasecmp(buffer, lang_code, 2) == 0) { - CFRelease(langs); - return (LanguageIndex)j; - } - } - } - - CFRelease(langs); - return LI_default; -} - -#else -static LanguageIndex detect_language() { - // First consult the LANGUAGE variable, which is a GNU extension that can - // contain multiple languages in order of preference. - const char *lang = getenv("LANGUAGE"); - while (lang != nullptr && lang[0] != 0) { - size_t len; - const char *next = strchr(lang, ':'); - if (next == nullptr) { - len = strlen(lang); - } else { - len = (next - lang); - ++next; - } - - if (len >= 2 && !isalnum(lang[2])) { - // It may be a two-letter language code; match it in our list. - for (int i = 0; i < LI_COUNT; ++i) { - const char *lang_code = language_codes[i]; - if (lang_code != nullptr && strncasecmp(lang, lang_code, 2) == 0) { - return (LanguageIndex)i; - } - } - } - - lang = next; - } - - // Fall back to the C locale functions. - setlocale(LC_ALL, ""); - lang = setlocale(LC_MESSAGES, nullptr); - - if (lang == nullptr || lang[0] == 0 || strcmp(lang, "C") == 0) { - // Try the LANG variable. - lang = getenv("LANG"); - } - - if (lang == nullptr || strlen(lang) < 2 || isalnum(lang[2])) { - // Couldn't extract a meaningful two-letter code. - return LI_default; - } - - // It may be a two-letter language code; match it in our list. - for (int i = 0; i < LI_COUNT; ++i) { - const char *lang_code = language_codes[i]; - if (lang_code != nullptr && strncasecmp(lang, lang_code, 2) == 0) { - return (LanguageIndex)i; - } - } - return LI_default; -} -#endif - -#ifdef _WIN32 -int WINAPI -wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { - OpenSSL_add_all_algorithms(); - - LPWSTR *argv; - int argc; - argv = CommandLineToArgvW(pCmdLine, &argc); - if (argv == nullptr || argc != 2) { - cerr << "usage: p3dcert cert_filename cert_dir\n"; - return 1; - } - - li = detect_language(); - - wstring cert_filename (argv[0]); - wstring cert_dir (argv[1]); - LocalFree(argv); - - AuthDialog *dialog = new AuthDialog(cert_filename, cert_dir); - dialog->show(); - - return Fl::run(); -} - -#else // _WIN32 -int main(int argc, char **argv) { - OpenSSL_add_all_algorithms(); - - if (argc != 3) { - cerr << "usage: p3dcert cert_filename cert_dir\n"; - return 1; - } - - li = detect_language(); - - string cert_filename (argv[1]); - string cert_dir (argv[2]); - - AuthDialog *dialog = new AuthDialog(cert_filename, cert_dir); - dialog->show(1, argv); - - return Fl::run(); -} -#endif // _WIN32 - -/** - * - */ -#ifdef _WIN32 -AuthDialog:: -AuthDialog(const wstring &cert_filename, const wstring &cert_dir) : -#else -AuthDialog:: -AuthDialog(const string &cert_filename, const string &cert_dir) : -#endif - Fl_Window(435, 242, new_application_title[li]), - _cert_dir(cert_dir) -{ - _view_cert_dialog = nullptr; - - _cert = nullptr; - _stack = nullptr; - _verify_result = -1; - - // Center the window on the screen. - position((Fl::w() - w()) / 2, (Fl::h() - h()) / 2); - set_modal(); - - read_cert_file(cert_filename); - get_friendly_name(); - verify_cert(); - layout(); -} - -/** - * - */ -AuthDialog:: -~AuthDialog() { - if (_view_cert_dialog != nullptr) { - _view_cert_dialog->hide(); - } - - if (_cert != nullptr) { - X509_free(_cert); - _cert = nullptr; - } - if (_stack != nullptr) { - sk_X509_free(_stack); - _stack = nullptr; - } -} - -/** - * The user clicks the "Run" button. - */ -void AuthDialog:: -run_clicked(Fl_Widget *w, void *data) { - AuthDialog *dlg = (AuthDialog *) data; - dlg->approve_cert(); -} - -/** - * The user clicks the "View Certificate" button. - */ -void AuthDialog:: -view_cert_clicked(Fl_Widget *w, void *data) { - AuthDialog *dlg = (AuthDialog *) data; - - if (dlg->_view_cert_dialog != nullptr) { - dlg->_view_cert_dialog->hide(); - } - dlg->hide(); - dlg->_view_cert_dialog = new ViewCertDialog(dlg, dlg->_cert); - dlg->_view_cert_dialog->show(); -} - -/** - * The user clicks the "Cancel" button. - */ -void AuthDialog:: -cancel_clicked(Fl_Widget *w, void *data) { - AuthDialog *dlg = (AuthDialog *) data; - dlg->hide(); -} - -/** - * Writes the certificate into the _cert_dir, so that it will be found by the - * P3DInstanceManager and known to be approved. - */ -void AuthDialog:: -approve_cert() { - assert(_cert != nullptr); - - // Make sure the directory exists. -#ifdef _WIN32 - mkdir_complete_w(_cert_dir, cerr); -#else - mkdir_complete(_cert_dir, cerr); -#endif - - // Look for an unused filename. - int i = 1; - size_t buf_length = _cert_dir.length() + 100; - - // Sure, there's a slight race condition right now: another process might - // attempt to create the same filename. So what. - FILE *fp = nullptr; - -#ifdef _WIN32 - wchar_t *buf = new wchar_t[buf_length]; - - while (true) { - swprintf(buf, L"%s/p%d.crt", _cert_dir.c_str(), i); - assert(wcslen(buf) < buf_length); - - // Check if it already exists. If not, take it. - if (GetFileAttributesW(buf) == -1) { - break; - } - ++i; - } - fp = _wfopen(buf, L"w"); - -#else // _WIN32 - char *buf = new char[buf_length]; - - while (true) { - sprintf(buf, "%s/p%d.crt", _cert_dir.c_str(), i); - assert(strlen(buf) < buf_length); - - // Check if it already exists. If not, take it. - struct stat statbuf; - if (stat(buf, &statbuf) != 0) { - break; - } - ++i; - } - fp = fopen(buf, "w"); -#endif // _WIN32 - - if (fp != nullptr) { - PEM_write_X509(fp, _cert); - fclose(fp); - } - - hide(); -} - -/** - * Reads the list of certificates in the pem filename passed on the command - * line into _cert and _stack. - */ -#ifdef _WIN32 -void AuthDialog:: -read_cert_file(const wstring &cert_filename) { -#else -void AuthDialog:: -read_cert_file(const string &cert_filename) { -#endif - - FILE *fp = nullptr; -#ifdef _WIN32 - fp = _wfopen(cert_filename.c_str(), L"r"); -#else // _WIN32 - fp = fopen(cert_filename.c_str(), "r"); -#endif // _WIN32 - - if (fp == nullptr) { -#ifdef _WIN32 - wcerr << L"Couldn't read " << cert_filename.c_str() << L"\n"; -#else - cerr << "Couldn't read " << cert_filename.c_str() << "\n"; -#endif - return; - } - _cert = PEM_read_X509(fp, nullptr, nullptr, (void *)""); - if (_cert == nullptr) { -#ifdef _WIN32 - wcerr << L"Could not read certificate in " << cert_filename.c_str() << L".\n"; -#else - cerr << "Could not read certificate in " << cert_filename.c_str() << ".\n"; -#endif - fclose(fp); - return; - } - - // Build up a STACK of the remaining certificates in the file. - _stack = sk_X509_new(nullptr); - X509 *c = PEM_read_X509(fp, nullptr, nullptr, (void *)""); - while (c != nullptr) { - sk_X509_push(_stack, c); - c = PEM_read_X509(fp, nullptr, nullptr, (void *)""); - } - - fclose(fp); -} - -/** - * Extracts the "friendly name" from the certificate: the common name or email - * name. - */ -void AuthDialog:: -get_friendly_name() { - if (_cert == nullptr) { - _friendly_name.clear(); - return; - } - - - static const int nid_choices[] = { - NID_pkcs9_emailAddress, - NID_commonName, - -1, - }; - - // Choose the first NID that exists on the cert. - for (int ni = 0; nid_choices[ni] != -1; ++ni) { - int nid = nid_choices[ni]; - - // A complex OpenSSL interface to extract out the name in utf-8. - X509_NAME *xname = X509_get_subject_name(_cert); - if (xname != nullptr) { - int pos = X509_NAME_get_index_by_NID(xname, nid, -1); - if (pos != -1) { - // We just get the first common name. I guess it's possible to have - // more than one; not sure what that means in this context. - X509_NAME_ENTRY *xentry = X509_NAME_get_entry(xname, pos); - if (xentry != nullptr) { - ASN1_STRING *data = X509_NAME_ENTRY_get_data(xentry); - if (data != nullptr) { - // We use "print" to dump the output to a memory BIO. Is there an - // easier way to decode the ASN1_STRING? Curse these incomplete - // docs. - BIO *mbio = BIO_new(BIO_s_mem()); - ASN1_STRING_print_ex(mbio, data, ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB); - - char *pp; - long pp_size = BIO_get_mem_data(mbio, &pp); - _friendly_name = string(pp, pp_size); - BIO_free(mbio); - return; - } - } - } - } - } -} - -/** - * Checks whether the certificate is valid by the chain and initializes - * _verify_status accordingly. - */ -void AuthDialog:: -verify_cert() { - if (_cert == nullptr) { - _verify_result = -1; - return; - } - - // Create a new X509_STORE. - X509_STORE *store = X509_STORE_new(); - X509_STORE_set_default_paths(store); - - // Add in the well-known certificate authorities. - load_certificates_from_der_ram(store, (const char *)ca_bundle_data, ca_bundle_data_len); - - // Create the X509_STORE_CTX for verifying the cert and chain. - X509_STORE_CTX *ctx = X509_STORE_CTX_new(); - X509_STORE_CTX_init(ctx, store, _cert, _stack); - X509_STORE_CTX_set_cert(ctx, _cert); - - if (X509_verify_cert(ctx)) { - _verify_result = 0; - } else { - _verify_result = X509_STORE_CTX_get_error(ctx); - } - - X509_STORE_CTX_free(ctx); - - X509_STORE_free(store); - - cerr << "Got certificate from " << _friendly_name.c_str() - << ", verify_result = " << _verify_result << "\n"; -} - -/** - * Reads a chain of trusted certificates from the indicated data buffer and - * adds them to the X509_STORE object. The data buffer should be DER- - * formatted. Returns the number of certificates read on success, or 0 on - * failure. - * - * You should call this only with trusted, locally-stored certificates; not - * with certificates received from an untrusted source. - */ -int AuthDialog:: -load_certificates_from_der_ram(X509_STORE *store, - const char *data, size_t data_size) { - int count = 0; - -#if OPENSSL_VERSION_NUMBER >= 0x00908000L - // Beginning in 0.9.8, d2i_X509() accepted a const unsigned char **. - const unsigned char *bp, *bp_end; -#else - // Prior to 0.9.8, d2i_X509() accepted an unsigned char **. - unsigned char *bp, *bp_end; -#endif - - bp = (unsigned char *)data; - bp_end = bp + data_size; - X509 *x509 = d2i_X509(nullptr, &bp, bp_end - bp); - while (x509 != nullptr) { - X509_STORE_add_cert(store, x509); - ++count; - x509 = d2i_X509(nullptr, &bp, bp_end - bp); - } - - return count; -} - -/** - * Arranges the text and controls within the dialog. - */ -void AuthDialog:: -layout() { - get_text(_header, sizeof _header, _text, sizeof _text); - - // Now replicate out any @ signs in the text to avoid FlTk's escape - // sequences. - int j = 0; - for (int i = 0; _text[i] != '\0'; ++i) { - _text_clean[j++] = _text[i]; - if (_text[i] == '@') { - _text_clean[j++] = _text[i]; - } - } - _text_clean[j] = '\0'; - assert(strlen(_text_clean) < sizeof(_text_clean)); - - int next_y = 35; - if (strlen(_header) > 0) { - Fl_Box *text0 = new Fl_Box(w() / 2, next_y, 0, 25, _header); - text0->align(FL_ALIGN_TOP | FL_ALIGN_CENTER); - text0->labelfont(FL_BOLD); - text0->labelsize(text0->labelsize() * 1.5); - next_y += 25; - } - - Fl_Box *text1 = new Fl_Box(17, next_y, 400, 180, _text_clean); - text1->align(FL_ALIGN_TOP | FL_ALIGN_INSIDE | FL_ALIGN_WRAP); - next_y += 180; - - short nbuttons = 1; - if (_cert != nullptr) { - nbuttons++; - if (_verify_result == 0) { - nbuttons++; - } - } - short bx = (w() - nbuttons * BUTTON_WIDTH - (nbuttons - 1) * BUTTON_SPACE) / 2; - - if (_verify_result == 0 && _cert != nullptr) { - Fl_Return_Button *run_button = new Fl_Return_Button(bx, next_y, BUTTON_WIDTH, 25, run_title[li]); - run_button->callback(this->run_clicked, this); - bx += BUTTON_WIDTH + BUTTON_SPACE; - } - - if (_cert != nullptr) { - Fl_Button *view_button = new Fl_Button(bx, next_y, BUTTON_WIDTH, 25, show_cert_title[li]); - view_button->callback(this->view_cert_clicked, this); - bx += BUTTON_WIDTH + BUTTON_SPACE; - } - - Fl_Button *cancel_button; - cancel_button = new Fl_Button(bx, next_y, BUTTON_WIDTH, 25, cancel_title[li]); - cancel_button->callback(this->cancel_clicked, this); - - next_y += 42; - size(435, next_y); - - end(); - set_modal(); -} - -/** - * Fills in the text appropriate to display in the dialog box, based on the - * certificate read so far. - */ -void AuthDialog:: -get_text(char *header, size_t hlen, char *text, size_t tlen) { - switch (_verify_result) { - case -1: - strncpy(header, no_cert_title[li], hlen); - strncpy(text, no_cert_text[li], tlen); - break; - - case 0: - snprintf(text, tlen, verified_cert_text[li], _friendly_name.c_str(), - _friendly_name.c_str(), _friendly_name.c_str()); - break; - - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_CRL_NOT_YET_VALID: - case X509_V_ERR_CRL_HAS_EXPIRED: - strncpy(header, expired_cert_title[li], hlen); - snprintf(text, tlen, expired_cert_text[li], _friendly_name.c_str()); - break; - - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: - strncpy(header, unverified_cert_title[li], hlen); - strncpy(text, unknown_auth_cert_text[li], tlen); - break; - - case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: - strncpy(header, unverified_cert_title[li], hlen); - strncpy(text, self_signed_cert_text[li], tlen); - break; - - default: - strncpy(header, unverified_cert_title[li], hlen); - snprintf(text, tlen, generic_error_cert_text[li], _verify_result); - } -} - -/** - * - */ -ViewCertDialog:: -ViewCertDialog(AuthDialog *auth_dialog, X509 *cert) : - Fl_Window(600, 400, show_cert_title[li]), - _auth_dialog(auth_dialog), - _cert(cert) -{ - // Center the window on the screen. - position((Fl::w() - w()) / 2, (Fl::h() - h()) / 2); - set_modal(); - - layout(); -} - -/** - * - */ -ViewCertDialog:: -~ViewCertDialog() { - if (_auth_dialog != nullptr) { - _auth_dialog->_view_cert_dialog = nullptr; - } -} - -/** - * The user clicks the "Run" button. - */ -void ViewCertDialog:: -run_clicked(Fl_Widget *w, void *data) { - ViewCertDialog *dlg = (ViewCertDialog *) data; - if (dlg->_auth_dialog != nullptr){ - dlg->_auth_dialog->approve_cert(); - } - dlg->hide(); -} - -/** - * The user clicks the "Cancel" button. - */ -void ViewCertDialog:: -cancel_clicked(Fl_Widget *w, void *data) { - ViewCertDialog *dlg = (ViewCertDialog *) data; - if (dlg->_auth_dialog != nullptr){ - dlg->_auth_dialog->hide(); - } - dlg->hide(); -} - -/** - * Arranges the text and controls within the dialog. - */ -void ViewCertDialog:: -layout() { - // Format the certificate text for display in the dialog. - assert(_cert != nullptr); - - BIO *mbio = BIO_new(BIO_s_mem()); - X509_print(mbio, _cert); - - char *pp; - long pp_size = BIO_get_mem_data(mbio, &pp); - string cert_body(pp, pp_size); - BIO_free(mbio); - - Fl_Text_Buffer *buffer = new Fl_Text_Buffer; - buffer->append(cert_body.c_str()); - - Fl_Text_Display *text = new Fl_Text_Display(20, 20, 565, 320); - text->buffer(buffer); - - short bx = (w() - BUTTON_WIDTH * 2 - BUTTON_SPACE) / 2; - - Fl_Return_Button *run_button = new Fl_Return_Button(bx, 360, BUTTON_WIDTH, 25, run_title[li]); - run_button->callback(this->run_clicked, this); - - bx += BUTTON_WIDTH + BUTTON_SPACE; - - Fl_Button *cancel_button = new Fl_Button(bx, 360, BUTTON_WIDTH, 25, cancel_title[li]); - cancel_button->callback(this->cancel_clicked, this); - - end(); - set_modal(); -} diff --git a/direct/src/plugin/p3dCert.h b/direct/src/plugin/p3dCert.h deleted file mode 100644 index c17c8129e8..0000000000 --- a/direct/src/plugin/p3dCert.h +++ /dev/null @@ -1,117 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dCert.h - * @author rdb - * @date 2011-03-08 - */ - -#ifndef P3DCERT_H -#define P3DCERT_H - -#include -#include - -#define OPENSSL_NO_KRB5 -#include -#include -#include - -#include -#include -#include - -class ViewCertDialog; - -#ifndef STACK_OF - // At some point, presumably in 1.0.0, openssl went to the STACK_OF() macro - // system to typedef the contents of a stack. Unfortunately, that new API - // is different. We define some macros here here for backward compatiblity. - #define STACK_OF(type) STACK - #define sk_X509_push(stack, item) sk_push((stack), (char *)(item)) - #define sk_X509_free(stack) sk_free(stack) - #define sk_X509_new(cmp) sk_new(cmp) -#endif - -/** - * This is the primary dialog of this application. - * - * This dialog is presented to the user when he/she clicks on the red - * authorization button on the splash window. It tells the user the status of - * the application's signature, and invites the user to approve the signature - * or cancel. - */ -class AuthDialog : public Fl_Window { -public: -#ifdef _WIN32 - AuthDialog(const std::wstring &cert_filename, const std::wstring &cert_dir); -#else - AuthDialog(const std::string &cert_filename, const std::string &cert_dir); -#endif - virtual ~AuthDialog(); - - static void run_clicked(Fl_Widget *w, void *data); - static void view_cert_clicked(Fl_Widget *w, void *data); - static void cancel_clicked(Fl_Widget *w, void *data); - - void approve_cert(); - -private: -#ifdef _WIN32 - void read_cert_file(const std::wstring &cert_filename); -#else - void read_cert_file(const std::string &cert_filename); -#endif - void get_friendly_name(); - void verify_cert(); - int load_certificates_from_der_ram(X509_STORE *store, - const char *data, size_t data_size); - - void layout(); - void get_text(char *header, size_t hlen, char *text, size_t tlen); - -public: - ViewCertDialog *_view_cert_dialog; - -private: -#ifdef _WIN32 - std::wstring _cert_dir; -#else - std::string _cert_dir; -#endif - X509 *_cert; - STACK_OF(X509) *_stack; - - char _header[64]; - char _text[1024]; - char _text_clean[2048]; - - std::string _friendly_name; - int _verify_result; -}; - -/** - * This is the detailed view of the particular certificate. - */ -class ViewCertDialog : public Fl_Window { -public: - ViewCertDialog(AuthDialog *auth_dialog, X509 *cert); - virtual ~ViewCertDialog(); - - static void run_clicked(Fl_Widget *w, void *data); - static void cancel_clicked(Fl_Widget *w, void *data); - -private: - void layout(); - -private: - AuthDialog *_auth_dialog; - X509 *_cert; -}; - -#endif diff --git a/direct/src/plugin/p3dCert_strings.cxx b/direct/src/plugin/p3dCert_strings.cxx deleted file mode 100644 index 575dee34b0..0000000000 --- a/direct/src/plugin/p3dCert_strings.cxx +++ /dev/null @@ -1,567 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dCert_strings.cxx - * @author rdb - * @date 2015-03-25 - */ - -#include "p3dCert_strings.h" - -// Translations kindly provided by: eng: drwr nld: rdb deu: Sebastian Hoffmann -// spa: Imanol Celaya ita: Flavio Clava rus: montreal - -const char *language_codes[LI_COUNT] = - {"en", "nl", "de", "es", "it", "eo", "ru"}; - -// https:msdn.microsoft.comen- -// uslibrarywindowsdesktopdd318693%28v=vs.85%29.aspx -const unsigned char language_ids[LI_COUNT] = - {0x09, 0x13, 0x07, 0x0A, 0x10, 0x8F, 0x19}; - -const char * -run_title[LI_COUNT] = { - "Run", - "Uitvoeren", - "Starten", - "Ejecutar", - "Lancia", - "Lan\304\211i", - "\320\227\320\260\320\277\321\203\321\201\321\202\320\270\321\202\321\214", -}; - -const char * -cancel_title[LI_COUNT] = { - "Cancel", - "Annuleren", - "Abbrechen", - "Cancelar", - "Cancella", - "Nuligi", - "\320\236\321\202\320\274\320\265\320\275\320\260", -}; - -const char * -show_cert_title[LI_COUNT] = { - "Show Certificate", - "Toon Certificaat", - "Zertifikat anzeigen", - "Mostrar certificado", - "Mostra certificato", - "Montri Ateston", - "\320\237\320\276\320\272\320\260\320\267\320\260\321\202\321\214 \321\201" - "\320\265\321\200\321\202\320\270\321\204\320\270\320\272\320\260\321\202", -}; - -const char * -new_application_title[LI_COUNT] = { - "New Panda3D Application", - "Nieuwe Panda3D Applicatie", - "Neue Panda3D-Anwendung", - "Nueva aplicaci\303\263n de Panda3D", - "Nuova applicazione Panda3D", - "Nova aplika\304\265o de Panda3D", - "\320\235\320\276\320\262\320\276\320\265 Panda3D-\320\277\321\200\320\270" - "\320\273\320\276\320\266\320\265\320\275\320\270\320\265", -}; - -const char * -no_cert_title[LI_COUNT] = { - "No signature!", - "Geen handtekening!", - "Keine Signatur!", - "Sin firma!", - "Nessuna firma!", - "Neniu subskribo!", - "\320\235\320\265\321\202 \320\277\320\276\320\264\320\277\320\270\321\201" - "\320\270!", -}; - -const char * -unverified_cert_title[LI_COUNT] = { - "Unverified signature!", - "Ongeverifieerde handtekening!", - "Unbest\303\244tigte Signatur!", - "Firma sin verificar!", - "Firma non verificata!", - "Nekontrolita subskribo!", - "\320\235\320\265\320\277\321\200\320\276\320\262\320\265\321\200\320\265" - "\320\275\320\275\320\260\321\217 \320\277\320\276\320\264\320\277\320\270" - "\321\201\321\214!", -}; - -const char * -expired_cert_title[LI_COUNT] = { - "Expired signature!", - "Verlopen handtekening!", - "Abgelaufene Signatur!", - "Firma caducada!", - "Firma scaduta!", - "Eksvalidi\304\235inta subskribo!", - "\320\241\321\200\320\276\320\272 \320\264\320\265\320\271\321\201\321\202" - "\320\262\320\270\321\217 \320\277\320\276\320\264\320\277\320\270\321\201" - "\320\270 \320\270\321\201\321\202\321\221\320\272!", -}; - - -const char * -self_signed_cert_text[LI_COUNT] = { - // eng - "This Panda3D application uses a self-signed certificate. " - "This means the author's name can't be verified, and you have " - "no way of knowing for sure who wrote it.\n" - "\n" - "We recommend you click Cancel to avoid running this application.", - - // nld - "Deze Panda3D applicatie gebruikt een zelf-getekend certificaat. " - "Dit betekent dat de auteursnaam niet kan worden geverifieerd, en het " - "niet zeker is of de applicatie te vertrouwen is.\n" - "\n" - "Het is aanbevolen om op Annuleren te klikken om de applicatie af te " - "sluiten.", - - // deu - "Diese Panda3D-Anwendung benutzt ein selbst-signiertes Zertifikat. Dies " - "bedeutet, dass weder der Name des Autors \303\274berpr\303\274ft werden " - "kann, noch dass garantiert werden kann, dass tats\303\244chlich die " - "angegebene Person diese Anwendung geschrieben hat.\n" - "\n" - "Wir empfehlen, dass Sie Abbrechen dr\303\274cken um diese Anwendung nicht " - "auszuf\303\274hren.", - - // spa - "Esta aplicaci\303\263n de Panda3D usa un certificado autofirmado. " - "Esto significa que el nombre del autor no puede ser verificado y no se " - "puede conocer seguro quien la ha escrito.\n" - "\n" - "Se recomienda cancelar para evitar ejecutar esta aplicaci\303\263n.", - - // ita - "Questa applicazione Panda3D usa un certificato autofirmato. Ci\303\262 " - "significa che il nome dell'autore non pu\303\262 essere verificato, e " - "che non hai modo di assicurarti circa chi la abbia scritta.\n" - "\n" - "Raccomandiamo di cliccare su Cancella per evitare di lanciare questa " - "applicazione.", - - // epo - "\304\210i tiu aplika\304\265o de Panda3D uzas memsubskribitan ateston. " - "Tio signifas ke la nomo de la verkanto ne povas esti kontrolita, kaj vi " - "ne havas certan scimanieron pri la vera verkanto de la aplika\304\265o.\n" - "\n" - "Ni rekomendas ke vi premas la butonon 'Nuligi' por eviti lan\304\211on de " - "\304\211i tiu aplika\304\265o.", - - // rus - "\320\255\321\202\320\276 \320\277\321\200\320\270\320\273\320\276\320\266" - "\320\265\320\275\320\270\320\265 \320\270\321\201\320\277\320\276\320\273" - "\321\214\320\267\321\203\320\265\321\202 \321\201\320\260\320\274\320\276" - "\320\267\320\260\320\262\320\265\321\200\320\265\320\275\320\275\321\213" - "\320\271 \321\201\320\265\321\200\321\202\320\270\321\204\320\270\320\272" - "\320\260\321\202. \320\255\321\202\320\276 \320\276\320\267\320\275" - "\320\260\321\207\320\260\320\265\321\202, \321\207\321\202\320\276 " - "\320\270\320\274\321\217 \320\260\320\262\321\202\320\276\321\200\320\260 " - "\320\275\320\265 \320\274\320\276\320\266\320\265\321\202 \320\261\321\213" - "\321\202\321\214 \320\277\320\276\320\264\321\202\320\262\320\265\320\266" - "\320\264\320\265\320\275\320\276, \320\270 \320\262\321\213 \320\275" - "\320\265 \320\274\320\276\320\266\320\265\321\202\320\265 \320\267\320\275" - "\320\260\321\202\321\214, \320\272\321\202\320\276 \320\275\320\260" - "\320\277\320\270\321\201\320\260\320\273 \321\215\321\202\320\276 \320\277" - "\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.\n" - "\n" - "\320\234\321\213 \321\200\320\265\320\272\320\276\320\274\320\265\320\275" - "\320\264\321\203\320\265\320\274 \320\262\320\260\320\274 \320\275\320\260" - "\320\266\320\260\321\202\321\214 \"\320\236\321\202\320\274\320\265" - "\320\275\320\260\" \320\270 \320\275\320\265 \320\267\320\260\320\277" - "\321\203\321\201\320\272\320\260\321\202\321\214 \321\215\321\202\320\276 " - "\320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270" - "\320\265.", -}; - - -const char * -unknown_auth_cert_text[LI_COUNT] = { - "This Panda3D application has been signed, but we don't recognize " - "the authority that verifies the signature. This means the author's " - "name can't be verified, and you have no way of knowing " - "for sure who wrote it.\n" - "\n" - "We recommend you click Cancel to avoid running this application.", - - // nld - "Deze Panda3D applicatie is ondertekend, maar de certificaatautoriteit " - "die het certificaat heeft uitgegeven wordt niet herkend. Dit betekent " - "dat de auteursnaam niet te vertrouwen is, en het niet zeker is wie de " - "applicatie gemaakt heeft.\n" - "\n" - "Het is aanbevolen om op Annuleren te klikken om de applicatie af te " - "sluiten.", - - // deu - "Diese Panda3D-Anwendung wurde signiert, aber die " - "\303\234berpr\303\274fungsstelle wurde nicht anerkannt. Dies bedeutet, " - "dass weder der Name des Autors \303\274berpr\303\274ft werden kann, noch " - "dass garantiert werden kann, dass tats\303\244chlich die angegebene " - "Person diese Anwendung geschrieben hat.\n" - "\n" - "Wir empfehlen, dass Sie Abbrechen dr\303\274cken um diese Anwendung nicht " - "auszuf\303\274hren.", - - // spa - "Esta aplicaci\303\263n de Panda3D esta firmada, pero no reconocemos la " - "autoridad que la verifica. Esto significa que el nombre del autor no " - "puede ser verificado y no se puede conocer seguro quien la ha escrito.\n" - "\n" - "Se recomienda cancelar para evitar ejecutar esta aplicaci\303\263n.", - - // ita - "Questa applicazione Panda3D \303\250 stata firmata, ma non riconosciamo " - "l'autorit\303\240 che verifica la firma. Ci\303\262 significa che il " - "nome dell'autore non pu\303\262 essere verificato, e che non hai modo " - "di assicurarti circa chi la abbia scritta.\n" - "\n" - "Raccomandiamo di cliccare su Cancella per evitare di lanciare questa " - "applicazione.", - - // epo - "\304\210i tiu aplika\304\265o estas subskribita, sed ni ne rekonas " - "la a\305\255toritaton, kiu kontrolas la subskribon. Tio signifas ke la " - "nomo de la verkanto ne povas esti konfidata, kaj vi ne havas certan " - "scimanieron pri la vera verkanto de la aplika\304\265o.\n" - "\n" - "Ni rekomendas ke vi premas la butonon 'Nuligi' por eviti lan\304\211on " - "de \304\211i tiu aplika\304\265o.", - - // rus - "\320\243 \321\215\321\202\320\276\320\263\320\276 \320\277\321\200\320\270" - "\320\273\320\276\320\266\320\265\320\275\320\270\321\217 \320\265\321\201" - "\321\202\321\214 \320\277\320\276\320\264\320\277\320\270\321\201\321\214," - " \320\277\320\276 \320\272\320\276\321\202\320\276\321\200\320\276\320\271" - " \320\274\321\213 \320\275\320\265 \320\274\320\276\320\266\320\265" - "\320\274 \321\200\320\260\321\201\320\277\320\276\320\267\320\275\320\260" - "\321\202\321\214 \320\262\320\273\320\260\320\264\320\265\320\273\321\214" - "\321\206\320\260. \320\255\321\202\320\276 \320\276\320\267\320\275" - "\320\260\321\207\320\260\320\265\321\202, \321\207\321\202\320\276 " - "\320\270\320\274\321\217 \320\260\320\262\321\202\320\276\321\200\320\260 " - "\320\275\320\265 \320\274\320\276\320\266\320\265\321\202 \320\261\321\213" - "\321\202\321\214 \320\276\320\277\321\200\320\265\320\264\320\265\320\273" - "\320\265\320\275\320\276, \320\270 \320\275\320\265\320\262\320\276" - "\320\267\320\274\320\276\320\266\320\275\320\276 \321\202\320\276\321\207" - "\320\275\320\276 \321\203\320\267\320\275\320\260\321\202\321\214, " - "\320\272\321\202\320\276 \320\275\320\260\320\277\320\270\321\201\320\260" - "\320\273 \321\215\321\202\320\276 \320\277\321\200\320\270\320\273\320\276" - "\320\266\320\265\320\275\320\270\320\265.\n" - "\n" - "\320\234\321\213 \321\200\320\265\320\272\320\276\320\274\320\265\320\275" - "\320\264\321\203\320\265\320\274 \320\262\320\260\320\274 \320\275\320\260" - "\320\266\320\260\321\202\321\214 \"\320\236\321\202\320\274\320\265" - "\320\275\320\260\" \320\270 \320\275\320\265 \320\267\320\260\320\277" - "\321\203\321\201\320\272\320\260\321\202\321\214 \321\215\321\202\320\276 " - "\320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270" - "\320\265.", -}; - - -const char * -verified_cert_text[LI_COUNT] = { - // eng - "This Panda3D application has been signed by %s. " - "If you trust %s, then click the Run button below " - "to run this application on your computer. This will also " - "automatically approve this and any other applications signed by " - "%s in the future.\n" - "\n" - "If you are unsure about this application, " - "you should click Cancel instead.", - - // nld - "Deze Panda3D applicatie is ondertekend door %s. " - "Als u %s vertrouwt, klik dan de onderstaande knop Uitvoeren om de applicatie " - "op uw computer uit te voeren. Dit zal ook deze en andere door %s getekende " - "applicaties in het vervolg toestaan.\n" - "\n" - "Als u niet zeker bent over deze applicatie is het aanbevolen om op " - "Annuleren te klikken.", - - // deu - "Diese Panda3D-Anwendung wurde von %s signiert. Falls Sie %s vertrauen, " - "dr\303\274cken Sie den Starten-Knopf, um diese Anwendung auszuf\303\274hren. " - "Zudem werden in der Zukunft diese und alle anderen von %s signierten " - "Anwendungen automatisch als vertrauensw\303\274rdig anerkannt.\n" - "\n" - "Falls Sie sich unsicher \303\274ber diese Anwendung sind, sollten Sie " - "Abbrechen dr\303\274cken.", - - // spa - "Esta aplicaci\303\263n de Panda3D ha sido firmada por %s. Si se considera %s" - "de confianza el bot\303\263n inferior ejecutar\303\241 la aplicaci\303\263n." - "Esto validara esta y cualquier otra applizacion firmada por %s en el futuro.\n" - "\n" - "Si se duda de la aplicaci\303\263nse recomienda cancelar." - - // ita - "Questa applicazione Panda3D \303\250 stata firmata da %s. Se %s \303\250 " - "un'entit\303\240 fidata, allora clicca il bottone Lancia sottostante per " - "lanciare questa applicazione sul tuo computer. Inoltre, ci\303\262 " - "approver\303\240 automaticamente questa e ogni altra applicazione " - "firmata da %s in futuro.\n" - "\n" - "Se non sei sicuro circa questa applicazione, dovresti invece cliccare " - "su Cancella.", - - // epo - "\304\210i tiu aplika\304\265o estas subskribita de %s. " - "Se %s estas fidinda la\305\255 vi, premu la butonon 'Lan\304\211i' sube por " - "lan\304\211i \304\211i tiun aplika\304\265on per via komputilo. Anka\305\255 " - "tio a\305\255tomate estonece aprobos \304\211i tiun kaj alian ajn " - "aplika\304\265on, kiu estas subskribita de %s.\n" - "\n" - "Se vi ne estas certa pri \304\211i tiu aplika\304\265o, " - "vi anstata\305\255e povus premi la butonon 'Nuligi'.", - - // rus - "\320\255\321\202\320\276 \320\277\321\200\320\270\320\273\320\276\320\266" - "\320\265\320\275\320\270\320\265 \320\277\320\276\320\264\320\277\320\270" - "\321\201\320\260\320\275\320\276 %s. " - "\320\225\321\201\320\273\320\270 \320\262\321\213 \320\264\320\276\320\262" - "\320\265\321\200\321\217\320\265\321\202\320\265 %s, \320\275\320\260" - "\320\266\320\274\320\270\321\202\320\265 \320\272\320\275\320\276\320\277" - "\320\272\321\203 \"\320\227\320\260\320\277\321\203\321\201\321\202" - "\320\270\321\202\321\214\" \320\262\320\275\320\270\320\267\321\203, " - "\321\207\321\202\320\276\320\261\321\213 \320\267\320\260\320\277\321\203" - "\321\201\321\202\320\270\321\202\321\214 \321\215\321\202\320\276 \320\277" - "\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265 " - "\320\275\320\260 \320\262\320\260\321\210\320\265\320\274 \320\272\320\276" - "\320\274\320\277\321\214\321\216\321\202\320\265\321\200\320\265. \320\255" - "\321\202\320\276 \321\202\320\260\320\272\320\266\320\265 \320\260\320\262" - "\321\202\320\276\320\274\320\260\321\202\320\270\321\207\320\265\321\201" - "\320\272\320\270 \320\277\320\276\320\264\321\202\320\262\320\265\321\200" - "\320\264\320\270\321\202 \321\215\321\202\320\276 \320\270 \320\264" - "\321\200\321\203\320\263\320\270\320\265 \320\277\321\200\320\270\320\273" - "\320\276\320\266\320\265\320\275\320\270\321\217, \320\275\320\260\320\277" - "\320\270\321\201\320\260\320\275\320\275\321\213\320\265 %s \320\262 " - "\320\261\321\203\320\264\321\203\321\211\320\265\320\274.\n" - "\n" - "\320\225\321\201\320\273\320\270 \320\262\321\213 \320\275\320\265 " - "\321\203\320\262\320\265\321\200\320\265\320\275\321\213 \320\262 \321\215" - "\321\202\320\276\320\274 \320\277\321\200\320\270\320\273\320\276\320\266" - "\320\265\320\275\320\270\320\270, \320\275\320\260\320\266\320\274\320\270" - "\321\202\320\265 \320\272\320\275\320\276\320\277\320\272\321\203 \"" - "\320\236\321\202\320\274\320\265\320\275\320\260\".", -}; - - -const char * -expired_cert_text[LI_COUNT] = { - // eng - "This Panda3D application has been signed by %s, " - "but the certificate has expired.\n" - "\n" - "You should check the current date set on your computer's clock " - "to make sure it is correct.\n" - "\n" - "If your computer's date is correct, we recommend " - "you click Cancel to avoid running this application.", - - // nld - "Deze Panda3D applicatie is ondertekend door %s, maar de geldigheidsdatum " - "van het certificaat is verstreken.\n" - "\n" - "Controleer de datum op uw computerklok om te zorgen dat deze juist is " - "ingesteld.\n" - "\n" - "Als de datum op uw computer juist is, is het aanbevolen om op Annuleren te " - "klikken om de applicatie af te sluiten.", - - // deu - "Diese Anwendung wurde von %s signiert, aber das Zertifikat ist abgelaufen.\n" - "\n" - "Sie sollten die aktuelle Uhrzeit auf Ihrem Computer " - "\303\274berpr\303\274fen, um sicherzugehen, dass sie korrekt ist.\n" - "\n" - "Falls die Uhrzeit auf Ihrem Computer korrekt ist, empfehlen wir Ihnen " - "Abbrechen zu dr\303\274cken.", - - // spa - "Esta aplicaci\303\263n Panda3D ha sido firmada por %s pero el certificado ha" - "caducado.\n" - "\n" - "Se recomienda comprobar la fecha del reloj.\n" - "\n" - "Si la fecha del reloj es correcta se recomienda cancelar.", - - // ita - "Questa applicazione Panda3D \303\250 stata firmata da %s, ma il " - "certificato \303\250 scaduto.\n" - "\n" - "Dovresti controllare la data attuale impostata nell'orologio del tuo " - "computer per assicurarti che sia corretta.\n" - "\n" - "Se la data del tuo computer \303\250 corretta, raccomandiamo di cliccare " - "Cancella per evitare di lanciare questa applicazione." - - // epo - "\304\210i tiu aplika\304\265o de Panda3D estas subskribita de %s, " - "sed la atesto eksvalidi\304\235is.\n" - "\n" - "Vi povus kontroli la aktualan daton, kiu estas agordata sur la horlo\304\235o de " - "via komputilo por certigi ke \304\235i estas korekta.\n" - "\n" - "Se la dato de via komputilo estas korekta, ni rekomendas ke vi premas la " - "butonon 'Nuligi' por eviti lan\304\211on de \304\211i tiu aplika\304\265o.", - - // rus - "\320\255\321\202\320\276 \320\277\321\200\320\270\320\273\320\276\320\266" - "\320\265\320\275\320\270\320\265 \320\277\320\276\320\264\320\277\320\270" - "\321\201\320\260\320\275\320\276 %s, \320\276\320\264\320\275\320\260" - "\320\272\320\276 \321\201\321\200\320\276\320\272 \320\264\320\265\320\271" - "\321\201\321\202\320\262\320\270\321\217 \321\201\320\265\321\200\321\202" - "\320\270\321\204\320\270\320\272\320\260\321\202\320\260 \320\270\321\201" - "\321\202\321\221\320\272.\n" - "\n" - "\320\237\321\200\320\276\320\262\320\265\321\200\321\214\321\202\320\265, " - "\320\277\320\276\320\266\320\260\320\273\321\203\320\271\321\201\321\202" - "\320\260, \320\264\320\260\321\202\321\203 \320\275\320\260 \320\262" - "\320\260\321\210\320\265\320\274 \320\272\320\276\320\274\320\277\321\214" - "\321\216\321\202\320\265\321\200\320\265.\n" - "\n" - "\320\225\321\201\320\273\320\270 \320\275\320\260 \320\262\320\260\321\210" - "\320\265\320\274 \320\272\320\276\320\274\320\277\321\214\321\216\321\202" - "\320\265\321\200\320\265 \321\203\321\201\321\202\320\260\320\275\320\276" - "\320\262\320\273\320\265\320\275\320\276 \320\277\321\200\320\260\320\262" - "\320\270\320\273\321\214\320\275\320\276\320\265 \320\262\321\200\320\265" - "\320\274\321\217, \320\274\321\213 \321\200\320\265\320\272\320\276" - "\320\274\320\265\320\275\320\264\321\203\320\265\320\274 \320\262\320\260" - "\320\274 \320\275\320\260\320\266\320\260\321\202\321\214 \320\272\320\275" - "\320\276\320\277\320\272\321\203 \"\320\236\321\202\320\274\320\265" - "\320\275\320\260\" \320\270 \320\275\320\265 \320\267\320\260\320\277" - "\321\203\321\201\320\272\320\260\321\202\321\214 \321\215\321\202\320\276 " - "\320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270" - "\320\265.", -}; - - -const char * -generic_error_cert_text[LI_COUNT] = { - // eng - "This Panda3D application has been signed, but there is a problem " - "with the certificate (OpenSSL error code %d).\n" - "\n" - "We recommend you click Cancel to avoid running this application.", - - // nld - "Deze Panda3D applicatie is ondertekend, maar er is een probleem " - "met het certificaat opgetreden (OpenSSL foutcode %d).\n" - "\n" - "Het is aanbevolen om op Annuleren te klikken om de applicatie af te " - "sluiten.", - - // deu - "Diese Panda3D-Anwendung wurde signiert, aber es gibt ein Problem mit " - "dem Zertifikat (OpenSSL Fehlercode %d).\n" - "\n" - "Wir empfehlen, dass Sie Abbrechen dr\303\274cken um diese Anwendung nicht " - "auszuf\303\274hren.", - - // spa - "Esta aplicaci\303\263n de Panda3D esta firmada pero hay un problema con el " - "certificado (Error de OpenSSL %d).\n" - "\n" - "Se recomienda cancelar para evitar ejecutar esta aplicaci\303\263n.", - - // ita - "Questa applicazione Panda3D \303\250 stata firmata, ma c'\303\250 un " - "problema col certificato (codice di errore OpenSSL %s).\n" - "\n" - "Raccomandiamo di cliccare su Cancella per evitare di lanciare questa " - "applicazione.", - - // epo - "\304\210i tiu aplika\304\265o de Panda3D estas subskribita, sed la " - "atesto havas problemon (OpenSSL erarkodo %d).\n" - "\n" - "Ni rekomendas ke vi premas la butonon 'Nuligi' por eviti lan\304\211on " - "de \304\211i tiu aplika\304\265o.", - - // rus - "\320\243 \321\215\321\202\320\276\320\263\320\276 \320\277\321\200\320\270" - "\320\273\320\276\320\266\320\265\320\275\320\270\321\217 \320\265\321\201" - "\321\202\321\214 \320\277\320\276\320\264\320\277\320\270\321\201\321\214," - " \320\275\320\276 \320\262\320\276\320\267\320\275\320\270\320\272\320\273" - "\320\260 \320\277\321\200\320\276\320\261\320\273\320\265\320\274\320\260 " - "\321\201 \321\201\320\265\321\200\321\202\320\270\321\204\320\270\320\272" - "\320\260\321\202\320\276\320\274 (\320\232\320\276\320\264 \320\276" - "\321\210\320\270\320\261\320\272\320\270 OpenSSL %d).\n" - "\n" - "\320\234\321\213 \321\200\320\265\320\272\320\276\320\274\320\265\320\275" - "\320\264\321\203\320\265\320\274 \320\262\320\260\320\274 \320\275\320\260" - "\320\266\320\260\321\202\321\214 \"\320\236\321\202\320\274\320\265" - "\320\275\320\260\" \320\270 \320\275\320\265 \320\267\320\260\320\277" - "\321\203\321\201\320\272\320\260\321\202\321\214 \321\215\321\202\320\276 " - "\320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270" - "\320\265.", -}; - - -const char * -no_cert_text[LI_COUNT] = { - "This Panda3D application has not been signed. This means you have " - "no way of knowing for sure who wrote it.\n" - "\n" - "Click Cancel to avoid running this application.", - - // nld - "Deze Panda3D applicatie is niet ondertekend. Dit betekent dat het niet " - "mogelijk is om de auteur te verifi\303\253ren.\n" - "\n" - "Klik op Annuleren om de applicatie af te sluiten.", - - // deu - "Diese Panda3D-Anwendung wurde nicht signiert. Es gibt keine " - "M\303\266glichkeit festzustellen, wer diese entwickelt hat.\n" - "\n" - "Dr\303\274cken Sie Abbrechen, um diese Anwendung nicht auszuf\303\274hren.", - - // spa - "Esta aplicaci\303\263n de Panda3D no esta firmada, no hay forma de conocer " - "quien la ha escrito.\n" - "\n" - "Cancelar para evitar ejecutar la aplicaci\303\263n.", - - // ita - "Questa applicazione Panda3D non \303\250 stata firmata. Ci\303\262 " - "significa che non hai modo di assicurarti circa chi la abbia scritta.\n" - "\n" - "Clicca Cancella per evitare di lanciare questa applicazione.", - - // epo - "\304\210i tiu aplika\304\265o de Panda3D ne estas subskribita. Tio " - "signifas ke vi ne havas certan scimanieron pri la vera verkanto de " - "la aplika\304\265o.\n" - "\n" - "Premu la butonon 'Nuligi' por eviti lan\304\211on de \304\211i tiu " - "aplika\304\265o.", - - // rus - "\320\243 \321\215\321\202\320\276\320\263\320\276 \320\277\321\200\320\270" - "\320\273\320\276\320\266\320\265\320\275\320\270\321\217 \320\275\320\265" - "\321\202 \320\277\320\276\320\264\320\277\320\270\321\201\320\270. " - "\320\255\321\202\320\276 \320\276\320\267\320\275\320\260\321\207\320\260" - "\320\265\321\202, \321\207\321\202\320\276 \320\262\321\213 \320\275" - "\320\265 \320\274\320\276\320\266\320\265\321\202\320\265 \320\267\320\275" - "\320\260\321\202\321\214, \320\272\321\202\320\276 \320\265\320\263" - "\320\276 \320\275\320\260\320\277\320\270\321\201\320\260\320\273.\n" - "\n" - "\320\235\320\260\320\266\320\274\320\270\321\202\320\265 \"\320\236" - "\321\202\320\274\320\265\320\275\320\260\", \321\207\321\202\320\276" - "\320\261\321\213 \320\275\320\265 \320\267\320\260\320\277\321\203\321\201" - "\320\272\320\260\321\202\321\214 \320\277\321\200\320\270\320\273\320\276" - "\320\266\320\265\320\275\320\270\320\265.", -}; diff --git a/direct/src/plugin/p3dCert_strings.h b/direct/src/plugin/p3dCert_strings.h deleted file mode 100644 index 7e6d391e2a..0000000000 --- a/direct/src/plugin/p3dCert_strings.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dCert_strings.h - * @author rdb - * @date 2015-03-25 - */ - -enum LanguageIndex { - LI_en, // English - LI_nl, // Dutch - LI_de, // German - LI_es, // Spanish - LI_it, // Italian - LI_eo, // Esperanto - LI_ru, // Russian - LI_COUNT, - - LI_default = LI_en -}; - -extern const char *language_codes[LI_COUNT]; -extern const unsigned char language_ids[LI_COUNT]; - -extern const char *run_title[LI_COUNT]; -extern const char *cancel_title[LI_COUNT]; -extern const char *show_cert_title[LI_COUNT]; - -extern const char *new_application_title[LI_COUNT]; -extern const char *no_cert_title[LI_COUNT]; -extern const char *unverified_cert_title[LI_COUNT]; -extern const char *expired_cert_title[LI_COUNT]; - -extern const char *self_signed_cert_text[LI_COUNT]; -extern const char *unknown_auth_cert_text[LI_COUNT]; -extern const char *verified_cert_text[LI_COUNT]; -extern const char *expired_cert_text[LI_COUNT]; -extern const char *generic_error_cert_text[LI_COUNT]; -extern const char *no_cert_text[LI_COUNT]; diff --git a/direct/src/plugin/p3dCert_wx.cxx b/direct/src/plugin/p3dCert_wx.cxx deleted file mode 100644 index e7002db46a..0000000000 --- a/direct/src/plugin/p3dCert_wx.cxx +++ /dev/null @@ -1,618 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dCert_wx.cxx - * @author drose - * @date 2009-09-11 - */ - -#include "p3dCert_wx.h" -#include "wstring_encode.h" -#include "mkdir_complete.h" - -#include -#include - -#include "ca_bundle_data_src.c" - -using std::cerr; - -static const wxString -self_signed_cert_text = - _T("This Panda3D application uses a self-signed certificate. ") - _T("This means the author's name can't be verified, and you have ") - _T("no way of knowing for sure who wrote it.\n\n") - - _T("We recommend you click Cancel to avoid running this application."); - -static const wxString -unknown_auth_cert_text = - _T("This Panda3D application has been signed, but we don't recognize ") - _T("the authority that verifies the signature. This means the author's ") - _T("name can't be trusted, and you have no way of knowing ") - _T("for sure who wrote it.\n\n") - - _T("We recommend you click Cancel to avoid running this application."); - -static const wxString -verified_cert_text = - _T("This Panda3D application has been signed by %s. ") - _T("If you trust %s, then click the Run button below ") - _T("to run this application on your computer. This will also ") - _T("automatically approve this and any other applications signed by ") - _T("%s in the future.\n\n") - - _T("If you are unsure about this application, ") - _T("you should click Cancel instead."); - -static const wxString -expired_cert_text = - _T("This Panda3D application has been signed by %s, ") - _T("but the certificate has expired.\n\n") - - _T("You should check the current date set on your computer's clock ") - _T("to make sure it is correct.\n\n") - - _T("If your computer's date is correct, we recommend ") - _T("you click Cancel to avoid running this application."); - -static const wxString -generic_error_cert_text = - _T("This Panda3D application has been signed, but there is a problem ") - _T("with the certificate (OpenSSL error code %d).\n\n") - - _T("We recommend you click Cancel to avoid running this application."); - -static const wxString -no_cert_text = - _T("This Panda3D application has not been signed. This means you have ") - _T("no way of knowing for sure who wrote it.\n\n") - - _T("Click Cancel to avoid running this application."); - -// wxWidgets boilerplate macro to define main() and start up the application. -IMPLEMENT_APP(P3DCertApp) - -/** - * The "main" of a wx application. This is the first entry point. - */ -bool P3DCertApp:: -OnInit() { - // call the base class initialization method, currently it only parses a few - // common command-line options but it could be do more in the future - if (!wxApp::OnInit()) { - return false; - } - - OpenSSL_add_all_algorithms(); - - AuthDialog *dialog = new AuthDialog(_cert_filename, _cert_dir); - SetTopWindow(dialog); - dialog->Show(true); - dialog->SetFocus(); - dialog->Raise(); - - // Return true to enter the main loop and wait for user input. - return true; -} - -/** - * A callback to initialize the parser with the command line options. - */ -void P3DCertApp:: -OnInitCmdLine(wxCmdLineParser &parser) { - parser.AddParam(); - parser.AddParam(); -} - -/** - * A callback after the successful parsing of the command line. - */ -bool P3DCertApp:: -OnCmdLineParsed(wxCmdLineParser &parser) { - _cert_filename = (const char *)parser.GetParam(0).mb_str(); - _cert_dir = (const char *)parser.GetParam(1).mb_str(); - - return true; -} - - -// The event table for AuthDialog. -#define VIEW_CERT_BUTTON (wxID_HIGHEST + 1) -BEGIN_EVENT_TABLE(AuthDialog, wxDialog) - EVT_BUTTON(wxID_OK, AuthDialog::run_clicked) - EVT_BUTTON(VIEW_CERT_BUTTON, AuthDialog::view_cert_clicked) - EVT_BUTTON(wxID_CANCEL, AuthDialog::cancel_clicked) -END_EVENT_TABLE() - -/** - * - */ -AuthDialog:: -AuthDialog(const std::string &cert_filename, const std::string &cert_dir) : - // I hate stay-on-top dialogs, but if we don't set this flag, it doesn't - // come to the foreground on OSX, and might be lost behind the browser - // window. - wxDialog(nullptr, wxID_ANY, _T("New Panda3D Application"), wxDefaultPosition, - wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP), - _cert_dir(cert_dir) -{ - _view_cert_dialog = nullptr; - - _cert = nullptr; - _stack = nullptr; - _verify_result = -1; - - read_cert_file(cert_filename); - get_friendly_name(); - verify_cert(); - layout(); -} - -/** - * - */ -AuthDialog:: -~AuthDialog() { - if (_view_cert_dialog != nullptr) { - _view_cert_dialog->Destroy(); - } - - if (_cert != nullptr) { - X509_free(_cert); - _cert = nullptr; - } - if (_stack != nullptr) { - sk_X509_free(_stack); - _stack = nullptr; - } -} - -/** - * The user clicks the "Run" button. - */ -void AuthDialog:: -run_clicked(wxCommandEvent &event) { - approve_cert(); -} - -/** - * The user clicks the "View Certificate" button. - */ -void AuthDialog:: -view_cert_clicked(wxCommandEvent &event) { - if (_view_cert_dialog != nullptr) { - _view_cert_dialog->Destroy(); - } - Hide(); - _view_cert_dialog = new ViewCertDialog(this, _cert); - _view_cert_dialog->Show(); -} - -/** - * The user clicks the "Cancel" button. - */ -void AuthDialog:: -cancel_clicked(wxCommandEvent &event) { - Destroy(); -} - -/** - * Writes the certificate into the _cert_dir, so that it will be found by the - * P3DInstanceManager and known to be approved. - */ -void AuthDialog:: -approve_cert() { - assert(_cert != nullptr); - - // Make sure the directory exists. - mkdir_complete(_cert_dir, cerr); - - // Look for an unused filename. - int i = 1; - size_t buf_length = _cert_dir.length() + 100; - char *buf = new char[buf_length]; -#ifdef _WIN32 - std::wstring buf_w; -#endif // _WIN32 - - while (true) { - sprintf(buf, "%s/p%d.crt", _cert_dir.c_str(), i); - assert(strlen(buf) < buf_length); - - // Check if it already exists. If not, take it. -#ifdef _WIN32 - DWORD results = 0; - if (string_to_wstring(buf_w, buf)) { - results = GetFileAttributesW(buf_w.c_str()); - } - if (results == -1) { - break; - } -#else - struct stat statbuf; - if (stat(buf, &statbuf) != 0) { - break; - } -#endif - ++i; - } - - // Sure, there's a slight race condition right now: another process might - // attempt to create the same filename. So what. - FILE *fp = nullptr; -#ifdef _WIN32 - fp = _wfopen(buf_w.c_str(), L"w"); -#else // _WIN32 - fp = fopen(buf, "w"); -#endif // _WIN32 - if (fp != nullptr) { - PEM_write_X509(fp, _cert); - fclose(fp); - } - - Destroy(); -} - -/** - * Reads the list of certificates in the pem filename passed on the command - * line into _cert and _stack. - */ -void AuthDialog:: -read_cert_file(const std::string &cert_filename) { - FILE *fp = nullptr; -#ifdef _WIN32 - std::wstring cert_filename_w; - if (string_to_wstring(cert_filename_w, cert_filename)) { - fp = _wfopen(cert_filename_w.c_str(), L"r"); - } -#else // _WIN32 - fp = fopen(cert_filename.c_str(), "r"); -#endif // _WIN32 - - if (fp == nullptr) { - cerr << "Couldn't read " << cert_filename << "\n"; - return; - } - _cert = PEM_read_X509(fp, nullptr, nullptr, (void *)""); - if (_cert == nullptr) { - cerr << "Could not read certificate in " << cert_filename << ".\n"; - fclose(fp); - return; - } - - // Build up a STACK of the remaining certificates in the file. - _stack = sk_X509_new(nullptr); - X509 *c = PEM_read_X509(fp, nullptr, nullptr, (void *)""); - while (c != nullptr) { - sk_X509_push(_stack, c); - c = PEM_read_X509(fp, nullptr, nullptr, (void *)""); - } - - fclose(fp); -} - -/** - * Extracts the "friendly name" from the certificate: the common name or email - * name. - */ -void AuthDialog:: -get_friendly_name() { - if (_cert == nullptr) { - _friendly_name.clear(); - return; - } - - - static const int nid_choices[] = { - NID_pkcs9_emailAddress, - NID_commonName, - -1, - }; - - // Choose the first NID that exists on the cert. - for (int ni = 0; nid_choices[ni] != -1; ++ni) { - int nid = nid_choices[ni]; - - // A complex OpenSSL interface to extract out the name in utf-8. - X509_NAME *xname = X509_get_subject_name(_cert); - if (xname != nullptr) { - int pos = X509_NAME_get_index_by_NID(xname, nid, -1); - if (pos != -1) { - // We just get the first common name. I guess it's possible to have - // more than one; not sure what that means in this context. - X509_NAME_ENTRY *xentry = X509_NAME_get_entry(xname, pos); - if (xentry != nullptr) { - ASN1_STRING *data = X509_NAME_ENTRY_get_data(xentry); - if (data != nullptr) { - // We use "print" to dump the output to a memory BIO. Is there an - // easier way to decode the ASN1_STRING? Curse these incomplete - // docs. - BIO *mbio = BIO_new(BIO_s_mem()); - ASN1_STRING_print_ex(mbio, data, ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB); - - char *pp; - long pp_size = BIO_get_mem_data(mbio, &pp); - _friendly_name = wxString(pp, wxConvUTF8, pp_size); - BIO_free(mbio); - return; - } - } - } - } - } -} - -/** - * Checks whether the certificate is valid by the chain and initializes - * _verify_status accordingly. - */ -void AuthDialog:: -verify_cert() { - if (_cert == nullptr) { - _verify_result = -1; - return; - } - - // Create a new X509_STORE. - X509_STORE *store = X509_STORE_new(); - X509_STORE_set_default_paths(store); - - // Add in the well-known certificate authorities. - load_certificates_from_der_ram(store, (const char *)ca_bundle_data, ca_bundle_data_len); - - // Create the X509_STORE_CTX for verifying the cert and chain. - X509_STORE_CTX *ctx = X509_STORE_CTX_new(); - X509_STORE_CTX_init(ctx, store, _cert, _stack); - X509_STORE_CTX_set_cert(ctx, _cert); - - if (X509_verify_cert(ctx)) { - _verify_result = 0; - } else { - _verify_result = X509_STORE_CTX_get_error(ctx); - } - - X509_STORE_CTX_free(ctx); - - X509_STORE_free(store); - - cerr << "Got certificate from " << _friendly_name.mb_str() - << ", verify_result = " << _verify_result << "\n"; -} - -/** - * Reads a chain of trusted certificates from the indicated data buffer and - * adds them to the X509_STORE object. The data buffer should be DER- - * formatted. Returns the number of certificates read on success, or 0 on - * failure. - * - * You should call this only with trusted, locally-stored certificates; not - * with certificates received from an untrusted source. - */ -int AuthDialog:: -load_certificates_from_der_ram(X509_STORE *store, - const char *data, size_t data_size) { - int count = 0; - -#if OPENSSL_VERSION_NUMBER >= 0x00908000L - // Beginning in 0.9.8, d2i_X509() accepted a const unsigned char **. - const unsigned char *bp, *bp_end; -#else - // Prior to 0.9.8, d2i_X509() accepted an unsigned char **. - unsigned char *bp, *bp_end; -#endif - - bp = (unsigned char *)data; - bp_end = bp + data_size; - X509 *x509 = d2i_X509(nullptr, &bp, bp_end - bp); - while (x509 != nullptr) { - X509_STORE_add_cert(store, x509); - ++count; - x509 = d2i_X509(nullptr, &bp, bp_end - bp); - } - - return count; -} - -/** - * Arranges the text and controls within the dialog. - */ -void AuthDialog:: -layout() { - wxString header, text; - get_text(header, text); - - wxPanel *panel = new wxPanel(this); - wxBoxSizer *vsizer = new wxBoxSizer(wxVERTICAL); - - wxFont font = panel->GetFont(); - wxFont *bold_font = wxTheFontList->FindOrCreateFont - ((int)(font.GetPointSize() * 1.5), - font.GetFamily(), font.GetStyle(), wxFONTWEIGHT_BOLD); - - if (!header.IsEmpty()) { - wxStaticText *text0 = new wxStaticText - (panel, wxID_ANY, header, wxDefaultPosition, wxDefaultSize, - wxALIGN_CENTER); - text0->SetFont(*bold_font); - vsizer->Add(text0, 0, wxCENTER | wxALL, 10); - } - - wxStaticText *text1 = new wxStaticText - (panel, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER); - text1->Wrap(400); - vsizer->Add(text1, 0, wxCENTER | wxALL, 10); - - // Create the run cancel buttons. - wxBoxSizer *bsizer = new wxBoxSizer(wxHORIZONTAL); - - if (_verify_result == 0 && _cert != nullptr) { - wxButton *run_button = new wxButton(panel, wxID_OK, _T("Run")); - bsizer->Add(run_button, 0, wxALIGN_CENTER | wxALL, 5); - } - - if (_cert != nullptr) { - wxButton *view_button = new wxButton(panel, VIEW_CERT_BUTTON, _T("View Certificate")); - bsizer->Add(view_button, 0, wxALIGN_CENTER | wxALL, 5); - } - - wxButton *cancel_button = new wxButton(panel, wxID_CANCEL, _T("Cancel")); - bsizer->Add(cancel_button, 0, wxALIGN_CENTER | wxALL, 5); - - vsizer->Add(bsizer, 0, wxALIGN_CENTER | wxALL, 5); - - panel->SetSizer(vsizer); - panel->SetAutoLayout(true); - vsizer->Fit(this); -} - -/** - * Fills in the text appropriate to display in the dialog box, based on the - * certificate read so far. - */ -void AuthDialog:: -get_text(wxString &header, wxString &text) { - switch (_verify_result) { - case -1: - header = _T("No signature!"); - text = no_cert_text; - break; - - case 0: - text.Printf(verified_cert_text, _friendly_name.c_str(), _friendly_name.c_str(), _friendly_name.c_str()); - break; - - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_CRL_NOT_YET_VALID: - case X509_V_ERR_CRL_HAS_EXPIRED: - header = _T("Expired signature!"); - text.Printf(expired_cert_text, _friendly_name.c_str()); - break; - - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: - header = _T("Unverified signature!"); - text.Printf(unknown_auth_cert_text, _friendly_name.c_str()); - break; - - case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: - header = _T("Unverified signature!"); - text = self_signed_cert_text; - break; - - default: - header = _T("Unverified signature!"); - text.Printf(generic_error_cert_text, _verify_result); - } -} - - -// The event table for ViewCertDialog. -BEGIN_EVENT_TABLE(ViewCertDialog, wxDialog) - EVT_BUTTON(wxID_OK, ViewCertDialog::run_clicked) - EVT_BUTTON(wxID_CANCEL, ViewCertDialog::cancel_clicked) -END_EVENT_TABLE() - -/** - * - */ -ViewCertDialog:: -ViewCertDialog(AuthDialog *auth_dialog, X509 *cert) : -wxDialog(nullptr, wxID_ANY, _T("View Certificate"), wxDefaultPosition, - wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), - _auth_dialog(auth_dialog), - _cert(cert) -{ - layout(); -} - -/** - * - */ -ViewCertDialog:: -~ViewCertDialog() { - if (_auth_dialog != nullptr) { - _auth_dialog->_view_cert_dialog = nullptr; - } -} - -/** - * The user clicks the "Run" button. - */ -void ViewCertDialog:: -run_clicked(wxCommandEvent &event) { - if (_auth_dialog != nullptr){ - _auth_dialog->approve_cert(); - } - Destroy(); -} - -/** - * The user clicks the "Cancel" button. - */ -void ViewCertDialog:: -cancel_clicked(wxCommandEvent &event) { - if (_auth_dialog != nullptr){ - _auth_dialog->Destroy(); - } - Destroy(); -} - -/** - * Arranges the text and controls within the dialog. - */ -void ViewCertDialog:: -layout() { - // Format the certificate text for display in the dialog. - assert(_cert != nullptr); - - BIO *mbio = BIO_new(BIO_s_mem()); - X509_print(mbio, _cert); - - char *pp; - long pp_size = BIO_get_mem_data(mbio, &pp); - wxString cert_body(pp, wxConvUTF8, pp_size); - BIO_free(mbio); - - wxPanel *panel = new wxPanel(this); - wxBoxSizer *vsizer = new wxBoxSizer(wxVERTICAL); - - wxScrolledWindow *slwin = new wxScrolledWindow - (panel, -1, wxDefaultPosition, wxDefaultSize, wxVSCROLL | wxHSCROLL | wxBORDER_SUNKEN); - slwin->SetScrollRate(20, 20); - - wxBoxSizer *slsizer = new wxBoxSizer(wxVERTICAL); - - wxStaticText *text1 = new wxStaticText - (slwin, wxID_ANY, cert_body, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); - slsizer->Add(text1, 0, wxEXPAND, 0); - slwin->SetSizer(slsizer); - - vsizer->Add(slwin, 1, wxEXPAND | wxALL, 10); - - // Create the run cancel buttons. - wxBoxSizer *bsizer = new wxBoxSizer(wxHORIZONTAL); - - wxButton *run_button = new wxButton(panel, wxID_OK, _T("Run")); - bsizer->Add(run_button, 0, wxALIGN_CENTER | wxALL, 5); - - wxButton *cancel_button = new wxButton(panel, wxID_CANCEL, _T("Cancel")); - bsizer->Add(cancel_button, 0, wxALIGN_CENTER | wxALL, 5); - - vsizer->Add(bsizer, 0, wxALIGN_CENTER | wxALL, 5); - - panel->SetSizer(vsizer); - panel->SetAutoLayout(true); - vsizer->Fit(this); - - // Make sure the resulting window is at least a certain size. - int width, height; - GetSize(&width, &height); - SetSize(std::max(width, 600), std::max(height, 400)); -} diff --git a/direct/src/plugin/p3dCert_wx.h b/direct/src/plugin/p3dCert_wx.h deleted file mode 100644 index b0b3dda12e..0000000000 --- a/direct/src/plugin/p3dCert_wx.h +++ /dev/null @@ -1,119 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dCert_wx.h - * @author drose - * @date 2009-09-11 - */ - -#ifndef P3DCERT_WX_H -#define P3DCERT_WX_H - -#include - -#define OPENSSL_NO_KRB5 -#include -#include -#include - -#include -#include -#include - -class ViewCertDialog; - -#ifndef STACK_OF - // At some point, presumably in 1.0.0, openssl went to the STACK_OF() macro - // system to typedef the contents of a stack. Unfortunately, that new API - // is different. We define some macros here here for backward compatiblity. - #define STACK_OF(type) STACK - #define sk_X509_push(stack, item) sk_push((stack), (char *)(item)) - #define sk_X509_free(stack) sk_free(stack) - #define sk_X509_new(cmp) sk_new(cmp) -#endif - -/** - * This is the wxApp that drives this application. - */ -class P3DCertApp : public wxApp { -public: - virtual bool OnInit(); - virtual void OnInitCmdLine(wxCmdLineParser &parser); - virtual bool OnCmdLineParsed(wxCmdLineParser &parser); - -private: - std::string _cert_filename; - std::string _cert_dir; -}; - -/** - * This is the primary dialog of this application. - * - * This dialog is presented to the user when he/she clicks on the red - * authorization button on the splash window. It tells the user the status of - * the application's signature, and invites the user to approve the signature - * or cancel. - */ -class AuthDialog : public wxDialog { -public: - AuthDialog(const std::string &cert_filename, const std::string &cert_dir); - virtual ~AuthDialog(); - - void run_clicked(wxCommandEvent &event); - void view_cert_clicked(wxCommandEvent &event); - void cancel_clicked(wxCommandEvent &event); - - void approve_cert(); - -private: - void read_cert_file(const std::string &cert_filename); - void get_friendly_name(); - void verify_cert(); - int load_certificates_from_der_ram(X509_STORE *store, - const char *data, size_t data_size); - - void layout(); - void get_text(wxString &header, wxString &text); - -public: - ViewCertDialog *_view_cert_dialog; - -private: - // any class wishing to process wxWidgets events must use this macro - DECLARE_EVENT_TABLE() - - std::string _cert_dir; - X509 *_cert; - STACK_OF(X509) *_stack; - - wxString _friendly_name; - int _verify_result; -}; - -/** - * This is the detailed view of the particular certificate. - */ -class ViewCertDialog : public wxDialog { -public: - ViewCertDialog(AuthDialog *auth_dialog, X509 *cert); - virtual ~ViewCertDialog(); - - void run_clicked(wxCommandEvent &event); - void cancel_clicked(wxCommandEvent &event); - -private: - void layout(); - -private: - DECLARE_EVENT_TABLE() - - AuthDialog *_auth_dialog; - X509 *_cert; -}; - -#endif diff --git a/direct/src/plugin/p3dConcreteSequence.cxx b/direct/src/plugin/p3dConcreteSequence.cxx deleted file mode 100644 index ec4291cb7b..0000000000 --- a/direct/src/plugin/p3dConcreteSequence.cxx +++ /dev/null @@ -1,213 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dConcreteSequence.cxx - * @author drose - * @date 2009-06-30 - */ - -#include "p3dConcreteSequence.h" -#include "p3dSession.h" - -/** - * - */ -P3DConcreteSequence:: -P3DConcreteSequence() { -} - -/** - * - */ -P3DConcreteSequence:: -~P3DConcreteSequence() { - Elements::iterator ei; - for (ei = _elements.begin(); ei != _elements.end(); ++ei) { - P3D_OBJECT_DECREF(*ei); - } -} - -/** - * Returns true if this is actually an instance of a P3DConcreteSequence, - * false otherwise. - */ -bool P3DConcreteSequence:: -is_sequence_object() { - return true; -} - -/** - * Returns the fundamental type of this kind of object. - */ -P3D_object_type P3DConcreteSequence:: -get_type() { - return P3D_OT_object; -} - -/** - * Returns the object value coerced to a boolean, if possible. - */ -bool P3DConcreteSequence:: -get_bool() { - return !_elements.empty(); -} - -/** - * Fills the indicated C++ string object with the value of this object coerced - * to a string. - */ -void P3DConcreteSequence:: -make_string(std::string &value) { - std::ostringstream strm; - strm << "["; - if (!_elements.empty()) { - strm << *_elements[0]; - for (size_t i = 1; i < _elements.size(); ++i) { - strm << ", " << *_elements[i]; - } - } - strm << "]"; - - value = strm.str(); -} - -/** - * Returns the named property element in the object. The return value is a - * new-reference P3D_object, or NULL on error. - */ -P3D_object *P3DConcreteSequence:: -get_property(const std::string &property) { - // We only understand integer "property" names. - char *endptr; - int index = strtoul(property.c_str(), &endptr, 10); - if (*endptr != '\0') { - return nullptr; - } - - return get_element(index); -} - -/** - * Modifies (or deletes, if value is NULL) the named property element in the - * object. Returns true on success, false on failure. - */ -bool P3DConcreteSequence:: -set_property(const std::string &property, P3D_object *value) { - // We only understand integer "property" names. - char *endptr; - int index = strtoul(property.c_str(), &endptr, 10); - if (*endptr != '\0') { - return false; - } - - return set_element(index, value); -} - -/** - * If this object has a valid XML representation for the indicated session - * (that hasn't already been implemented by the generic code in P3DSession), - * this method will apply it to the indicated "value" element and return true. - * Otherwise, this method will leave the element unchanged and return false. - */ -bool P3DConcreteSequence:: -fill_xml(TiXmlElement *xvalue, P3DSession *session) { - xvalue->SetAttribute("type", "concrete_sequence"); - Elements::const_iterator ei; - for (ei = _elements.begin(); ei != _elements.end(); ++ei) { - xvalue->LinkEndChild(session->p3dobj_to_xml(*ei)); - } - - return true; -} - -/** - * Returns a pointer to the array of objects represented by this object. Most - * objects represent only themselves, but a P3DConcreteSequence represents its - * list. - */ -P3D_object **P3DConcreteSequence:: -get_object_array() { - if (_elements.empty()) { - return nullptr; - } - return &_elements[0]; -} - -/** - * Returns the number of elements in the array returned by get_object_array(). - */ -int P3DConcreteSequence:: -get_object_array_size() { - return _elements.size(); -} - -/** - * Returns the number of items in the sequence. - */ -int P3DConcreteSequence:: -get_length() const { - return _elements.size(); -} - -/** - * Returns the nth item in the sequence. The return value is a new-reference - * P3DObject object, or NULL on error. - */ -P3D_object *P3DConcreteSequence:: -get_element(int n) const { - if (n >= 0 && n < (int)_elements.size()) { - P3D_OBJECT_INCREF(_elements[n]); - return _elements[n]; - } - - return nullptr; -} - -/** - * Modifies (or deletes, if value is NULL) the nth item in the sequence. - * Returns true on success, false on failure. - */ -bool P3DConcreteSequence:: -set_element(int n, P3D_object *value) { - if (value == nullptr) { - // Delete an element. - if (n < 0 || n >= (int)_elements.size()) { - // Invalid index. - return false; - } - P3D_OBJECT_DECREF(_elements[n]); - _elements.erase(_elements.begin() + n); - return true; - - } else if (n == _elements.size()) { - // Append an element. - append(value); - return true; - - } else { - // Replace an element. - if (n < 0 || n >= (int)_elements.size()) { - // Invalid index. - return false; - } - - P3D_OBJECT_INCREF(value); - P3D_OBJECT_DECREF(_elements[n]); - _elements[n] = value; - return true; - } -} - -/** - * Adds a new element to the end of the list. - */ -void P3DConcreteSequence:: -append(P3D_object *value) { - _elements.push_back(value); - P3D_OBJECT_INCREF(value); -} diff --git a/direct/src/plugin/p3dConcreteSequence.h b/direct/src/plugin/p3dConcreteSequence.h deleted file mode 100644 index 09b489c5ba..0000000000 --- a/direct/src/plugin/p3dConcreteSequence.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dConcreteSequence.h - * @author drose - * @date 2009-06-30 - */ - -#ifndef P3DCONCRETESEQUENCE_H -#define P3DCONCRETESEQUENCE_H - -#include "p3d_plugin_common.h" -#include "p3dObject.h" - -/** - * An object type that contains a sequence of objects, which is passed by - * value between Python and JavaScript, so may be more optimal for small lists - * that are accessed repeatedly. - * - * This is converted from a Python "tuple" object. - */ -class P3DConcreteSequence : public P3DObject { -public: - P3DConcreteSequence(); - virtual ~P3DConcreteSequence(); - - virtual bool is_sequence_object(); - - virtual P3D_object_type get_type(); - virtual bool get_bool(); - - virtual void make_string(std::string &value); - - virtual P3D_object *get_property(const std::string &property); - virtual bool set_property(const std::string &property, P3D_object *value); - - virtual bool fill_xml(TiXmlElement *xvalue, P3DSession *session); - virtual P3D_object **get_object_array(); - virtual int get_object_array_size(); - - int get_length() const; - P3D_object *get_element(int n) const; - bool set_element(int n, P3D_object *value); - void append(P3D_object *value); - -private: - typedef std::vector Elements; - Elements _elements; -}; - -#endif diff --git a/direct/src/plugin/p3dConcreteStruct.cxx b/direct/src/plugin/p3dConcreteStruct.cxx deleted file mode 100644 index fa9917d955..0000000000 --- a/direct/src/plugin/p3dConcreteStruct.cxx +++ /dev/null @@ -1,178 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dConcreteStruct.cxx - * @author drose - * @date 2009-07-14 - */ - -#include "p3dConcreteStruct.h" - -using std::string; - -/** - * - */ -P3DConcreteStruct:: -P3DConcreteStruct() { -} - -/** - * - */ -P3DConcreteStruct:: -~P3DConcreteStruct() { - Elements::iterator ei; - for (ei = _elements.begin(); ei != _elements.end(); ++ei) { - P3D_OBJECT_DECREF((*ei).second); - } -} - -/** - * Returns the fundamental type of this kind of object. - */ -P3D_object_type P3DConcreteStruct:: -get_type() { - return P3D_OT_object; -} - -/** - * Returns the object value coerced to a boolean, if possible. - */ -bool P3DConcreteStruct:: -get_bool() { - return !_elements.empty(); -} - -/** - * Fills the indicated C++ string object with the value of this object coerced - * to a string. - */ -void P3DConcreteStruct:: -make_string(string &value) { - std::ostringstream strm; - strm << "{"; - if (!_elements.empty()) { - Elements::iterator ei; - ei = _elements.begin(); - strm << (*ei).first << ": " << *(*ei).second; - ++ei; - while (ei != _elements.end()) { - strm << ", " << (*ei).first << ": " << *(*ei).second; - ++ei; - } - } - strm << "}"; - - value = strm.str(); -} - -/** - * Returns the named property element in the object. The return value is a - * new-reference P3D_object, or NULL on error. - */ -P3D_object *P3DConcreteStruct:: -get_property(const string &property) { - Elements::const_iterator ei = _elements.find(property); - if (ei != _elements.end()) { - P3D_OBJECT_INCREF((*ei).second); - return (*ei).second; - } - - return nullptr; -} - -/** - * Modifies (or deletes, if value is NULL) the named property element in the - * object. Returns true on success, false on failure. - */ -bool P3DConcreteStruct:: -set_property(const string &property, P3D_object *value) { - if (value == nullptr) { - // Delete an element. - Elements::iterator ei = _elements.find(property); - if (ei == _elements.end()) { - // Invalid property. - return false; - } - P3D_OBJECT_DECREF((*ei).second); - _elements.erase(ei); - return true; - - } else { - // Replace or insert an element. - P3D_OBJECT_INCREF(value); - std::pair result = _elements.insert(Elements::value_type(property, value)); - if (!result.second) { - // Replacing an element. - Elements::iterator ei = result.first; - P3D_OBJECT_DECREF((*ei).second); - (*ei).second = value; - } - return true; - } -} - -/** - * Returns true if the named method exists on this object, false otherwise. - */ -bool P3DConcreteStruct:: -has_method(const string &method_name) { - if (method_name == "toString") { - return true; - } - - return false; -} - -/** - * Invokes the named method on the object, passing the indicated parameters. - * If the method name is empty, invokes the object itself. - * - * If needs_response is true, the return value is a new-reference P3D_object - * on success, or NULL on failure. If needs_response is false, the return - * value is always NULL, and there is no way to determine success or failure. - */ -P3D_object *P3DConcreteStruct:: -call(const string &method_name, bool needs_response, - P3D_object *params[], int num_params) { - P3D_object *result = nullptr; - - if (method_name == "toString") { - string value; - make_string(value); - result = P3D_new_string_object(value.data(), value.length()); - } - - if (result != nullptr && !needs_response) { - P3D_OBJECT_DECREF(result); - result = nullptr; - } - - return result; -} - - -/** - * If this object has a valid XML representation for the indicated session - * (that hasn't already been implemented by the generic code in P3DSession), - * this method will apply it to the indicated "value" element and return true. - * Otherwise, this method will leave the element unchanged and return false. - */ -bool P3DConcreteStruct:: -fill_xml(TiXmlElement *xvalue, P3DSession *session) { - xvalue->SetAttribute("type", "concrete_struct"); - Elements::const_iterator ei; - for (ei = _elements.begin(); ei != _elements.end(); ++ei) { - TiXmlElement *xitem = session->p3dobj_to_xml((*ei).second); - xitem->SetAttribute("key", (*ei).first); - xvalue->LinkEndChild(xitem); - } - - return true; -} diff --git a/direct/src/plugin/p3dConcreteStruct.h b/direct/src/plugin/p3dConcreteStruct.h deleted file mode 100644 index cccd35bbeb..0000000000 --- a/direct/src/plugin/p3dConcreteStruct.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dConcreteStruct.h - * @author drose - * @date 2009-07-14 - */ - -#ifndef P3DCONCRETESTRUCT_H -#define P3DCONCRETESTRUCT_H - -#include "p3d_plugin_common.h" -#include "p3dObject.h" - -/** - * A simple object that contains a standard mapping of string -> element. It - * is passed by value between Python and Javascript, so it may be more optimal - * for relatively small objects. - * - * Methods are not supported, other than built-in methods like toString(). - */ -class P3DConcreteStruct : public P3DObject { -public: - P3DConcreteStruct(); - virtual ~P3DConcreteStruct(); - - virtual P3D_object_type get_type(); - virtual bool get_bool(); - - virtual void make_string(std::string &value); - - virtual P3D_object *get_property(const std::string &property); - virtual bool set_property(const std::string &property, P3D_object *value); - - virtual bool has_method(const std::string &method_name); - virtual P3D_object *call(const std::string &method_name, bool needs_response, - P3D_object *params[], int num_params); - - virtual bool fill_xml(TiXmlElement *xvalue, P3DSession *session); - -private: - typedef std::map Elements; - Elements _elements; -}; - -#endif diff --git a/direct/src/plugin/p3dConditionVar.I b/direct/src/plugin/p3dConditionVar.I deleted file mode 100644 index 08ae4ffe7e..0000000000 --- a/direct/src/plugin/p3dConditionVar.I +++ /dev/null @@ -1,12 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dConditionVar.I - * @author drose - * @date 2009-07-02 - */ diff --git a/direct/src/plugin/p3dConditionVar.cxx b/direct/src/plugin/p3dConditionVar.cxx deleted file mode 100644 index 22133c0781..0000000000 --- a/direct/src/plugin/p3dConditionVar.cxx +++ /dev/null @@ -1,171 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dConditionVar.cxx - * @author drose - * @date 2009-07-02 - */ - -#include "p3dConditionVar.h" - -#ifndef _WIN32 -#include -#include -#endif -#include - -/** - * - */ -P3DConditionVar:: -P3DConditionVar() { -#ifdef _WIN32 - InitializeCriticalSection(&_lock); - - // Create an auto-reset event. - _event_signal = CreateEvent(nullptr, false, false, nullptr); - -#else // _WIN32 - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); - int result = pthread_mutex_init(&_lock, &attr); - pthread_mutexattr_destroy(&attr); - assert(result == 0); - - result = pthread_cond_init(&_cvar, nullptr); - assert(result == 0); - -#endif // _WIN32 -} - -/** - * - */ -P3DConditionVar:: -~P3DConditionVar() { -#ifdef _WIN32 - DeleteCriticalSection(&_lock); - CloseHandle(_event_signal); - -#else // _WIN32 - int result = pthread_mutex_destroy(&_lock); - assert(result == 0); - - result = pthread_cond_destroy(&_cvar); - assert(result == 0); - -#endif // _WIN32 -} - -/** - * Acquires the internal lock. The lock should be held during any calls to - * wait() or notify(). - */ -void P3DConditionVar:: -acquire() { -#ifdef _WIN32 - EnterCriticalSection(&_lock); - -#else // _WIN32 - int result = pthread_mutex_lock(&_lock); - assert(result == 0); - -#endif // _WIN32 -} - -/** - * Requires the lock to be held on entry. Releases the lock, waits for - * another thread to call notify(), then reacquires the lock on exit. - */ -void P3DConditionVar:: -wait() { -#ifdef _WIN32 - LeaveCriticalSection(&_lock); - - DWORD result = WaitForSingleObject(_event_signal, INFINITE); - assert(result == WAIT_OBJECT_0); - - EnterCriticalSection(&_lock); - -#else // _WIN32 - int result = pthread_cond_wait(&_cvar, &_lock); - assert(result == 0); - -#endif // _WIN32 -} - -/** - * As above, but waits no longer than timeout seconds before returning. - */ -void P3DConditionVar:: -wait(double timeout) { -#ifdef _WIN32 - LeaveCriticalSection(&_lock); - - DWORD result = WaitForSingleObject(_event_signal, (DWORD)(timeout * 1000.0)); - assert(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT); - - EnterCriticalSection(&_lock); -#else // _WIN32 - - struct timeval now; - gettimeofday(&now, nullptr); - - // Convert from timeval to timespec - struct timespec ts; - ts.tv_sec = now.tv_sec; - ts.tv_nsec = now.tv_usec * 1000; - - int seconds = (int)floor(timeout); - ts.tv_sec += seconds; - ts.tv_nsec += (int)((timeout - seconds) * 1000000.0); - if (ts.tv_nsec > 1000000) { - ts.tv_nsec -= 1000000; - ++ts.tv_sec; - } - - int result = pthread_cond_timedwait(&_cvar, &_lock, &ts); - if (result != 0 && result != ETIMEDOUT) { - errno = result; - perror("pthread_cond_timedwait"); - } - -#endif // _WIN32 -} - -/** - * Waits a single thread blocked on wait(), if any. If no threads are - * waiting, the event is lost. The lock should be held during this call. - */ -void P3DConditionVar:: -notify() { -#ifdef _WIN32 - SetEvent(_event_signal); - -#else // _WIN32 - int result = pthread_cond_signal(&_cvar); - assert(result == 0); - -#endif // _WIN32 -} - -/** - * Releases the internal lock. - */ -void P3DConditionVar:: -release() { -#ifdef _WIN32 - LeaveCriticalSection(&_lock); - -#else // _WIN32 - int result = pthread_mutex_unlock(&_lock); - assert(result == 0); - -#endif // _WIN32 -} diff --git a/direct/src/plugin/p3dConditionVar.h b/direct/src/plugin/p3dConditionVar.h deleted file mode 100644 index f4de8f549d..0000000000 --- a/direct/src/plugin/p3dConditionVar.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dConditionVar.h - * @author drose - * @date 2009-07-02 - */ - -#ifndef P3DCONDITIONVAR_H -#define P3DCONDITIONVAR_H - -#include "p3d_plugin_common.h" - -/** - * A simple condition-variable like object. It doesn't support the full - * condition-var semantics, but it works well enough with one waiter and one - * signaller. - */ -class P3DConditionVar { -public: - P3DConditionVar(); - ~P3DConditionVar(); - - void acquire(); - void wait(); - void wait(double timeout); - void notify(); - void release(); - -private: -#ifdef _WIN32 - CRITICAL_SECTION _lock; - HANDLE _event_signal; - -#else // _WIN32 - pthread_mutex_t _lock; - pthread_cond_t _cvar; -#endif // _WIN32 -}; - -#include "p3dConditionVar.I" - -#endif diff --git a/direct/src/plugin/p3dDownload.I b/direct/src/plugin/p3dDownload.I deleted file mode 100644 index c248948612..0000000000 --- a/direct/src/plugin/p3dDownload.I +++ /dev/null @@ -1,126 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dDownload.I - * @author drose - * @date 2009-06-11 - */ - -/** - * Returns the URL that we are querying. - */ -const std::string &P3DDownload:: -get_url() const { - return _url; -} - -/** - * Specifies the particular P3DInstance that is responsible for downloading - * this object. - */ -inline void P3DDownload:: -set_instance(P3DInstance *instance) { - _instance = instance; -} - -/** - * Returns the particular P3DInstance that is responsible for downloading this - * object. - */ -inline P3DInstance *P3DDownload:: -get_instance() const { - return _instance; -} - -/** - * Returns an indication of the progress through the download file, 0.0 to - * 1.0. Returns 1.0 if the size of the file is not known. - */ -inline double P3DDownload:: -get_download_progress() const { - if (_total_expected_data == 0) { - return 1.0; - } - - return (double)_total_data / (double)_total_expected_data; -} - -/** - * Returns true if the download progress is known, or false if it is unknown - * because the server hasn't told us the total size it will be feeding us. If - * this is false, get_download_progress() will generally always return 1.0; - * use get_total_bytes() to measure progress in this case. - */ -inline bool P3DDownload:: -is_download_progress_known() const { - return _progress_known; -} - -/** - * Returns the total number of bytes downloaded so far. - */ -inline size_t P3DDownload:: -get_total_data() const { - return _total_data; -} - -/** - * Sets the total number of bytes expected to be downloaded. This is used to - * compute the progress. Normally, this can be set from the download server, - * but there may be cases when the download server doesn't accurately report - * it. - */ -inline void P3DDownload:: -set_total_expected_data(size_t expected_data) { - _total_expected_data = expected_data; - _progress_known = true; -} - -/** - * Returns true if the download has finished, either successfully or - * otherwise, or false if it is still in progress. - */ -inline bool P3DDownload:: -get_download_finished() const { - return _status != P3D_RC_in_progress; -} - -/** - * Returns true if the download has finished successfully, or false if it is - * still in progress or if it has failed. - */ -inline bool P3DDownload:: -get_download_success() const { - return _status == P3D_RC_done; -} - -/** - * Returns true if the download has failed because the instance is about to be - * shut down, or false if it hasn't failed, or failed for some other reason. - */ -inline bool P3DDownload:: -get_download_terminated() const { - return _status == P3D_RC_shutdown; -} - -/** - * Called only by P3DInstance to set a unique ID for this particular download - * object. - */ -inline void P3DDownload:: -set_download_id(int download_id) { - _download_id = download_id; -} - -/** - * Returns the unique ID set by the P3DInstance. - */ -inline int P3DDownload:: -get_download_id() const { - return _download_id; -} diff --git a/direct/src/plugin/p3dDownload.cxx b/direct/src/plugin/p3dDownload.cxx deleted file mode 100644 index 3b6a6cca7a..0000000000 --- a/direct/src/plugin/p3dDownload.cxx +++ /dev/null @@ -1,192 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dDownload.cxx - * @author drose - * @date 2009-06-11 - */ - -#include "p3dDownload.h" - -/** - * - */ -P3DDownload:: -P3DDownload() { - _status = P3D_RC_in_progress; - _http_status_code = 0; - _total_data = 0; - _total_expected_data = 0; - _last_reported_time = 0; - _progress_known = false; - - _canceled = false; - _download_id = 0; - _instance = nullptr; -} - -/** - * - */ -P3DDownload:: -P3DDownload(const P3DDownload ©) : - _url(copy._url), - _total_expected_data(copy._total_expected_data), - _progress_known(copy._progress_known) -{ - _status = P3D_RC_in_progress; - _http_status_code = 0; - _total_data = 0; - _last_reported_time = 0; - - _canceled = false; - _download_id = 0; - _instance = nullptr; -} - -/** - * - */ -P3DDownload:: -~P3DDownload() { -} - -/** - * Supplies the source URL for the download. - */ -void P3DDownload:: -set_url(const std::string &url) { - _url = url; -} - -/** - * Cancels a running download. download_finished() will not be called, but - * the P3DDownload object itself will eventually be deleted by its owning - * P3DInstance. - */ -void P3DDownload:: -cancel() { - _canceled = true; - if (_status == P3D_RC_in_progress) { - _status = P3D_RC_generic_error; - } -} - -/** - * Resets the download to its initial state, for re-trying the same download. - */ -void P3DDownload:: -clear() { - _status = P3D_RC_in_progress; - _http_status_code = 0; - _total_data = 0; - _last_reported_time = 0; - - _canceled = false; - _download_id = 0; -} - -/** - * Called by P3DInstance as more data arrives from the host. Returns true on - * success, false if the download should be aborted. - */ -bool P3DDownload:: -feed_url_stream(P3D_result_code result_code, - int http_status_code, - size_t total_expected_data, - const unsigned char *this_data, - size_t this_data_size) { - if (_canceled) { - return false; - } - - _status = result_code; - _http_status_code = http_status_code; - - if (this_data_size != 0) { - if (!receive_data(this_data, this_data_size)) { - // Failure writing to disk or some such. - _status = P3D_RC_generic_error; - download_finished(false); - return false; - } - - _total_data += this_data_size; - } - - total_expected_data = std::max(total_expected_data, _total_data); - if (total_expected_data > _total_expected_data) { - // If the expected data grows during the download, we don't really know - // how much we're getting. - _progress_known = false; - _total_expected_data = total_expected_data; - } - if (_total_expected_data > 0 && - (double)_total_data / (double)_total_expected_data < 0.9) { - // But if we're not close to our target yet, let's say we do know (at - // least until we get there and the target moves again). - _progress_known = true; - } - - download_progress(); - - if (_status != P3D_RC_in_progress) { - // We're done. - if (get_download_success()) { - _progress_known = true; - } - download_finished(get_download_success()); - } - - return true; -} - - -/** - * Called as new data is downloaded. Returns true on success, false on - * failure. - */ -bool P3DDownload:: -receive_data(const unsigned char *this_data, size_t this_data_size) { - return false; -} - -/** - * Intended to be overloaded to generate an occasional callback as new data - * comes in. - */ -void P3DDownload:: -download_progress() { - time_t now = time(nullptr); - if (now - _last_reported_time > 10) { - _last_reported_time = now; - nout << "Downloading " << get_url() << ": "; - if (_progress_known) { - nout << int(get_download_progress() * 1000.0) / 10.0 << "%"; - } else { - nout << int((double)get_total_data() / 104857.6) / 10.0 << "M"; - } - nout << ", " << this << "\n"; - } -} - -/** - * Intended to be overloaded to generate a callback when the download - * finishes, either successfully or otherwise. The bool parameter is true if - * the download was successful. - */ -void P3DDownload:: -download_finished(bool success) { - nout << "Downloaded " << get_url() << ": "; - if (_progress_known) { - nout << int(get_download_progress() * 1000.0) / 10.0 << "%"; - } else { - nout << int((double)get_total_data() / 104857.6) / 10.0 << "M"; - } - nout << ", " << this << ", success = " << success << "\n"; -} diff --git a/direct/src/plugin/p3dDownload.h b/direct/src/plugin/p3dDownload.h deleted file mode 100644 index ad2cd872a5..0000000000 --- a/direct/src/plugin/p3dDownload.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dDownload.h - * @author drose - * @date 2009-06-11 - */ - -#ifndef P3DDOWNLOAD_H -#define P3DDOWNLOAD_H - -#include "p3d_plugin_common.h" -#include "p3dReferenceCount.h" -class P3DInstance; - -#include - -/** - * This represents a request to download a single file from a URL, with no - * particular destination. It is intended to be used as an abstract base - * class; to use it, subclass it and redefine the appropriate callback - * methods. - */ -class P3DDownload : public P3DReferenceCount { -public: - P3DDownload(); - P3DDownload(const P3DDownload ©); - virtual ~P3DDownload(); - - void set_url(const std::string &url); - inline const std::string &get_url() const; - - inline void set_instance(P3DInstance *instance); - inline P3DInstance *get_instance() const; - - inline double get_download_progress() const; - inline bool is_download_progress_known() const; - inline bool get_download_finished() const; - inline bool get_download_success() const; - inline bool get_download_terminated() const; - inline size_t get_total_data() const; - inline void set_total_expected_data(size_t expected_data); - - void cancel(); - void clear(); - -public: - // These are intended to be called only by P3DInstance. - inline void set_download_id(int download_id); - inline int get_download_id() const; - - bool feed_url_stream(P3D_result_code result_code, - int http_status_code, - size_t total_expected_data, - const unsigned char *this_data, - size_t this_data_size); - -protected: - virtual bool receive_data(const unsigned char *this_data, - size_t this_data_size); - virtual void download_progress(); - virtual void download_finished(bool success); - -protected: - P3D_result_code _status; - int _http_status_code; - - size_t _total_data; - size_t _total_expected_data; - time_t _last_reported_time; - bool _progress_known; - -private: - bool _canceled; - int _download_id; - std::string _url; - P3DInstance *_instance; -}; - -#include "p3dDownload.I" - -#endif diff --git a/direct/src/plugin/p3dFileDownload.I b/direct/src/plugin/p3dFileDownload.I deleted file mode 100644 index af4e2b1ec8..0000000000 --- a/direct/src/plugin/p3dFileDownload.I +++ /dev/null @@ -1,20 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dFileDownload.I - * @author drose - * @date 2009-06-11 - */ - -/** - * Returns the filename that we are downloading into. - */ -const std::string &P3DFileDownload:: -get_filename() const { - return _filename; -} diff --git a/direct/src/plugin/p3dFileDownload.cxx b/direct/src/plugin/p3dFileDownload.cxx deleted file mode 100644 index a978c3640e..0000000000 --- a/direct/src/plugin/p3dFileDownload.cxx +++ /dev/null @@ -1,107 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dFileDownload.cxx - * @author drose - * @date 2009-06-11 - */ - -#include "p3dFileDownload.h" -#include "p3dInstanceManager.h" -#include "mkdir_complete.h" -#include "wstring_encode.h" - -/** - * - */ -P3DFileDownload:: -P3DFileDownload() { -} - -/** - * - */ -P3DFileDownload:: -P3DFileDownload(const P3DFileDownload ©) : - P3DDownload(copy) -{ - // We don't copy the filename. You have to copy it yourself. -} - -/** - * Supplies the target local filename for the download. Returns true on - * success, false on failure. - */ -bool P3DFileDownload:: -set_filename(const std::string &filename) { - _filename = filename; - - return open_file(); -} - -/** - * Opens the local file for receiving the download. Returns true on success, - * false on failure. - */ -bool P3DFileDownload:: -open_file() { - if (!mkfile_complete(_filename, nout)) { - nout << "Failed to create " << _filename << "\n"; - return false; - } - - _file.clear(); -#ifdef _WIN32 - std::wstring filename_w; - if (string_to_wstring(filename_w, _filename)) { - _file.open(filename_w.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); - } -#else // _WIN32 - _file.open(_filename.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); -#endif // _WIN32 - if (!_file) { - nout << "Failed to open " << _filename << " in write mode\n"; - return false; - } - - return true; -} - -/** - * Closes the local file. - */ -void P3DFileDownload:: -close_file() { - _file.close(); -} - -/** - * Called as new data is downloaded. Returns true on success, false on - * failure. - */ -bool P3DFileDownload:: -receive_data(const unsigned char *this_data, size_t this_data_size) { - _file.write((const char *)this_data, this_data_size); - - if (!_file) { - return false; - } - - return true; -} - -/** - * Intended to be overloaded to generate a callback when the download - * finishes, either successfully or otherwise. The bool parameter is true if - * the download was successful. - */ -void P3DFileDownload:: -download_finished(bool success) { - P3DDownload::download_finished(success); - _file.close(); -} diff --git a/direct/src/plugin/p3dFileDownload.h b/direct/src/plugin/p3dFileDownload.h deleted file mode 100644 index 923f8ec0ec..0000000000 --- a/direct/src/plugin/p3dFileDownload.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dFileDownload.h - * @author drose - * @date 2009-06-11 - */ - -#ifndef P3DFILEDOWNLOAD_H -#define P3DFILEDOWNLOAD_H - -#include "p3d_plugin_common.h" -#include "p3dDownload.h" - -#include - -/** - * This is a specialization on P3DDownload that specifically writes a disk - * file. - */ -class P3DFileDownload : public P3DDownload { -public: - P3DFileDownload(); - P3DFileDownload(const P3DFileDownload ©); - - bool set_filename(const std::string &filename); - inline const std::string &get_filename() const; - -protected: - virtual bool open_file(); - void close_file(); - virtual bool receive_data(const unsigned char *this_data, - size_t this_data_size); - virtual void download_finished(bool success); - -protected: - ofstream _file; - -private: - std::string _filename; -}; - -#include "p3dFileDownload.I" - -#endif diff --git a/direct/src/plugin/p3dFileParams.I b/direct/src/plugin/p3dFileParams.I deleted file mode 100644 index 8565c47a90..0000000000 --- a/direct/src/plugin/p3dFileParams.I +++ /dev/null @@ -1,63 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dFileParams.I - * @author drose - * @date 2009-06-23 - */ - -/** - * Returns the filename that was passed to set_p3d_filename(). - */ -inline const std::string &P3DFileParams:: -get_p3d_filename() const { - return _p3d_filename; -} - -/** - * Returns the p3d file offset, the location in the file where the p3d data - * starts. - */ -inline int P3DFileParams:: -get_p3d_offset() const { - return _p3d_offset; -} - -/** - * Returns the string that was passed to set_p3d_url(). - */ -inline const std::string &P3DFileParams:: -get_p3d_url() const { - return _p3d_url; -} - -/** - * Returns the number of tokens in the params. - */ -inline int P3DFileParams:: -get_num_tokens() const { - return _tokens.size(); -} - -/** - * Returns the keyword of the nth token. - */ -inline const std::string &P3DFileParams:: -get_token_keyword(int n) const { - assert(n >= 0 && n < (int)_tokens.size()); - return _tokens[n]._keyword; -} - -/** - * Returns the value of the nth token. - */ -inline const std::string &P3DFileParams:: -get_token_value(int n) const { - assert(n >= 0 && n < (int)_tokens.size()); - return _tokens[n]._value; -} diff --git a/direct/src/plugin/p3dFileParams.cxx b/direct/src/plugin/p3dFileParams.cxx deleted file mode 100644 index a32ede4b95..0000000000 --- a/direct/src/plugin/p3dFileParams.cxx +++ /dev/null @@ -1,193 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dFileParams.cxx - * @author drose - * @date 2009-06-23 - */ - -#include "p3dFileParams.h" -#include - -using std::string; - -/** - * - */ -P3DFileParams:: -P3DFileParams() : _p3d_offset(0) { -} - -/** - * - */ -P3DFileParams:: -P3DFileParams(const P3DFileParams ©) : - _p3d_filename(copy._p3d_filename), - _p3d_offset(copy._p3d_offset), - _p3d_url(copy._p3d_url), - _tokens(copy._tokens), - _args(copy._args) -{ -} - -/** - * - */ -void P3DFileParams:: -operator = (const P3DFileParams &other) { - _p3d_filename = other._p3d_filename; - _p3d_offset = other._p3d_offset; - _p3d_url = other._p3d_url; - _tokens = other._tokens; - _args = other._args; -} - -/** - * Specifies the file that contains the instance data. - */ -void P3DFileParams:: -set_p3d_filename(const string &p3d_filename) { - _p3d_filename = p3d_filename; -} - -/** - * Specifies the location in the file where the p3d file data starts. - */ -void P3DFileParams:: -set_p3d_offset(const int &p3d_offset) { - _p3d_offset = p3d_offset; -} - -/** - * Specifies the original URL that hosted the p3d file, if any. This is for - * documentation purposes only; it is communicated to the child Panda3D - * process. - */ -void P3DFileParams:: -set_p3d_url(const string &p3d_url) { - _p3d_url = p3d_url; -} - -/** - * Replaces all the tokens associated with the instance. - */ -void P3DFileParams:: -set_tokens(const P3D_token tokens[], size_t num_tokens) { - _tokens.clear(); - - for (size_t i = 0; i < num_tokens; ++i) { - set_token(tokens[i]._keyword, tokens[i]._value); - } -} - -/** - * Sets an individual token value. - */ -void P3DFileParams:: -set_token(const char *keyword, const char *value) { - Token token; - if (keyword != nullptr) { - // Make the token lowercase, since HTML is case-insensitive but we're not. - for (const char *p = keyword; *p; ++p) { - token._keyword += tolower(*p); - } - } - if (value != nullptr) { - token._value = value; - } - _tokens.push_back(token); -} - -/** - * Specifies the command-line arguments associated with the instance. - */ -void P3DFileParams:: -set_args(int argc, const char *argv[]) { - _args.clear(); - - for (int i = 0; i < argc; ++i) { - const char *arg = argv[i]; - if (arg == nullptr) { - arg = ""; - } - _args.push_back(arg); - } -} - -/** - * Returns the value associated with the first appearance of the named token, - * or empty string if the token does not appear. - */ -string P3DFileParams:: -lookup_token(const string &keyword) const { - Tokens::const_iterator ti; - for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) { - if ((*ti)._keyword == keyword) { - return (*ti)._value; - } - } - - return string(); -} - -/** - * Returns the integer value associated with the first appearance of the named - * token, or zero if the token does not appear or is not an integer. - */ -int P3DFileParams:: -lookup_token_int(const string &keyword) const { - string value = lookup_token(keyword); - return atoi(value.c_str()); -} - -/** - * Returns true if the named token appears in the list, false otherwise. - */ -bool P3DFileParams:: -has_token(const string &keyword) const { - Tokens::const_iterator ti; - for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) { - if ((*ti)._keyword == keyword) { - return true; - } - } - - return false; -} - -/** - * Returns a newly-allocated XML structure that corresponds to the file - * parameter data within this instance. - */ -TiXmlElement *P3DFileParams:: -make_xml() { - TiXmlElement *xfparams = new TiXmlElement("fparams"); - - xfparams->SetAttribute("p3d_filename", _p3d_filename); - xfparams->SetAttribute("p3d_offset", _p3d_offset); - xfparams->SetAttribute("p3d_url", _p3d_url); - - Tokens::const_iterator ti; - for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) { - const Token &token = (*ti); - TiXmlElement *xtoken = new TiXmlElement("token"); - xtoken->SetAttribute("keyword", token._keyword); - xtoken->SetAttribute("value", token._value); - xfparams->LinkEndChild(xtoken); - } - - Args::const_iterator ai; - for (ai = _args.begin(); ai != _args.end(); ++ai) { - TiXmlElement *xarg = new TiXmlElement("arg"); - xarg->SetAttribute("value", (*ai)); - xfparams->LinkEndChild(xarg); - } - - return xfparams; -} diff --git a/direct/src/plugin/p3dFileParams.h b/direct/src/plugin/p3dFileParams.h deleted file mode 100644 index 53b2630680..0000000000 --- a/direct/src/plugin/p3dFileParams.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dFileParams.h - * @author drose - * @date 2009-06-23 - */ - -#ifndef P3DFILEPARAMS_H -#define P3DFILEPARAMS_H - -#include "p3d_plugin_common.h" -#include "get_tinyxml.h" -#include - -/** - * Encapsulates the file parameters: the p3d_filename, and extra tokens. - */ -class P3DFileParams { -public: - P3DFileParams(); - P3DFileParams(const P3DFileParams ©); - void operator = (const P3DFileParams &other); - - void set_p3d_filename(const std::string &p3d_filename); - void set_p3d_offset(const int &p3d_offset); - void set_p3d_url(const std::string &p3d_url); - void set_tokens(const P3D_token tokens[], size_t num_tokens); - void set_token(const char *keyword, const char *value); - void set_args(int argc, const char *argv[]); - - inline const std::string &get_p3d_filename() const; - inline int get_p3d_offset() const; - inline const std::string &get_p3d_url() const; - std::string lookup_token(const std::string &keyword) const; - int lookup_token_int(const std::string &keyword) const; - bool has_token(const std::string &keyword) const; - - inline int get_num_tokens() const; - inline const std::string &get_token_keyword(int n) const; - inline const std::string &get_token_value(int n) const; - - TiXmlElement *make_xml(); - -private: - class Token { - public: - std::string _keyword; - std::string _value; - }; - typedef std::vector Tokens; - typedef std::vector Args; - - std::string _p3d_filename; - int _p3d_offset; - std::string _p3d_url; - Tokens _tokens; - Args _args; -}; - -#include "p3dFileParams.I" - -#endif diff --git a/direct/src/plugin/p3dFloatObject.cxx b/direct/src/plugin/p3dFloatObject.cxx deleted file mode 100644 index 3262d45a54..0000000000 --- a/direct/src/plugin/p3dFloatObject.cxx +++ /dev/null @@ -1,74 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dFloatObject.cxx - * @author drose - * @date 2009-06-30 - */ - -#include "p3dFloatObject.h" - -/** - * - */ -P3DFloatObject:: -P3DFloatObject(double value) : _value(value) { -} - -/** - * - */ -P3DFloatObject:: -P3DFloatObject(const P3DFloatObject ©) : - P3DObject(copy), - _value(copy._value) -{ -} - -/** - * Returns the fundamental type of this kind of object. - */ -P3D_object_type P3DFloatObject:: -get_type() { - return P3D_OT_float; -} - -/** - * Returns the object value coerced to a boolean, if possible. - */ -bool P3DFloatObject:: -get_bool() { - return (_value != 0.0); -} - -/** - * Returns the object value coerced to an integer, if possible. - */ -int P3DFloatObject:: -get_int() { - return (int)_value; -} - -/** - * Returns the object value coerced to a floating-point value, if possible. - */ -double P3DFloatObject:: -get_float() { - return _value; -} - -/** - * Fills the indicated C++ string object with the value of this object coerced - * to a string. - */ -void P3DFloatObject:: -make_string(std::string &value) { - std::ostringstream strm; - strm << _value; - value = strm.str(); -} diff --git a/direct/src/plugin/p3dFloatObject.h b/direct/src/plugin/p3dFloatObject.h deleted file mode 100644 index 13f7ba8358..0000000000 --- a/direct/src/plugin/p3dFloatObject.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dFloatObject.h - * @author drose - * @date 2009-06-30 - */ - -#ifndef P3DFLOATOBJECT_H -#define P3DFLOATOBJECT_H - -#include "p3d_plugin_common.h" -#include "p3dObject.h" - -/** - * An object type that contains a floating-point value. - */ -class P3DFloatObject : public P3DObject { -public: - P3DFloatObject(double value); - P3DFloatObject(const P3DFloatObject ©); - -public: - virtual P3D_object_type get_type(); - virtual bool get_bool(); - virtual int get_int(); - virtual double get_float(); - virtual void make_string(std::string &value); - -private: - double _value; -}; - -#endif diff --git a/direct/src/plugin/p3dHost.I b/direct/src/plugin/p3dHost.I deleted file mode 100644 index 9fb3672205..0000000000 --- a/direct/src/plugin/p3dHost.I +++ /dev/null @@ -1,106 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dHost.I - * @author drose - * @date 2009-08-21 - */ - -/** - * Returns true if the host_dir has already been set, false if not. If this - * returns true it is safe to call get_host_dir(). - */ -inline bool P3DHost:: -has_host_dir() const { - return (!_host_dir.empty()); -} - -/** - * Returns the local directory into which files downloaded from this host will - * be installed. It may not be safe to call this before the host has fully - * bootstrapped; if there is some danger of calling this early in the - * initialization process, you should check has_host_dir() first. - */ -inline const std::string &P3DHost:: -get_host_dir() const { - assert(has_host_dir()); - return _host_dir; -} - -/** - * Returns the root URL of this particular host, as passed from the package - * file. This is a unique string that identifies each host. - */ -inline const std::string &P3DHost:: -get_host_url() const { - return _host_url; -} - -/** - * Returns the root URL of this host, for constructing the URL to download - * contents.xml only. This is the same as get_host_url(), except it is - * guaranteed to end in a slash character. - * - * Also see get_download_url_prefix(). - */ -inline const std::string &P3DHost:: -get_host_url_prefix() const { - return _host_url_prefix; -} - -/** - * Returns the root URL of this host, for downloading everything other than - * the contents.xml file. This is often the same as get_host_url_prefix(), - * but it may be different in the case of an https server for contents.xml. - */ -inline const std::string &P3DHost:: -get_download_url_prefix() const { - return _download_url_prefix; -} - -/** - * Returns the descriptive name provided for this host, if any. Returns the - * url if no descriptive name is provided. This will be available after - * read_contents_file() has been called. - */ -inline const std::string &P3DHost:: -get_descriptive_name() const { - return _descriptive_name; -} - -/** - * Returns true if a contents.xml file has been successfully read for this - * host, false otherwise. - */ -inline bool P3DHost:: -has_contents_file() const { - return (_xcontents != nullptr); -} - -/** - * Returns a number that increments whenever a new version of the contents.xml - * file has been read. This number is local to the session only; it has - * nothing to do with the "seq" value written into the contents.xml file - * itself. - * - * This can be used by packages to determine whether they need to redownload - * from scratch. - */ -inline int P3DHost:: -get_contents_iseq() const { - return _contents_iseq; -} - -/** - * Returns true if the indicated pathname has the same md5 hash as the - * contents.xml file (as provided by the server), false otherwise. - */ -inline bool P3DHost:: -check_contents_hash(const std::string &pathname) const { - return _contents_spec.check_hash(pathname); -} diff --git a/direct/src/plugin/p3dHost.cxx b/direct/src/plugin/p3dHost.cxx deleted file mode 100644 index db189e14c4..0000000000 --- a/direct/src/plugin/p3dHost.cxx +++ /dev/null @@ -1,1056 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dHost.cxx - * @author drose - * @date 2009-08-21 - */ - -#include "p3dHost.h" -#include "p3dInstanceManager.h" -#include "p3dPackage.h" -#include "mkdir_complete.h" -#include "wstring_encode.h" -#include "xml_helpers.h" -#include - -#include - -#ifndef _WIN32 -#include -#endif - -using std::ios; -using std::ostringstream; -using std::string; -using std::wstring; - -/** - * Use P3DInstanceManager::get_host() to construct a new P3DHost. - */ -P3DHost:: -P3DHost(const string &host_url, const string &host_dir) : - _host_url(host_url), - _host_dir(host_dir) -{ - // Ensure that the download URL ends with a slash. - _host_url_prefix = _host_url; - if (!_host_url_prefix.empty() && _host_url_prefix[_host_url_prefix.size() - 1] != '/') { - _host_url_prefix += "/"; - } - _download_url_prefix = _host_url_prefix; - - _descriptive_name = _host_url; - - _xcontents = nullptr; - _contents_expiration = 0; - _contents_iseq = 0; -} - -/** - * - */ -P3DHost:: -~P3DHost() { - if (_xcontents != nullptr) { - delete _xcontents; - } - - Packages::iterator mi; - for (mi = _packages.begin(); mi != _packages.end(); ++mi) { - PackageMap &package_map = (*mi).second; - PackageMap::iterator pi; - for (pi = package_map.begin(); pi != package_map.end(); ++pi) { - PlatformPackages &ppackages = (*pi).second; - PlatformPackages::iterator ppi; - for (ppi = ppackages.begin(); ppi != ppackages.end(); ++ppi) { - delete (*ppi); - } - } - } - _packages.clear(); - - FailedPackages::iterator pi; - for (pi = _failed_packages.begin(); pi != _failed_packages.end(); ++pi) { - delete (*pi); - } - _failed_packages.clear(); -} - -/** - * Returns the pre-defined alternate host with the indicated token, if one is - * defined for this token, or the original host if there is no alternate host - * defined for this token. - * - * This is intended to implement test versions and the like, for instance in - * which a particular p3d file may reference a package on one particular host, - * but there is an alternate version to be tested on a different host. The - * HTML code that embeds the p3d file can choose to set the alt_host token to - * redirect the p3d file to the alternate host. - * - * The actual URL for the alternate host is embedded within the host's - * contents.xml as a security measure, to prevent people from tricking a p3d - * file into running untrusted code by redirecting it to an arbitrary URL. - */ -P3DHost *P3DHost:: -get_alt_host(const string &alt_host) { - assert(_xcontents != nullptr); - - AltHosts::iterator hi; - hi = _alt_hosts.find(alt_host); - if (hi != _alt_hosts.end() && (*hi).second != _host_url) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - return inst_mgr->get_host((*hi).second); - } - return this; -} - -/** - * Returns true if a contents.xml file has been successfully read for this - * host and is still current, false otherwise. - */ -bool P3DHost:: -has_current_contents_file(P3DInstanceManager *inst_mgr) const { - if (inst_mgr->get_verify_contents() == P3D_VC_never - || inst_mgr->get_verify_contents() == P3D_VC_none) { - // If we're not asking to verify contents, then contents.xml files never - // expire. - return has_contents_file(); - } - - time_t now = time(nullptr); - return now < _contents_expiration && (_xcontents != nullptr); -} - -/** - * Reads the contents.xml file in the standard filename, if possible. - * - * Returns true on success, false on failure. - */ -bool P3DHost:: -read_contents_file() { - if (_host_dir.empty()) { - // If we haven't got a host_dir yet, we can't read the contents. - return false; - } - - string standard_filename = _host_dir + "/contents.xml"; - return read_contents_file(standard_filename, false); -} - -/** - * Reads the contents.xml file in the indicated filename. On success, writes - * the contents.xml file into the standard location (if it's not there - * already). - * - * Returns true on success, false on failure. - */ -bool P3DHost:: -read_contents_file(const string &contents_filename, bool fresh_download) { - TiXmlDocument doc(contents_filename.c_str()); - if (!doc.LoadFile()) { - return false; - } - - TiXmlElement *xcontents = doc.FirstChildElement("contents"); - if (xcontents == nullptr) { - return false; - } - - if (_xcontents != nullptr) { - delete _xcontents; - } - _xcontents = (TiXmlElement *)xcontents->Clone(); - ++_contents_iseq; - _contents_spec = FileSpec(); - - int max_age = P3D_CONTENTS_DEFAULT_MAX_AGE; - xcontents->Attribute("max_age", &max_age); - - // Get the latest possible expiration time, based on the max_age indication. - // Any expiration time later than this is in error. - time_t now = time(nullptr); - _contents_expiration = now + (time_t)max_age; - - if (fresh_download) { - _contents_spec.read_hash(contents_filename); - - // Update the XML with the new download information. - TiXmlElement *xorig = xcontents->FirstChildElement("orig"); - while (xorig != nullptr) { - xcontents->RemoveChild(xorig); - xorig = xcontents->FirstChildElement("orig"); - } - - xorig = new TiXmlElement("orig"); - xcontents->LinkEndChild(xorig); - _contents_spec.store_xml(xorig); - - xorig->SetAttribute("expiration", (int)_contents_expiration); - - } else { - // Read the download hash and expiration time from the XML. - int expiration = 0; - TiXmlElement *xorig = xcontents->FirstChildElement("orig"); - if (xorig != nullptr) { - _contents_spec.load_xml(xorig); - xorig->Attribute("expiration", &expiration); - } - if (!_contents_spec.has_hash()) { - _contents_spec.read_hash(contents_filename); - } - - _contents_expiration = std::min(_contents_expiration, (time_t)expiration); - } - - nout << "read contents.xml, max_age = " << max_age - << ", expires in " << std::max(_contents_expiration, now) - now - << " s\n"; - - TiXmlElement *xhost = _xcontents->FirstChildElement("host"); - if (xhost != nullptr) { - const char *url = xhost->Attribute("url"); - if (url != nullptr && _host_url == string(url)) { - // We're the primary host. This is the normal case. - read_xhost(xhost); - - // Build up the list of alternate hosts. - TiXmlElement *xalthost = xhost->FirstChildElement("alt_host"); - while (xalthost != nullptr) { - const char *keyword = xalthost->Attribute("keyword"); - const char *url = xalthost->Attribute("url"); - if (keyword != nullptr && url != nullptr) { - _alt_hosts[keyword] = url; - } - xalthost = xalthost->NextSiblingElement("alt_host"); - } - - } else { - // We're not the primary host; perhaps we're an alternate host. - TiXmlElement *xalthost = xhost->FirstChildElement("alt_host"); - while (xalthost != nullptr) { - const char *url = xalthost->Attribute("url"); - if (url != nullptr && _host_url == string(url)) { - // Yep, we're this alternate host. - read_xhost(xalthost); - break; - } - xalthost = xalthost->NextSiblingElement("alt_host"); - } - } - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - if (_host_dir.empty()) { - determine_host_dir(""); - } - assert(!_host_dir.empty()); - - string standard_filename = _host_dir + "/contents.xml"; - - if (inst_mgr->get_verify_contents() != P3D_VC_never) { - mkdir_complete(_host_dir, nout); - - if (fresh_download) { - if (!save_xml_file(&doc, standard_filename)) { - nout << "Couldn't save to " << standard_filename << "\n"; - } - } else { - if (standardize_filename(standard_filename) != - standardize_filename(contents_filename)) { - if (!copy_file(contents_filename, standard_filename)) { - nout << "Couldn't copy to " << standard_filename << "\n"; - } - } - } - - if (_host_url == inst_mgr->get_host_url()) { - // If this is also the plugin host, then copy the contents.xml file into - // the root Panda directory as well, for the next plugin iteration. - string top_filename = inst_mgr->get_root_dir() + "/contents.xml"; - if (standardize_filename(top_filename) != - standardize_filename(standard_filename)) { - if (!copy_file(standard_filename, top_filename)) { - nout << "Couldn't copy to " << top_filename << "\n"; - } - } - } - } - - return true; -} - -/** - * Reads the host data from the (or ) entry in the - * contents.xml file, or from a p3d_info.xml file. - */ -void P3DHost:: -read_xhost(TiXmlElement *xhost) { - const char *descriptive_name = xhost->Attribute("descriptive_name"); - if (descriptive_name != nullptr && _descriptive_name.empty()) { - _descriptive_name = descriptive_name; - } - - const char *host_dir_basename = xhost->Attribute("host_dir"); - if (host_dir_basename == nullptr) { - host_dir_basename = ""; - } - if (_host_dir.empty()) { - determine_host_dir(host_dir_basename); - } - - // Get the "download" URL, which is the source from which we download - // everything other than the contents.xml file. - const char *download_url = xhost->Attribute("download_url"); - if (download_url != nullptr) { - _download_url_prefix = download_url; - } - if (!_download_url_prefix.empty()) { - if (_download_url_prefix[_download_url_prefix.size() - 1] != '/') { - _download_url_prefix += "/"; - } - } else { - _download_url_prefix = _host_url_prefix; - } - - TiXmlElement *xmirror = xhost->FirstChildElement("mirror"); - while (xmirror != nullptr) { - const char *url = xmirror->Attribute("url"); - if (url != nullptr) { - add_mirror(url); - } - xmirror = xmirror->NextSiblingElement("mirror"); - } -} - -/** - * Returns a (possibly shared) pointer to the indicated package. - * - * The package_seq value should be the expected minimum package_seq value for - * the indicated package. If the given seq value is higher than the - * package_seq value in the contents.xml file cached for the host, it is a - * sign that the contents.xml file is out of date and needs to be - * redownloaded. - */ -P3DPackage *P3DHost:: -get_package(const string &package_name, const string &package_version, - const string &package_platform, const string &package_seq, - const string &alt_host) { - if (!alt_host.empty()) { - if (_xcontents != nullptr) { - // If we're asking for an alt host and we've already read our - // contents.xml file, then we already know all of our hosts, and we can - // start the package off with the correct host immediately. - P3DHost *new_host = get_alt_host(alt_host); - return new_host->get_package(package_name, package_version, - package_platform, package_seq); - } - - // If we haven't read contents.xml yet, we need to create the package - // first, then let it be responsible for downloading our contents.xml, and - // it can migrate to its alt_host after that. - } - - string key = package_name + "_" + package_version; - PlatformPackages &ppackages = _packages[alt_host][key]; - PlatformPackages::iterator ppi; - P3DPackage *package = nullptr; - - // First, look for an exact match of the platform. - for (ppi = ppackages.begin(); ppi != ppackages.end(); ++ppi) { - if ((*ppi)->get_package_platform() == package_platform) { - package = *ppi; - break; - } - } - - // If an exact match isn't found, look for a generic platform. - if (package == nullptr) { - for (ppi = ppackages.begin(); ppi != ppackages.end(); ++ppi) { - if ((*ppi)->get_package_platform().empty()) { - package = *ppi; - break; - } - } - } - - if (package != nullptr) { - if (package->get_failed()) { - // If the package has previously failed, move it aside and try again - // (maybe it just failed because the user interrupted it). - nout << "Package " << key << " has previously failed; trying again.\n"; - _failed_packages.push_back(package); - ppackages.erase(ppi); - package = nullptr; - } - } - - if (package == nullptr) { - package = - new P3DPackage(this, package_name, package_version, package_platform, alt_host); - ppackages.push_back(package); - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (!package_seq.empty() && has_current_contents_file(inst_mgr)) { - // If we were given a specific package_seq file to verify, and we believe - // we have a valid contents.xml file, then check the seq value in the - // contents. - FileSpec desc_file; - string seq; - bool solo; - if (get_package_desc_file(desc_file, seq, solo, - package_name, package_version, package_platform)) { - nout << package_name << ": asked for seq " << package_seq - << ", we have seq " << seq << "\n"; - if (compare_seq(package_seq, seq) > 0) { - // The requested seq value is higher than the one we have on file; our - // contents.xml file must be out of date after all. - nout << "expiring contents.xml for " << get_host_url() << "\n"; - _contents_expiration = 0; - } - } - } - - return package; -} - -/** - * Chooses the most appropriate platform for the indicated package based on - * what this hardware supports and what is actually available. Also fills in - * per_platform, which is a boolean value indicating whether the directory - * structure contains the platform directory or not. - */ -bool P3DHost:: -choose_suitable_platform(string &selected_platform, - bool &per_platform, - const string &package_name, - const string &package_version, - const string &package_platform) { - if (_xcontents == nullptr) { - return false; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - TiXmlElement *xpackage; - - // If the platform is initially unspecified, we allow searching for any - // available supported platform. - if (package_platform == "") { - int num_supported_platforms = inst_mgr->get_num_supported_platforms(); - for (int pi = 0; pi < num_supported_platforms; ++pi) { - string supported_platform = inst_mgr->get_supported_platform(pi); - xpackage = _xcontents->FirstChildElement("package"); - while (xpackage != nullptr) { - const char *name = xpackage->Attribute("name"); - const char *platform = xpackage->Attribute("platform"); - const char *version = xpackage->Attribute("version"); - if (platform == nullptr) { - platform = ""; - } - if (version == nullptr) { - version = ""; - } - if (name != nullptr && - package_name == name && - supported_platform == platform && - package_version == version) { - // Here's the matching package definition. - selected_platform = platform; - per_platform = parse_bool_attrib(xpackage, "per_platform", false); - return true; - } - - xpackage = xpackage->NextSiblingElement("package"); - } - } - } - - // Now, we look for an exact match for the expected platform. - xpackage = _xcontents->FirstChildElement("package"); - while (xpackage != nullptr) { - const char *name = xpackage->Attribute("name"); - const char *platform = xpackage->Attribute("platform"); - const char *version = xpackage->Attribute("version"); - if (platform == nullptr) { - platform = ""; - } - if (version == nullptr) { - version = ""; - } - if (name != nullptr && - package_name == name && - package_platform == platform && - package_version == version) { - // Here's the matching package definition. - selected_platform = platform; - per_platform = parse_bool_attrib(xpackage, "per_platform", false); - return true; - } - - xpackage = xpackage->NextSiblingElement("package"); - } - - // Look one more time, this time looking for a non-platform-specific - // version. - xpackage = _xcontents->FirstChildElement("package"); - while (xpackage != nullptr) { - const char *name = xpackage->Attribute("name"); - const char *platform = xpackage->Attribute("platform"); - const char *version = xpackage->Attribute("version"); - if (platform == nullptr) { - platform = ""; - } - if (version == nullptr) { - version = ""; - } - if (name != nullptr && - package_name == name && - *platform == '\0' && - package_version == version) { - selected_platform = platform; - per_platform = parse_bool_attrib(xpackage, "per_platform", false); - return true; - } - - xpackage = xpackage->NextSiblingElement("package"); - } - - // Couldn't find a suitable platform. - return false; -} - -/** - * Fills the indicated FileSpec with the hash information for the package's - * desc file, and also determines the package's platform. Returns true if - * successful, false if the package is unknown. This requires - * has_contents_file() to return true in order to be successful. - */ -bool P3DHost:: -get_package_desc_file(FileSpec &desc_file, // out - string &package_seq, // out - bool &package_solo, // out - const string &package_name, // in - const string &package_version, // in - const string &package_platform) { // in - if (_xcontents == nullptr) { - return false; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - // Scan the contents data for the indicated package. We expect to match the - // platform precisely, because we previously called - // choose_suitable_platform(). - TiXmlElement *xpackage = _xcontents->FirstChildElement("package"); - while (xpackage != nullptr) { - const char *name = xpackage->Attribute("name"); - const char *platform = xpackage->Attribute("platform"); - const char *version = xpackage->Attribute("version"); - const char *seq = xpackage->Attribute("seq"); - const char *solo = xpackage->Attribute("solo"); - if (platform == nullptr) { - platform = ""; - } - if (version == nullptr) { - version = ""; - } - if (seq == nullptr) { - seq = ""; - } - if (name != nullptr && platform != nullptr && - package_name == name && - package_platform == platform && - package_version == version) { - // Here's the matching package definition. - desc_file.load_xml(xpackage); - package_seq = seq; - package_solo = false; - if (solo != nullptr) { - package_solo = (atoi(solo) != 0); - } - return true; - } - - xpackage = xpackage->NextSiblingElement("package"); - } - - // Couldn't find the named package. - return false; -} - -/** - * Removes the indicated package from the cache of packages known by this - * host. This is invoked from the Python side by AppRunner.deletePackages(), - * so that we remove the package before deleting its files. - */ -void P3DHost:: -forget_package(P3DPackage *package, const string &alt_host) { - string key = package->get_package_name() + "_" + package->get_package_version(); - nout << "Forgetting package " << key << "\n"; - - PlatformPackages &ppackages = _packages[alt_host][key]; - - PlatformPackages::iterator ppi = find(ppackages.begin(), ppackages.end(), package); - if (ppi != ppackages.end()) { - // Hmm, this is a memory leak. But we allow it to remain, since it's an - // unusual circumstance (uninstalling), and it's safer to leak than to - // risk a floating pointer. - ppackages.erase(ppi); - } -} - -/** - * This is called by P3DPackage when it migrates from this host to its final - * alt_host, after downloading the contents.xml file for this file and - * learning the true URL for its target alt_host. - */ -void P3DHost:: -migrate_package_host(P3DPackage *package, const string &alt_host, P3DHost *new_host) { - assert(new_host != this); - assert(new_host == get_alt_host(alt_host)); - - string key = package->get_package_name() + "_" + package->get_package_version(); - - PlatformPackages &ppackages = _packages[alt_host][key]; - - PlatformPackages::iterator ppi = find(ppackages.begin(), ppackages.end(), package); - - assert(ppi != ppackages.end()); - ppackages.erase(ppi); - - PlatformPackages &new_ppackages = new_host->_packages[""][key]; - new_ppackages.push_back(package); -} - -/** - * Selects num_mirrors elements, chosen at random, from the _mirrors list. - * Adds the selected mirrors to result. If there are fewer than num_mirrors - * elements in the list, adds only as many mirrors as we can get. - */ -void P3DHost:: -choose_random_mirrors(std::vector &result, int num_mirrors) { - std::vector selected; - - size_t num_to_select = std::min(_mirrors.size(), (size_t)num_mirrors); - while (num_to_select > 0) { - size_t i = (size_t)(((double)rand() / (double)RAND_MAX) * _mirrors.size()); - while (find(selected.begin(), selected.end(), i) != selected.end()) { - // Already found this i, find a new one. - i = (size_t)(((double)rand() / (double)RAND_MAX) * _mirrors.size()); - } - selected.push_back(i); - result.push_back(_mirrors[i]); - --num_to_select; - } -} - -/** - * Adds a new URL to serve as a mirror for this host. The mirrors will be - * consulted first, before consulting the host directly. - */ -void P3DHost:: -add_mirror(string mirror_url) { - // Ensure the URL ends in a slash. - if (!mirror_url.empty() && mirror_url[mirror_url.size() - 1] != '/') { - mirror_url += '/'; - } - - // Add it to the _mirrors list, but only if it's not already there. - if (find(_mirrors.begin(), _mirrors.end(), mirror_url) == _mirrors.end()) { - _mirrors.push_back(mirror_url); - } -} - -/** - * Removes the host directory and all its contents from the user's hard disk. - */ -void P3DHost:: -uninstall() { - if (_host_dir.empty()) { - nout << "Cannot uninstall " << _descriptive_name << ": host directory not yet known.\n"; - return; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - // Check if we're even allowed to. - if (inst_mgr->get_verify_contents() == P3D_VC_never) { - nout << "Not allowed to uninstall " << _descriptive_name << ".\n"; - return; - } - - // First, explicitly uninstall each of our packages. - Packages::iterator mi; - for (mi = _packages.begin(); mi != _packages.end(); ++mi) { - PackageMap &package_map = (*mi).second; - PackageMap::iterator pi; - for (pi = package_map.begin(); pi != package_map.end(); ++pi) { - PlatformPackages &ppackages = (*pi).second; - PlatformPackages::iterator ppi; - for (ppi = ppackages.begin(); ppi != ppackages.end(); ++ppi) { - P3DPackage *package = (*ppi); - package->uninstall(); - } - } - } - - // Then, uninstall the host itself. - nout << "Uninstalling " << _descriptive_name << " from " << _host_dir << "\n"; - inst_mgr->delete_directory_recursively(_host_dir); - inst_mgr->forget_host(this); -} - -/** - * Hashes the host_url into a (mostly) unique directory string, which will be - * the root of the host's install tree. Stores the result in _host_dir. - * - * This code is duplicated in Python, in HostInfo.determineHostDir(). - */ -void P3DHost:: -determine_host_dir(const string &host_dir_basename) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - _host_dir = inst_mgr->get_root_dir(); - _host_dir += "/hosts"; - - if (!host_dir_basename.empty()) { - // If the contents.xml specified a host_dir parameter, use it. - inst_mgr->append_safe_dir(_host_dir, host_dir_basename); - return; - } - - // If we didn't get a host_dir parameter, we have to make one up. - _host_dir += "/"; - string hostname; - - // Look for a server name in the URL. Including this string in the - // directory name makes it friendlier for people browsing the directory. - - // We can't use URLSpec here, because we don't link with Panda3D. We have to - // do it by hand. - size_t p = _host_url.find("://"); - if (p != string::npos) { - size_t start = p + 3; - size_t end = _host_url.find("/", start); - // Now start .. end is something like "username@host:port". - - size_t at = _host_url.find("@", start); - if (at < end) { - start = at + 1; - } - - size_t colon = _host_url.find(":", start); - if (colon < end) { - end = colon; - } - - // Now start .. end is just the hostname. - hostname = _host_url.substr(start, end - start); - } - -/* - * Now build a hash string of the whole URL. We'll use MD5 to get a pretty - * good hash, with a minimum chance of collision. Even if there is a hash - * collision, though, it's not the end of the world; it just means that both - * hosts will dump their packages into the same directory, and they'll fight - * over the toplevel contents.xml file. Assuming they use different version - * numbers (which should be safe since they have the same hostname), there - * will be minimal redownloading. - */ - - static const size_t hash_size = 16; - unsigned char md[hash_size]; - - size_t keep_hash = hash_size; - - if (!hostname.empty()) { - _host_dir += hostname; - _host_dir += "_"; - - // If we successfully got a hostname, we don't really need the full hash. - // We'll keep half of it. - keep_hash = keep_hash / 2; - } - - MD5_CTX ctx; - MD5_Init(&ctx); - MD5_Update(&ctx, _host_url.data(), _host_url.size()); - MD5_Final(md, &ctx); - - for (size_t i = 0; i < keep_hash; ++i) { - int high = (md[i] >> 4) & 0xf; - int low = md[i] & 0xf; - _host_dir += P3DInstanceManager::encode_hexdigit(high); - _host_dir += P3DInstanceManager::encode_hexdigit(low); - } -} - - -/** - * Attempts to change the filename into some standard form for comparison with - * other filenames. On a case-insensitive filesystem, this converts the - * filename to lowercase. On Windows, it further replaces forward slashes - * with backslashes. - */ -string P3DHost:: -standardize_filename(const string &filename) { -#if defined(_WIN32) || defined(__APPLE__) - string new_filename; - for (string::const_iterator si = filename.begin(); - si != filename.end(); - ++si) { - char ch = *si; -#ifdef _WIN32 - if (ch == '/') { - ch = '\\'; - } -#endif // _WIN32 - new_filename += tolower(ch); - } - return new_filename; -#else // _WIN32 || __APPLE__ - return filename; -#endif // _WIN32 || __APPLE__ -} - -/** - * Copies the data in the file named by from_filename into the file named by - * to_filename. - */ -bool P3DHost:: -copy_file(const string &from_filename, const string &to_filename) { -#ifdef _WIN32 - ifstream in; - wstring from_filename_w; - if (string_to_wstring(from_filename_w, from_filename)) { - in.open(from_filename_w.c_str(), ios::in | ios::binary); - } - - // Copy to a temporary file first, in case (a) the filenames actually refer - // to the same file, or (b) in case we have different processes writing to - // the same file, and (c) to prevent partially overwriting the file should - // something go wrong. - ostringstream strm; - strm << to_filename << ".t"; - strm << GetCurrentProcessId() << "_" << GetCurrentThreadId(); - string temp_filename = strm.str(); - ofstream out; - wstring temp_filename_w; - if (string_to_wstring(temp_filename_w, temp_filename)) { - out.open(temp_filename_w.c_str(), ios::out | ios::binary); - } - - static const size_t buffer_size = 4096; - char buffer[buffer_size]; - - in.read(buffer, buffer_size); - std::streamsize count = in.gcount(); - while (count != 0) { - out.write(buffer, count); - if (out.fail()) { - unlink(temp_filename.c_str()); - return false; - } - in.read(buffer, buffer_size); - count = in.gcount(); - } - out.close(); - - wstring to_filename_w; - string_to_wstring(to_filename_w, to_filename); - - if (!in.eof()) { - _wunlink(temp_filename_w.c_str()); - return false; - } - - if (_wrename(temp_filename_w.c_str(), to_filename_w.c_str()) == 0) { - return true; - } - - _wunlink(to_filename_w.c_str()); - if (_wrename(temp_filename_w.c_str(), to_filename_w.c_str()) == 0) { - return true; - } - - _wunlink(temp_filename_w.c_str()); - return false; - -#else // _WIN32 - - ifstream in; - in.open(from_filename.c_str(), ios::in | ios::binary); - - // Copy to a temporary file first, in case (a) the filenames actually refer - // to the same file, or (b) in case we have different processes writing to - // the same file, and (c) to prevent partially overwriting the file should - // something go wrong. - ostringstream strm; - strm << to_filename << ".t"; - strm << getpid(); - - string temp_filename = strm.str(); - ofstream out; - out.open(temp_filename.c_str(), ios::out | ios::binary); - - static const size_t buffer_size = 4096; - char buffer[buffer_size]; - - in.read(buffer, buffer_size); - size_t count = in.gcount(); - while (count != 0) { - out.write(buffer, count); - if (out.fail()) { - unlink(temp_filename.c_str()); - return false; - } - in.read(buffer, buffer_size); - count = in.gcount(); - } - out.close(); - - if (!in.eof()) { - unlink(temp_filename.c_str()); - return false; - } - - if (rename(temp_filename.c_str(), to_filename.c_str()) == 0) { - return true; - } - - unlink(to_filename.c_str()); - if (rename(temp_filename.c_str(), to_filename.c_str()) == 0) { - return true; - } - - unlink(temp_filename.c_str()); - return false; -#endif // _WIN32 -} - -/** - * Stores the XML document to the file named by to_filename, safely. - */ -bool P3DHost:: -save_xml_file(TiXmlDocument *doc, const string &to_filename) { - // Save to a temporary file first, in case (a) we have different processes - // writing to the same file, and (b) to prevent partially overwriting the - // file should something go wrong. - -#ifdef _WIN32 - ostringstream strm; - strm << to_filename << ".t"; - strm << GetCurrentProcessId() << "_" << GetCurrentThreadId(); - string temp_filename = strm.str(); - - wstring temp_filename_w; - string_to_wstring(temp_filename_w, temp_filename); - wstring to_filename_w; - string_to_wstring(to_filename_w, to_filename); - - if (!doc->SaveFile(temp_filename.c_str())) { - _wunlink(temp_filename_w.c_str()); - return false; - } - - if (_wrename(temp_filename_w.c_str(), to_filename_w.c_str()) == 0) { - return true; - } - - _wunlink(to_filename_w.c_str()); - if (_wrename(temp_filename_w.c_str(), to_filename_w.c_str()) == 0) { - return true; - } - - _wunlink(temp_filename_w.c_str()); - return false; - -#else // _WIN32 - ostringstream strm; - strm << to_filename << ".t"; - strm << getpid(); - string temp_filename = strm.str(); - - if (!doc->SaveFile(temp_filename.c_str())) { - unlink(temp_filename.c_str()); - return false; - } - - if (rename(temp_filename.c_str(), to_filename.c_str()) == 0) { - return true; - } - - unlink(to_filename.c_str()); - if (rename(temp_filename.c_str(), to_filename.c_str()) == 0) { - return true; - } - - unlink(temp_filename.c_str()); - return false; -#endif // _WIN32 -} - -/** - * Compares the two dotted-integer sequence values numerically. Returns -1 if - * seq_a sorts first, 1 if seq_b sorts first, 0 if they are equivalent. - */ -int P3DHost:: -compare_seq(const string &seq_a, const string &seq_b) { - const char *num_a = seq_a.c_str(); - const char *num_b = seq_b.c_str(); - int comp = compare_seq_int(num_a, num_b); - while (comp == 0) { - if (*num_a != '.') { - if (*num_b != '.') { - // Both strings ran out together. - return 0; - } - // a ran out first. - return -1; - } else if (*num_b != '.') { - // b ran out first. - return 1; - } - - // Increment past the dot. - ++num_a; - ++num_b; - comp = compare_seq(num_a, num_b); - } - - return comp; -} - -/** - * Numerically compares the formatted integer value at num_a with num_b. - * Increments both num_a and num_b to the next character following the valid - * integer. - */ -int P3DHost:: -compare_seq_int(const char *&num_a, const char *&num_b) { - long int a; - char *next_a; - long int b; - char *next_b; - - a = strtol((char *)num_a, &next_a, 10); - b = strtol((char *)num_b, &next_b, 10); - - num_a = next_a; - num_b = next_b; - - if (a < b) { - return -1; - } else if (b < a) { - return 1; - } else { - return 0; - } -} diff --git a/direct/src/plugin/p3dHost.h b/direct/src/plugin/p3dHost.h deleted file mode 100644 index fd880ccde0..0000000000 --- a/direct/src/plugin/p3dHost.h +++ /dev/null @@ -1,115 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dHost.h - * @author drose - * @date 2009-08-21 - */ - -#ifndef P3DHOST_H -#define P3DHOST_H - -#include "p3d_plugin_common.h" -#include "fileSpec.h" -#include - -class FileSpec; -class P3DInstanceManager; -class P3DPackage; - -/** - * Represents a particular download host serving up Panda3D packages. - */ -class P3DHost { -private: - P3DHost(const std::string &host_url, const std::string &host_dir = ""); - ~P3DHost(); - -public: - inline bool has_host_dir() const; - inline const std::string &get_host_dir() const; - inline const std::string &get_host_url() const; - inline const std::string &get_host_url_prefix() const; - inline const std::string &get_download_url_prefix() const; - inline const std::string &get_descriptive_name() const; - - P3DHost *get_alt_host(const std::string &alt_host); - - inline bool has_contents_file() const; - bool has_current_contents_file(P3DInstanceManager *inst_mgr) const; - inline int get_contents_iseq() const; - inline bool check_contents_hash(const std::string &pathname) const; - - bool read_contents_file(); - bool read_contents_file(const std::string &contents_filename, bool fresh_download); - void read_xhost(TiXmlElement *xhost); - - P3DPackage *get_package(const std::string &package_name, - const std::string &package_version, - const std::string &package_platform, - const std::string &package_seq, - const std::string &alt_host = ""); - bool choose_suitable_platform(std::string &selected_platform, - bool &per_platform, - const std::string &package_name, - const std::string &package_version, - const std::string &package_platform); - bool get_package_desc_file(FileSpec &desc_file, - std::string &package_seq, - bool &package_solo, - const std::string &package_name, - const std::string &package_version, - const std::string &package_platform); - - void forget_package(P3DPackage *package, const std::string &alt_host = ""); - void migrate_package_host(P3DPackage *package, const std::string &alt_host, P3DHost *new_host); - - void choose_random_mirrors(std::vector &result, int num_mirrors); - void add_mirror(std::string mirror_url); - - void uninstall(); - -private: - void determine_host_dir(const std::string &host_dir_basename); - - static std::string standardize_filename(const std::string &filename); - static bool copy_file(const std::string &from_filename, const std::string &to_filename); - static bool save_xml_file(TiXmlDocument *doc, const std::string &to_filename); - static int compare_seq(const std::string &seq_a, const std::string &seq_b); - static int compare_seq_int(const char *&num_a, const char *&num_b); - -private: - std::string _host_dir; - std::string _host_url; - std::string _host_url_prefix; - std::string _download_url_prefix; - std::string _descriptive_name; - TiXmlElement *_xcontents; - time_t _contents_expiration; - int _contents_iseq; - FileSpec _contents_spec; - - typedef std::vector Mirrors; - Mirrors _mirrors; - - typedef std::map AltHosts; - AltHosts _alt_hosts; - - typedef std::vector PlatformPackages; - typedef std::map PackageMap; - typedef std::map Packages; - Packages _packages; - typedef std::vector FailedPackages; - FailedPackages _failed_packages; - - friend class P3DInstanceManager; -}; - -#include "p3dHost.I" - -#endif diff --git a/direct/src/plugin/p3dInstance.I b/direct/src/plugin/p3dInstance.I deleted file mode 100644 index 63765832d3..0000000000 --- a/direct/src/plugin/p3dInstance.I +++ /dev/null @@ -1,147 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dInstance.I - * @author drose - * @date 2009-05-29 - */ - -/** - * Returns the current file parameters. - */ -inline const P3DFileParams &P3DInstance:: -get_fparams() const { - return _fparams; -} - -/** - * Returns the current window parameters. - */ -inline const P3DWindowParams &P3DInstance:: -get_wparams() const { - return _wparams; -} - -/** - * Returns a unique integer for each instance in the system. - */ -inline int P3DInstance:: -get_instance_id() const { - return _instance_id; -} - -/** - * Returns a string that uniquely identifies this session. This is a - * constructed string that includes the supplied session_name, the python and - * panda version, and the publisher, as well as any other relevant details; it - * is guaranteed to be unique for each unique session required for different - * P3DInstances. - */ -inline const std::string &P3DInstance:: -get_session_key() const { - return _session_key; -} - -/** - * Returns the platform of this particular session. Before the panda3d - * package has been seen, this is the empty string; once we have downloaded - * the info file for the panda3d package, it is filled in with whatever - * platform is provided (that we're also runtime-compatible with). - * - * Presumably all of the platform-specific packages that are downloaded - * subsequently must be of the exact same platform. - */ -inline const std::string &P3DInstance:: -get_session_platform() const { - return _session_platform; -} - -/** - * Returns the P3DSession that is hosting this instance, or NULL if the - * instance is not running. - */ -inline P3DSession *P3DInstance:: -get_session() const { - return _session; -} - -/** - * Returns a pointer to the asynchronous notification function that was passed - * to the constructor, if any, or NULL if asynchronous notifications are not - * required. - */ -inline P3D_request_ready_func *P3DInstance:: -get_request_ready_func() const { - return _func; -} - -/** - * Returns true if this instance's p3d file is trusted and ready to launch, - * false if it needs to be approved by the user. - */ -inline bool P3DInstance:: -is_trusted() const { - return _p3d_trusted; -} - -/** - * Returns true if this instance is allowed to be scripted by its embedding - * web page, false otherwise. This may not be known until the p3d file has - * been fully downloaded and opened. - */ -inline bool P3DInstance:: -get_matches_script_origin() const { - return _matches_script_origin; -} - -/** - * Returns true if this instance has already been started within some session, - * false otherwise. - */ -inline bool P3DInstance:: -is_started() const { - return (_session != nullptr); -} - -/** - * Returns true if this instance has tried and failed to launch for some - * reason. - */ -inline bool P3DInstance:: -is_failed() const { - return _failed; -} - -/** - * - */ -inline P3DInstance::ImageFile:: -ImageFile() { - _use_standard_image = true; - _temp_filename = nullptr; - _image_placement = P3DSplashWindow::IP_none; -} - -/** - * - */ -inline P3DInstance::ImageFile:: -~ImageFile() { - cleanup(); -} - -/** - * Removes the temporary file, if any. - */ -inline void P3DInstance::ImageFile:: -cleanup() { - if (_temp_filename != nullptr) { - delete _temp_filename; - _temp_filename = nullptr; - } -} diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx deleted file mode 100644 index 220e28c667..0000000000 --- a/direct/src/plugin/p3dInstance.cxx +++ /dev/null @@ -1,3936 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dInstance.cxx - * @author drose - * @date 2009-05-29 - */ - -#include "p3dInstance.h" -#include "p3dInstanceManager.h" -#include "p3dDownload.h" -#include "p3dSession.h" -#include "p3dPackage.h" -#include "p3dSplashWindow.h" -#include "p3dWinSplashWindow.h" -#include "p3dOsxSplashWindow.h" -#include "p3dX11SplashWindow.h" -#include "p3dObject.h" -#include "p3dMainObject.h" -#include "p3dUndefinedObject.h" -#include "p3dMultifileReader.h" -#include "p3dTemporaryFile.h" -#include "parse_color.h" - -#include -#include - -#ifdef __APPLE__ -#include -#include - -using std::max; -using std::min; -using std::ostream; -using std::ostringstream; -using std::stringstream; -using std::string; -using std::vector; - -// Lifted from NSEvent.h (which is Objective-C). -enum { - NSAlphaShiftKeyMask = 1 << 16, - NSShiftKeyMask = 1 << 17, - NSControlKeyMask = 1 << 18, - NSAlternateKeyMask = 1 << 19, - NSCommandKeyMask = 1 << 20, - NSNumericPadKeyMask = 1 << 21, - NSHelpKeyMask = 1 << 22, - NSFunctionKeyMask = 1 << 23, - NSDeviceIndependentModifierFlagsMask = 0xffff0000U -}; - -#endif // __APPLE__ - -#ifdef _WIN32 -typedef P3DWinSplashWindow SplashWindowType; -#elif defined(__APPLE__) && !__LP64__ -typedef P3DOsxSplashWindow SplashWindowType; -#elif defined(HAVE_X11) -typedef P3DX11SplashWindow SplashWindowType; -#else -typedef P3DSplashWindow SplashWindowType; -#endif - -// The amount of time (in seconds) over which we average the total download -// time, for smoothing out the time estimate. -static const double time_average = 10.0; - -// These are the various image files we might download for use in the splash -// window. This list must match the ImageType enum. -const char *P3DInstance::_image_type_names[P3DInstance::IT_num_image_types] = { - "download", - "unauth", - "ready", - "failed", - "launch", - "active", - "auth_ready", - "auth_rollover", - "auth_click", - "play_ready", - "play_rollover", - "play_click", - "none", // Not really used. -}; - -static void -write_str(ostream &out, const wchar_t *str) { - const wchar_t *p = str; - while (*p != 0) { - out << (int)*p << ' '; - ++p; - } -} - -/** - * - */ -P3DInstance:: -P3DInstance(P3D_request_ready_func *func, - const P3D_token tokens[], size_t num_tokens, - int argc, const char *argv[], void *user_data) : - _func(func) -{ - _dom_object = nullptr; - _main_object = new P3DMainObject; - _main_object->set_instance(this); - _user_data = user_data; - _request_pending = false; - _total_time_reports = 0; - _temp_p3d_filename = nullptr; - _image_package = nullptr; - _current_background_image = IT_none; - _current_button_image = IT_none; - _got_fparams = false; - _got_wparams = false; - _p3d_trusted = false; - _xpackage = nullptr; - _certlist_package = nullptr; - _p3dcert_package = nullptr; - - _fparams.set_tokens(tokens, num_tokens); - _fparams.set_args(argc, argv); - - nout << "Creating P3DInstance " << this << ": "; - for (int i = 0; i < _fparams.get_num_tokens(); ++i) { - nout << " " << _fparams.get_token_keyword(i) - << "=\"" << _fparams.get_token_value(i) << "\""; - } - nout << "\n"; - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - _instance_id = inst_mgr->get_unique_id(); - _hidden = (_fparams.lookup_token_int("hidden") != 0); - _matches_run_origin = true; - _matches_script_origin = false; - _allow_python_dev = false; - _keep_user_env = (_fparams.lookup_token_int("keep_user_env") != 0); - _auto_start = (_fparams.lookup_token_int("auto_start") != 0); - _stop_on_ready = (_fparams.lookup_token_int("stop_on_ready") != 0); - _auto_install = true; - if (_fparams.has_token("auto_install")) { - _auto_install = (_fparams.lookup_token_int("auto_install") != 0); - } - _auth_button_clicked = false; - _failed = false; - _session = nullptr; - _auth_session = nullptr; - _panda3d_package = nullptr; - _splash_window = nullptr; - _instance_window_opened = false; - _instance_window_attached = false; - _stuff_to_download = false; - _download_package_index = 0; - _prev_downloaded = 0; - _total_download_size = 0; - _total_downloaded = 0; - _packages_specified = false; - _download_started = false; - _download_complete = false; - _instance_started = false; - - INIT_LOCK(_request_lock); - _requested_stop = false; - -#ifdef __APPLE__ - _shared_fd = -1; - _shared_mmap_size = 0; - _swbuffer = nullptr; - _reversed_buffer = nullptr; - _buffer_data = nullptr; - _data_provider = nullptr; - _buffer_color_space = nullptr; - _buffer_image = nullptr; - - // We have to start with _mouse_active true; firefox doesn't send activate - // events. - _mouse_active = true; - _modifiers = 0; - _frame_timer = nullptr; -#endif // __APPLE__ - - // Set some initial properties. - _main_object->set_float_property("instanceDownloadProgress", 0.0); - _main_object->set_float_property("downloadProgress", 0.0); - _main_object->set_undefined_property("downloadElapsedSeconds"); - _main_object->set_undefined_property("downloadElapsedFormatted"); - _main_object->set_undefined_property("downloadRemainingSeconds"); - _main_object->set_undefined_property("downloadRemainingFormatted"); - _main_object->set_string_property("downloadPackageName", ""); - _main_object->set_string_property("downloadPackageDisplayName", ""); - _main_object->set_bool_property("downloadComplete", false); - _main_object->set_string_property("status", "initial"); - - ostringstream stream; - stream << inst_mgr->get_plugin_major_version() << "." - << inst_mgr->get_plugin_minor_version() << "." - << inst_mgr->get_plugin_sequence_version(); - if (!inst_mgr->get_plugin_official_version()) { - stream << "c"; - } - - // The plugin version as a single number, with three digits reserved for - // each component. - int numeric_version = - inst_mgr->get_plugin_major_version() * 1000000 + - inst_mgr->get_plugin_minor_version() * 1000 + - inst_mgr->get_plugin_sequence_version(); - if (!inst_mgr->get_plugin_official_version()) { - // Subtract 1 if we are not an official version. - --numeric_version; - } - - _main_object->set_string_property("pluginVersionString", stream.str()); - _main_object->set_int_property("pluginMajorVersion", inst_mgr->get_plugin_major_version()); - _main_object->set_int_property("pluginMinorVersion", inst_mgr->get_plugin_minor_version()); - _main_object->set_int_property("pluginSequenceVersion", inst_mgr->get_plugin_sequence_version()); - _main_object->set_bool_property("pluginOfficialVersion", inst_mgr->get_plugin_official_version()); - _main_object->set_int_property("pluginNumericVersion", numeric_version); - _main_object->set_string_property("pluginDistributor", inst_mgr->get_plugin_distributor()); - _main_object->set_string_property("coreapiHostUrl", inst_mgr->get_coreapi_host_url()); - time_t timestamp = inst_mgr->get_coreapi_timestamp(); - _main_object->set_int_property("coreapiTimestamp", (int)timestamp); - const char *timestamp_string = ctime(×tamp); - if (timestamp_string == nullptr) { - timestamp_string = ""; - } - _main_object->set_string_property("coreapiTimestampString", timestamp_string); - _main_object->set_string_property("coreapiVersionString", inst_mgr->get_coreapi_set_ver()); - - _main_object->set_bool_property("trustedEnvironment", (int)inst_mgr->get_trusted_environment()); - _main_object->set_bool_property("consoleEnvironment", (int)inst_mgr->get_console_environment()); - - // We'll start off with the "download" image displayed in the splash window - // (when it opens), until we get stuff downloaded. - set_background_image(IT_download); - - // We'd better ask for the image package up front, even if it turns out we - // don't need it for this particular app. We'll probably use it eventually, - // and it's good to have it loaded early, so we can put up a splash image - // (for instance, the above IT_download image) while we download the real - // contents. - P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url()); - _image_package = host->get_package("images", "", "", ""); - if (_image_package != nullptr) { - _image_package->add_instance(this); - } - - // Check if the window size has been explicitly set to 0. This means we - // have an explicitly hidden plugin, and we should be prepared not to get a - // wparams from the browser. - if (_fparams.has_token("width") && _fparams.has_token("height") && - (_fparams.lookup_token_int("width") == 0 || - _fparams.lookup_token_int("height") == 0)) { - P3D_window_handle dummy_handle; - memset(&dummy_handle, 0, sizeof(dummy_handle)); - P3DWindowParams wparams(P3D_WT_hidden, 0, 0, 0, 0, dummy_handle); - set_wparams(wparams); - } -} - -/** - * - */ -P3DInstance:: -~P3DInstance() { - assert(_session == nullptr); - cleanup(); - - if (_dom_object != nullptr) { - P3D_OBJECT_DECREF(_dom_object); - _dom_object = nullptr; - } - - if (_main_object != nullptr) { - nout << "panda_script_object ref = " - << _main_object->_ref_count << "\n"; - _main_object->set_instance(nullptr); - P3D_OBJECT_DECREF(_main_object); - _main_object = nullptr; - } - - Downloads::iterator di; - for (di = _downloads.begin(); di != _downloads.end(); ++di) { - P3DDownload *download = (*di).second; - if (download->get_instance() == this) { - download->set_instance(nullptr); - } - p3d_unref_delete(download); - } - _downloads.clear(); - - DESTROY_LOCK(_request_lock); - - // TODO: Is it possible for someone to delete an instance while a download - // is still running? Who will crash when this happens? -} - -/** - * Invalidates the instance and removes any structures prior to deleting. - */ -void P3DInstance:: -cleanup() { - _failed = true; - - if (_auth_session != nullptr) { - _auth_session->shutdown(false); - p3d_unref_delete(_auth_session); - _auth_session = nullptr; - } - - for (int i = 0; i < (int)IT_num_image_types; ++i) { - _image_files[i].cleanup(); - } - - // Tell all of the packages that we're no longer in business for them. - Packages::iterator pi; - for (pi = _packages.begin(); pi != _packages.end(); ++pi) { - (*pi)->remove_instance(this); - } - _packages.clear(); - if (_image_package != nullptr) { - _image_package->remove_instance(this); - _image_package = nullptr; - } - - if (_certlist_package != nullptr) { - _certlist_package->remove_instance(this); - _certlist_package = nullptr; - } - - if (_p3dcert_package != nullptr) { - _p3dcert_package->remove_instance(this); - _p3dcert_package = nullptr; - } - - if (_splash_window != nullptr) { - delete _splash_window; - _splash_window = nullptr; - } - - if (_temp_p3d_filename != nullptr) { - delete _temp_p3d_filename; - _temp_p3d_filename = nullptr; - } - - if (_xpackage != nullptr) { - delete _xpackage; - _xpackage = nullptr; - } - -#ifdef __APPLE__ - if (_frame_timer != nullptr) { - CFRunLoopTimerInvalidate(_frame_timer); - CFRelease(_frame_timer); - _frame_timer = nullptr; - } - - free_swbuffer(); -#endif - - TiXmlDocument *doc = nullptr; - ACQUIRE_LOCK(_request_lock); - RawRequests::iterator ri; - for (ri = _raw_requests.begin(); ri != _raw_requests.end(); ++ri) { - doc = (*ri); - delete doc; - } - _raw_requests.clear(); - RELEASE_LOCK(_request_lock); - - BakedRequests::iterator bi; - for (bi = _baked_requests.begin(); bi != _baked_requests.end(); ++bi) { - P3D_request *request = (*bi); - finish_request(request, false); - } - _baked_requests.clear(); - - Downloads::iterator di; - for (di = _downloads.begin(); di != _downloads.end(); ++di) { - P3DDownload *download = (*di).second; - download->cancel(); - } -} - - -/** - * Specifies a URL that should be contacted to download the instance data. - * Normally this, or set_p3d_filename() or make_p3d_stream(), is only called - * once. - * - * The instance data at the other end of this URL is key. We can't start the - * instance until we have downloaded the instance file and examined the - * p3d_info.xml, and we know what Python version we need and so forth. - */ -void P3DInstance:: -set_p3d_url(const string &p3d_url) { - if (p3d_url.empty()) { - nout << "No p3d URL specified. Cannot run.\n"; - set_failed(); - return; - } - _fparams.set_p3d_url(p3d_url); - - // Save the last part of the URL as the p3d_basename, for reporting purposes - // or whatever. - determine_p3d_basename(p3d_url); - - // Make a temporary file to receive the instance data. - assert(_temp_p3d_filename == nullptr); - _temp_p3d_filename = new P3DTemporaryFile(".p3d"); - _stuff_to_download = true; - - // Maybe it's time to open a splash window now. - make_splash_window(); - - // Mark the time we started downloading, so we'll know when to reveal the - // progress bar, and we can predict the total download time. -#ifdef _WIN32 - _start_dl_tick = GetTickCount(); -#else - gettimeofday(&_start_dl_timeval, nullptr); -#endif - _show_dl_instance_progress = false; - - // Start downloading the data. - InstanceDownload *download = new InstanceDownload(this); - download->set_url(p3d_url); - download->set_filename(_temp_p3d_filename->get_filename()); - if (_fparams.has_token("p3d_size")) { - download->set_total_expected_data(_fparams.lookup_token_int("p3d_size")); - } - - _main_object->set_string_property("status", "downloading_instance"); - start_download(download); -} - -/** - * Indicates an intention to transmit the p3d data as a stream. Should return - * a new unique stream ID to receive it. - */ -int P3DInstance:: -make_p3d_stream(const string &p3d_url) { - _fparams.set_p3d_url(p3d_url); - - // Save the last part of the URL as the p3d_basename, for reporting purposes - // or whatever. - determine_p3d_basename(p3d_url); - - // Make a temporary file to receive the instance data. - assert(_temp_p3d_filename == nullptr); - _temp_p3d_filename = new P3DTemporaryFile(".p3d"); - _stuff_to_download = true; - - // Maybe it's time to open a splash window now. - make_splash_window(); - - // Mark the time we started downloading, so we'll know when to reveal the - // progress bar. -#ifdef _WIN32 - _start_dl_tick = GetTickCount(); -#else - gettimeofday(&_start_dl_timeval, nullptr); -#endif - _show_dl_instance_progress = false; - - // Start downloading the data. - InstanceDownload *download = new InstanceDownload(this); - download->set_url(p3d_url); - download->set_filename(_temp_p3d_filename->get_filename()); - if (_fparams.has_token("p3d_size")) { - download->set_total_expected_data(_fparams.lookup_token_int("p3d_size")); - } - - _main_object->set_string_property("status", "downloading_instance"); - return start_download(download, false); -} - -/** - * Specifies the file that contains the instance data. Normally this is only - * called once. - */ -void P3DInstance:: -set_p3d_filename(const string &p3d_filename, const int &p3d_offset) { - determine_p3d_basename(p3d_filename); - priv_set_p3d_filename(p3d_filename, p3d_offset); -} - -/** - * Changes the window parameters, e.g. to resize or reposition the window; or - * sets the parameters for the first time, creating the initial window. - */ -void P3DInstance:: -set_wparams(const P3DWindowParams &wparams) { - bool prev_got_wparams = _got_wparams; - _got_wparams = true; - _wparams = wparams; - - nout << "set_wparams: " << wparams.get_window_type() - << " " << wparams.get_win_width() << " " << wparams.get_win_height() - << "\n"; - - if (_hidden || _wparams.get_win_width() == 0 || _wparams.get_win_height() == 0) { - // If we're a hidden app, or if the window has no size, then it is really - // a hidden window, regardless of what type it claims to be. - _wparams.set_window_type(P3D_WT_hidden); - } - - if (_wparams.get_window_type() != P3D_WT_hidden) { - // Update or create the splash window. - if (_splash_window != nullptr) { - _splash_window->set_wparams(_wparams); - } else { - make_splash_window(); - } - } - - // It doesn't make much sense to go further than this point if the instance - // is already in the failed state. - if (is_failed()) { - return; - } - - if (_wparams.get_window_type() != P3D_WT_hidden) { -#ifdef __APPLE__ - // On Mac, we have to communicate the results of the rendering back via - // shared memory, instead of directly parenting windows to the browser. - // Set up this mechanism. - int x_size = _wparams.get_win_width(); - int y_size = _wparams.get_win_height(); - if (x_size != 0 && y_size != 0) { - if (_swbuffer == nullptr || _swbuffer->get_x_size() != x_size || - _swbuffer->get_y_size() != y_size) { - // We need to open a new shared buffer. - alloc_swbuffer(); - } - - if (_swbuffer == nullptr) { - nout << "Could not open swbuffer\n"; - } - } -#endif // __APPLE__ - } - - // Update the instance in the sub-process. - if (_session != nullptr) { - TiXmlDocument *doc = new TiXmlDocument; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "setup_window"); - xcommand->SetAttribute("instance_id", get_instance_id()); - TiXmlElement *xwparams = _wparams.make_xml(this); - - doc->LinkEndChild(xcommand); - xcommand->LinkEndChild(xwparams); - - _session->send_command(doc); - } - - if (!prev_got_wparams) { - // If this was the first set_wparams call, try to start the app. - if (_p3d_trusted && get_packages_ready()) { - ready_to_start(); - } - } -} - -/** - * Returns a pointer to the top-level scriptable object of the instance, to be - * used by JavaScript code in the browser to control this program. - */ -P3D_object *P3DInstance:: -get_panda_script_object() const { - nout << "get_panda_script_object\n"; - return _main_object; -} - -/** - * Stores a pointer to the top-level window object of the browser, to be used - * by Panda code to control JavaScript. The new object's reference count is - * incremented, and the previous object's is decremented. - */ -void P3DInstance:: -set_browser_script_object(P3D_object *browser_script_object) { - nout << "set_browser_script_object\n"; - if (browser_script_object != _dom_object) { - P3D_OBJECT_XDECREF(_dom_object); - _dom_object = browser_script_object; - if (_dom_object != nullptr) { - P3D_OBJECT_INCREF(_dom_object); - } - - if (_session != nullptr) { - send_browser_script_object(); - } - } - - // Query the origin: protocol, hostname, and port. We'll use this to limit - // access to the scripting interfaces for a particular p3d file. - _origin_protocol.clear(); - _origin_hostname.clear(); - _origin_port.clear(); - if (_dom_object != nullptr) { - P3D_object *location = P3D_OBJECT_GET_PROPERTY(_dom_object, "location"); - if (location != nullptr) { - P3D_object *protocol = P3D_OBJECT_GET_PROPERTY(location, "protocol"); - if (protocol != nullptr) { - int size = P3D_OBJECT_GET_STRING(protocol, nullptr, 0); - char *buffer = new char[size]; - P3D_OBJECT_GET_STRING(protocol, buffer, size); - _origin_protocol = string(buffer, size); - delete [] buffer; - P3D_OBJECT_DECREF(protocol); - } - - P3D_object *hostname = P3D_OBJECT_GET_PROPERTY(location, "hostname"); - if (hostname != nullptr) { - int size = P3D_OBJECT_GET_STRING(hostname, nullptr, 0); - char *buffer = new char[size]; - P3D_OBJECT_GET_STRING(hostname, buffer, size); - _origin_hostname = string(buffer, size); - delete [] buffer; - P3D_OBJECT_DECREF(hostname); - } - - P3D_object *port = P3D_OBJECT_GET_PROPERTY(location, "port"); - if (port != nullptr) { - int size = P3D_OBJECT_GET_STRING(port, nullptr, 0); - char *buffer = new char[size]; - P3D_OBJECT_GET_STRING(port, buffer, size); - _origin_port = string(buffer, size); - delete [] buffer; - P3D_OBJECT_DECREF(port); - } - - if (_origin_hostname.empty() && _origin_protocol == "file:") { - _origin_hostname = "localhost"; - } - - if (_origin_port.empty()) { - // Maybe the actual URL doesn't include the port, in which case it is - // implicit. - if (_origin_protocol == "http:") { - _origin_port = "80"; - } else if (_origin_protocol == "https:") { - _origin_port = "443"; - } - } - - P3D_OBJECT_DECREF(location); - } - } - - nout << "origin is " << _origin_protocol << "//" << _origin_hostname; - if (!_origin_port.empty()) { - nout << ":" << _origin_port; - } - nout << "\n"; -} - - -/** - * Returns true if the instance has any pending requests at the time of this - * call, false otherwise. - */ -bool P3DInstance:: -has_request() { - return _request_pending; -} - -/** - * Returns a newly-allocated P3D_request corresponding to the pending request - * for the host, or NULL if there is no pending request. If the return value - * is non-NULL, it should eventually be passed back to finish_request() for - * cleanup. - */ -P3D_request *P3DInstance:: -get_request() { - bake_requests(); - if (_baked_requests.empty()) { - // No requests ready. - _request_pending = false; - return nullptr; - } - - P3D_request *request = _baked_requests.front(); - _baked_requests.pop_front(); - _request_pending = !_baked_requests.empty(); - - if (request != nullptr) { - switch (request->_request_type) { - case P3D_RT_notify: - { - // Also eval the associated HTML token, if any. - string message = request->_request._notify._message; - string expression = _fparams.lookup_token(message); - nout << "notify: " << message << " " << expression << "\n"; - if (!expression.empty() && _dom_object != nullptr) { - P3D_object *result = P3D_OBJECT_EVAL(_dom_object, expression.c_str()); - P3D_OBJECT_XDECREF(result); - } - } - break; - - case P3D_RT_stop: - { - // We also send an implicit message when Python requests itself to - // shutdown. - _main_object->set_pyobj(nullptr); - _main_object->set_string_property("status", "stopped"); - - string message = "onpythonstop"; - string expression = _fparams.lookup_token(message); - nout << "notify: " << message << " " << expression << "\n"; - if (!expression.empty() && _dom_object != nullptr) { - P3D_object *result = P3D_OBJECT_EVAL(_dom_object, expression.c_str()); - P3D_OBJECT_XDECREF(result); - } - } - break; - - case P3D_RT_callback: - { - // And when the callback request is extracted, we make the callback. - P3D_callback_func *func = request->_request._callback._func; - void *data = request->_request._callback._data; - (*func)(data); - } - break; - - case P3D_RT_forget_package: - { - // We're being asked to forget a particular package. - const char *host_url = request->_request._forget_package._host_url; - const char *package_name = request->_request._forget_package._package_name; - const char *package_version = request->_request._forget_package._package_version; - if (package_version == nullptr) { - package_version = ""; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3DHost *host = inst_mgr->get_host(host_url); - if (package_name != nullptr) { - P3DPackage *package = host->get_package(package_name, package_version, _session_platform, ""); - host->forget_package(package); - } else { - // If a NULL package name is given, forget the whole host. - inst_mgr->forget_host(host); - } - } - break; - - default: - break; - } - } - - return request; -} - -/** - * Copies requests from the _raw_requests queue, which is built up in one or - * more sub-threads, into the _baked_requests queue, which is publicly - * presented to the browser. Along the way, some requests (like script - * requests) are handled immediately. - * - * At the end of this call, _baked_requests will contain the current set of - * requests pending for the browser. - * - * This method should only be called in the main thread. - */ -void P3DInstance:: -bake_requests() { - while (true) { - // Get the latest request from the read thread. - TiXmlDocument *doc = nullptr; - ACQUIRE_LOCK(_request_lock); - if (!_raw_requests.empty()) { - doc = _raw_requests.front(); - _raw_requests.pop_front(); - } - RELEASE_LOCK(_request_lock); - - if (doc == nullptr) { - // No more requests to process right now. - return; - } - - // Now we've got a request in XML form; convert it to P3D_request form. - TiXmlElement *xrequest = doc->FirstChildElement("request"); - assert(xrequest != nullptr); - P3D_request *request = make_p3d_request(xrequest); - delete doc; - - if (request != nullptr) { - _baked_requests.push_back(request); - } - } -} - -/** - * May be called in any thread to add a new XML request to the pending_request - * queue for this instance. The XML document will be deleted when the request - * is eventually handled. - */ -void P3DInstance:: -add_raw_request(TiXmlDocument *doc) { - ACQUIRE_LOCK(_request_lock); - _raw_requests.push_back(doc); - _request_pending = true; - RELEASE_LOCK(_request_lock); - - // We don't decode the XML yet, since we might be running in any thread - // here. We'll decode it in the main thread, where it's safe. - - // Tell the world we've got a new request. - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - inst_mgr->signal_request_ready(this); - if (_session != nullptr) { - _session->signal_request_ready(this); - } -} - -/** - * May be called in the main thread only to add a new request to the - * baked_request queue. This request queue is directly passed on the browser - * without further processing at this level. - */ -void P3DInstance:: -add_baked_request(P3D_request *request) { - assert(request->_instance == nullptr); - request->_instance = this; - ref(); - - _baked_requests.push_back(request); - _request_pending = true; - - // Tell the world we've got a new request. - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - inst_mgr->signal_request_ready(this); -} - -/** - * Deallocates a previously-returned request from get_request(). If handled - * is true, the request has been handled by the host; otherwise, it has been - * ignored. - */ -void P3DInstance:: -finish_request(P3D_request *request, bool handled) { - assert(request != nullptr); - if (request->_instance == nullptr) { - nout << "Ignoring empty request " << request << "\n"; - return; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (inst_mgr->validate_instance(request->_instance) == nullptr) { - // nout << "Ignoring unknown request " << request << "\n"; - return; - } - - switch (request->_request_type) { - case P3D_RT_stop: - break; - - case P3D_RT_get_url: - if (request->_request._get_url._url != nullptr) { - free((char *)request->_request._get_url._url); - request->_request._get_url._url = nullptr; - } - break; - - case P3D_RT_notify: - if (request->_request._notify._message != nullptr) { - free((char *)request->_request._notify._message); - request->_request._notify._message = nullptr; - } - break; - - case P3D_RT_forget_package: - if (request->_request._forget_package._host_url != nullptr) { - free((char *)request->_request._forget_package._host_url); - request->_request._forget_package._host_url = nullptr; - } - if (request->_request._forget_package._package_name != nullptr) { - free((char *)request->_request._forget_package._package_name); - request->_request._forget_package._package_name = nullptr; - } - if (request->_request._forget_package._package_version != nullptr) { - free((char *)request->_request._forget_package._package_version); - request->_request._forget_package._package_version = nullptr; - } - break; - - default: - break; - } - - p3d_unref_delete(((P3DInstance *)request->_instance)); - request->_instance = nullptr; - - delete request; -} - -/** - * Called by the host in response to a get_url request, this sends the data - * retrieved from the requested URL, a piece at a time. - */ -bool P3DInstance:: -feed_url_stream(int unique_id, - P3D_result_code result_code, - int http_status_code, - size_t total_expected_data, - const unsigned char *this_data, - size_t this_data_size) { - Downloads::iterator di = _downloads.find(unique_id); - if (di == _downloads.end()) { - nout << "Unexpected feed_url_stream for " << unique_id << "\n"; - // Don't know this request. - return false; - } - - P3DDownload *download = (*di).second; - assert(download->get_instance() == this); - bool download_ok = download->feed_url_stream - (result_code, http_status_code, total_expected_data, - this_data, this_data_size); - - if (!download_ok || download->get_download_finished()) { - // All done. - if (download->get_instance() == this) { - download->set_instance(nullptr); - } - _downloads.erase(di); - p3d_unref_delete(download); - } - - return download_ok; -} - -/** - * Responds to the os-generated window event. Returns true if the event is - * handled, false if ignored. - */ -bool P3DInstance:: -handle_event(const P3D_event_data &event) { - bool retval = false; - if (_splash_window != nullptr) { - if (_splash_window->handle_event(event)) { - retval = true; - } - } - -#if defined(__APPLE__) - if (event._event_type == P3D_ET_osx_event_record) { - retval = handle_event_osx_event_record(event); - } else if (event._event_type == P3D_ET_osx_cocoa) { - retval = handle_event_osx_cocoa(event); - } else { - assert(false); - } -#endif // __APPLE__ - - return retval; -} - -/** - * Returns the log filename for this particular session, if the session was - * started and if it has a log file. Returns empty string if the session - * never started or if it lacks a log file. - * - * This is the same value returned by P3DSession::get_log_pathname(), except - * that it remains valid even after the session has closed. - */ -const string &P3DInstance:: -get_log_pathname() const { - if (_session != nullptr) { - return _session->_log_pathname; - } - return _log_pathname; -} - -/** - * Adds the package to the list of packages used by this instance. The - * instance will share responsibility for downloading the package with any of - * the other instances that use the same package. - * - * The seq value should be the expected minimum package_seq value for the - * indicated package. If the given seq value is higher than the package_seq - * value in the contents.xml file cached for the host, it is a sign that the - * contents.xml file is out of date and needs to be redownloaded. - */ -void P3DInstance:: -add_package(const string &name, const string &version, const string &seq, - P3DHost *host) { - string alt_host = _fparams.lookup_token("alt_host"); - - // Look up in the p3d_info.xml file to see if this p3d file has a specific - // alt_host indication for this host_url. - string alt_host_url = find_alt_host_url(host->get_host_url(), alt_host); - if (!alt_host_url.empty()) { - // If it does, we go ahead and switch to that host now, instead of - // bothering to contact the original host. - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - host = inst_mgr->get_host(alt_host_url); - alt_host.clear(); - } - - if (!host->has_contents_file()) { - // Since we haven't downloaded this host's contents.xml file yet, get its - // additional host information. - get_host_info(host); - } - - P3DPackage *package = host->get_package(name, version, _session_platform, - seq, alt_host); - add_package(package); -} - -/** - * Adds the package to the list of packages used by this instance. The - * instance will share responsibility for downloading the package with any of - * the other instances that use the same package. - */ -void P3DInstance:: -add_package(P3DPackage *package) { - if (find(_packages.begin(), _packages.end(), package) != _packages.end()) { - // Already have this package. - return; - } - - if (package->get_package_name() == "panda3d") { - _panda3d_package = package; - } - - _packages.push_back(package); - - // This call must be at the end of this method, because it might ultimately - // start the application before it returns (if this was the last required - // package). - package->add_instance(this); -} - -/** - * Indicates that the given package is destructing and this instance should no - * longer retain a pointer to it. This is normally called only by the - * P3DPackage destructor, and it invalidates the instance. - */ -void P3DInstance:: -remove_package(P3DPackage *package) { - Packages::iterator pi = find(_packages.begin(), _packages.end(), package); - if (pi != _packages.end()) { - _packages.erase(pi); - } - pi = find(_downloading_packages.begin(), _downloading_packages.end(), package); - if (pi != _downloading_packages.end()) { - _downloading_packages.erase(pi); - } - if (package == _image_package) { - _image_package = nullptr; - } - if (package == _certlist_package) { - _certlist_package = nullptr; - } - if (package == _p3dcert_package) { - _p3dcert_package = nullptr; - } - if (package == _panda3d_package) { - _panda3d_package = nullptr; - } - - set_failed(); -} - -/** - * Returns true if all of the packages required by the instance have their - * information available and are ready to be downloaded, false if one or more - * of them is still waiting for information (or has failed). - */ -bool P3DInstance:: -get_packages_info_ready() const { - if (!_packages_specified) { - // We haven't even specified the full set of required packages yet. - return false; - } - - Packages::const_iterator pi; - for (pi = _packages.begin(); pi != _packages.end(); ++pi) { - if (!(*pi)->get_info_ready()) { - return false; - } - } - - return true; -} - -/** - * Returns true if all of the packages required by the instance (as specified - * in previous calls to add_package()) have been fully downloaded and are - * ready to run, or false if one or more of them still requires downloading. - */ -bool P3DInstance:: -get_packages_ready() const { - if (!_packages_specified) { - // We haven't even specified the full set of required packages yet. - return false; - } - - Packages::const_iterator pi; - for (pi = _packages.begin(); pi != _packages.end(); ++pi) { - if (!(*pi)->get_ready()) { - return false; - } - } - - return true; -} - -/** - * Returns true if any of the packages required by the instance have failed to - * download (and thus we will never be ready). - */ -bool P3DInstance:: -get_packages_failed() const { - Packages::const_iterator pi; - for (pi = _packages.begin(); pi != _packages.end(); ++pi) { - if ((*pi)->get_failed()) { - return true; - } - } - - return false; -} - -/** - * Adds a newly-allocated P3DDownload object to the download queue, and issues - * the request to start it downloading. As the download data comes in, it - * will be fed to the download object. - * - * This increments the P3DDownload object's reference count, and will - * decrement it (and possibly delete the object) after download_finished() has - * been called. - * - * add_request should be true to actually request the URL from the plugin, or - * false not to. Normally, this should always be set true, except in the one - * special case of make_p3d_stream(), in which case the plugin is already - * prepared to send the stream and doesn't need to have it requested. - * - * Returns the unique ID of this stream. - */ -int P3DInstance:: -start_download(P3DDownload *download, bool add_request) { - assert(download->get_download_id() == 0); - assert(!download->get_url().empty()); - - if (is_failed()) { - // Can't download anything more after failure. - download->cancel(); - return 0; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - int download_id = inst_mgr->get_unique_id(); - download->set_download_id(download_id); - download->set_instance(this); - - download->ref(); - bool inserted = _downloads.insert(Downloads::value_type(download_id, download)).second; - assert(inserted); - - // add_request will be false only for the initial p3d stream, which the - // plugin already knows about. For all other download streams, add_request - // is true in order to ask the plugin for the stream. - if (add_request) { - P3D_request *request = new P3D_request; - request->_instance = nullptr; - request->_request_type = P3D_RT_get_url; - request->_request._get_url._url = strdup(download->get_url().c_str()); - request->_request._get_url._unique_id = download_id; - - add_baked_request(request); - } - - return download_id; -} - -/** - * Asks the host to shut down this particular instance, presumably because the - * user has indicated it should exit. This call may be made in any thread. - */ -void P3DInstance:: -request_stop_sub_thread() { - // Atomically check _requested_stop. - bool add_request = false; - ACQUIRE_LOCK(_request_lock); - if (!_requested_stop) { - _requested_stop = true; - add_request = true; - } - RELEASE_LOCK(_request_lock); - - // If we haven't requested a stop already, do it now. - if (add_request) { - TiXmlDocument *doc = new TiXmlDocument; - TiXmlElement *xrequest = new TiXmlElement("request"); - xrequest->SetAttribute("rtype", "stop"); - doc->LinkEndChild(xrequest); - - add_raw_request(doc); - } -} - -/** - * Asks the host to shut down this particular instance, presumably because the - * user has indicated it should exit. This call may only be made in the main - * thread. - */ -void P3DInstance:: -request_stop_main_thread() { - // Atomically check _requested_stop. - bool add_request = false; - ACQUIRE_LOCK(_request_lock); - if (!_requested_stop) { - _requested_stop = true; - add_request = true; - } - RELEASE_LOCK(_request_lock); - - // If we haven't requested a stop already, do it now. - if (add_request) { - _requested_stop = true; - P3D_request *request = new P3D_request; - request->_instance = nullptr; - request->_request_type = P3D_RT_stop; - add_baked_request(request); - } -} - -/** - * Asks the host to refresh the plugin window. This is only relevant for - * windowless plugins, for instance, the way OSX plugins always run. - */ -void P3DInstance:: -request_refresh() { - P3D_request *request = new P3D_request; - request->_instance = nullptr; - request->_request_type = P3D_RT_refresh; - add_baked_request(request); -} - -/** - * Asks the host to make a callback later. - */ -void P3DInstance:: -request_callback(P3D_callback_func *func, void *data) { - P3D_request *request = new P3D_request; - request->_instance = nullptr; - request->_request_type = P3D_RT_callback; - request->_request._callback._func = func; - request->_request._callback._data = data; - add_baked_request(request); -} - -/** - * Returns a newly-allocated XML structure that corresponds to the data within - * this instance. - */ -TiXmlElement *P3DInstance:: -make_xml() { - assert(_got_fparams); - - TiXmlElement *xinstance = new TiXmlElement("instance"); - xinstance->SetAttribute("instance_id", _instance_id); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - xinstance->SetAttribute("root_dir", inst_mgr->get_root_dir()); - xinstance->SetAttribute("log_directory", inst_mgr->get_log_directory()); - xinstance->SetAttribute("verify_contents", (int)inst_mgr->get_verify_contents()); - - // Tell the Panda process that it was started by a plugin that knows about - // the new per_platform flag. - xinstance->SetAttribute("respect_per_platform", 1); - - if (!inst_mgr->get_super_mirror().empty()) { - xinstance->SetAttribute("super_mirror", inst_mgr->get_super_mirror()); - } - - - TiXmlElement *xfparams = _fparams.make_xml(); - xinstance->LinkEndChild(xfparams); - - if (_got_wparams) { - TiXmlElement *xwparams = _wparams.make_xml(this); - xinstance->LinkEndChild(xwparams); - } - - Packages::const_iterator pi; - for (pi = _packages.begin(); pi != _packages.end(); ++pi) { - TiXmlElement *xpackage = (*pi)->make_xml(); - xinstance->LinkEndChild(xpackage); - } - - TiXmlElement *xmain = _session->p3dobj_to_xml(_main_object); - xmain->SetValue("main"); - xinstance->LinkEndChild(xmain); - - return xinstance; -} - -/** - * Called by the P3DSplashWindow code (maybe in a sub-thread) when the user - * clicks the button visible on the splash window. This will forward the - * event to the main thread via the request callback mechanism. - */ -void P3DInstance:: -splash_button_clicked_sub_thread() { - TiXmlDocument *doc = new TiXmlDocument; - TiXmlElement *xrequest = new TiXmlElement("request"); - xrequest->SetAttribute("rtype", "notify"); - xrequest->SetAttribute("message", "buttonclick"); - doc->LinkEndChild(xrequest); - - add_raw_request(doc); -} - -/** - * Called only in the main thread, indirectly from - * splash_button_clicked_sub_thread(), as the result of the user clicking on - * the button visible in the splash window. - */ -void P3DInstance:: -splash_button_clicked_main_thread() { - if (is_failed()) { - // Can't click the button after we've failed. - nout << "Ignoring click for failed instance\n"; - return; - } - - if (!_p3d_trusted) { - auth_button_clicked(); - } else if (_session == nullptr) { - play_button_clicked(); - } else { - nout << "Ignoring click for already-started instance\n"; - } -} - -/** - * Called to authorize the p3d file by the user clicking the red "auth" - * button. - */ -void P3DInstance:: -auth_button_clicked() { - // Delete the previous session and create a new one. - if (_auth_session != nullptr) { - _auth_session->shutdown(false); - p3d_unref_delete(_auth_session); - _auth_session = nullptr; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - _auth_session = inst_mgr->authorize_instance(this); - _auth_session->ref(); -} - -/** - * Called to start the game by the user clicking the green "play" button, or - * by JavaScript calling play(). - */ -void P3DInstance:: -play_button_clicked() { - if (_session == nullptr && _p3d_trusted) { - set_button_image(IT_none); - if (!_download_started) { - // Now we initiate the download. - _auto_install = true; - _auto_start = true; - if (get_packages_info_ready()) { - ready_to_install(); - } - - } else { - set_background_image(IT_launch); - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - inst_mgr->start_instance(this); - } - } -} - -/** - * Called by the P3DAuthSession code in a sub-thread when the auth dialog - * exits (for instance, because the user approved the certificate, or - * cancelled). - */ -void P3DInstance:: -auth_finished_sub_thread() { - TiXmlDocument *doc = new TiXmlDocument; - TiXmlElement *xrequest = new TiXmlElement("request"); - xrequest->SetAttribute("rtype", "notify"); - xrequest->SetAttribute("message", "authfinished"); - doc->LinkEndChild(xrequest); - - add_raw_request(doc); -} - -/** - * Called only in the main thread, indirectly from auth_finished_sub_thread(), - * as the result of the user closing the auth dialog. - */ -void P3DInstance:: -auth_finished_main_thread() { - // Set this flag to indicate that the user has clicked on the red "auth" - // button. This eliminates the need to click on the green "start" button. - _auth_button_clicked = true; - - // After the authorization program has returned, check the signature again. - check_p3d_signature(); -} - -/** - * Stops the instance (if it is running) and deletes any packages referenced - * by the instance. This is normally called by JavaScript, via - * P3DMainObject::call_uninstall(). - */ -bool P3DInstance:: -uninstall_packages() { - if (_packages.empty()) { - // If we have no packages (for instance, because we're untrusted), we - // can't uninstall anything. - nout << "Uninstall failed: no packages.\n"; - return false; - } - - nout << "Uninstalling " << _packages.size() << " packages\n"; - - Packages::const_iterator pi; - for (pi = _packages.begin(); pi != _packages.end(); ++pi) { - P3DPackage *package = (*pi); - if (package != _image_package && package != _certlist_package && - package != _p3dcert_package) { - package->uninstall(); - } - } - - // Also clean up the start directory, if we have a custom start dir. We - // won't do this if verify_contents is 'none'. - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (inst_mgr->get_verify_contents() != P3D_VC_never) { - string start_dir_suffix = get_start_dir_suffix(); - if (!start_dir_suffix.empty()) { - string start_dir = inst_mgr->get_start_dir() + start_dir_suffix; - nout << "Cleaning up start directory " << start_dir << "\n"; - inst_mgr->delete_directory_recursively(start_dir); - } - } - - return true; -} - -/** - * Stops the instance (if it is running) and deletes all packages downloaded - * from any of the host(s) referenced by the instance. This is a more - * aggressive uninstall than uninstall_packages(). This is normally called by - * JavaScript, via P3DMainObject::call_uninstall(). - */ -bool P3DInstance:: -uninstall_host() { - if (_packages.empty()) { - // If we have no packages (for instance, because we're untrusted), we - // can't uninstall anything. - nout << "Uninstall failed: no packages.\n"; - return false; - } - - uninstall_packages(); - - // Collect the set of hosts referenced by this instance. - std::set hosts; - Packages::const_iterator pi; - for (pi = _packages.begin(); pi != _packages.end(); ++pi) { - P3DPackage *package = (*pi); - if (package != _image_package && package != _certlist_package && - package != _p3dcert_package) { - hosts.insert(package->get_host()); - } - } - nout << "Uninstalling " << hosts.size() << " hosts\n"; - - // Uninstall all of them. - std::set::iterator hi; - for (hi = hosts.begin(); hi != hosts.end(); ++hi) { - P3DHost *host = (*hi); - host->uninstall(); - } - - return true; -} - -/** - * The private implementation of set_p3d_filename(), this does all the work - * except for updating p3d_basename. It is intended to be called internally, - * and might be passed a temporary filename. - */ -void P3DInstance:: -priv_set_p3d_filename(const string &p3d_filename, const int &p3d_offset) { - if (!_fparams.get_p3d_filename().empty()) { - nout << "p3d_filename already set to: " << _fparams.get_p3d_filename() - << ", trying to set to " << p3d_filename << "\n"; - return; - } - - _fparams.set_p3d_filename(p3d_filename); - // The default for p3d_offset is -1, which means not to change it. - if (p3d_offset >= 0) { - _fparams.set_p3d_offset(p3d_offset); - } - _got_fparams = true; - - _main_object->set_float_property("instanceDownloadProgress", 1.0); - - // Generate a special notification: onpluginload, indicating the plugin has - // read its parameters and is ready to be queried (even if Python has not - // yet started). - send_notify("onpluginload"); - - if (!_mf_reader.open_read(_fparams.get_p3d_filename(), _fparams.get_p3d_offset())) { - if (_fparams.get_p3d_offset() == 0) { - nout << "Couldn't read " << _fparams.get_p3d_filename() << "\n"; - } else { - nout << "Couldn't read " << _fparams.get_p3d_filename() - << " at offset " << _fparams.get_p3d_offset() << "\n"; - } - set_failed(); - return; - } - - check_p3d_signature(); -} - -/** - * Determines _p3d_basename from the indicated URL. - */ -void P3DInstance:: -determine_p3d_basename(const string &p3d_url) { - string file_part = p3d_url; - size_t question = file_part.find('?'); - if (question != string::npos) { - file_part = file_part.substr(0, question); - } - size_t slash = file_part.rfind('/'); - if (slash != string::npos) { - file_part = file_part.substr(slash + 1); - } - _p3d_basename = file_part; - - nout << "p3d_basename = " << _p3d_basename << "\n"; -} - -/** - * Returns true if the indicated origin_match string, one of either run_origin - * or script_origin from the p3d_info.xml file, matches the origin of the page - * that embedded the p3d file. - */ -bool P3DInstance:: -check_matches_origin(const string &origin_match) { - // First, separate the string up at the semicolons. - size_t p = 0; - size_t semicolon = origin_match.find(';'); - while (semicolon != string::npos) { - if (check_matches_origin_one(origin_match.substr(p, semicolon - p))) { - return true; - } - p = semicolon + 1; - semicolon = origin_match.find(';', p); - } - if (check_matches_origin_one(origin_match.substr(p))) { - return true; - } - - // It doesn't match any of the semicolon-delimited strings within - // origin_match. - return false; -} - -/** - * Called for each semicolon-delimited string within origin_match passed to - * check_matches_origin(). - */ -bool P3DInstance:: -check_matches_origin_one(const string &origin_match) { - // Do we have a protocol? - size_t p = 0; - size_t colon = origin_match.find(':'); - if (colon + 1 < origin_match.length() && origin_match[colon + 1] == '/') { - // Yes. It should therefore match the protocol we have in the origin. - string protocol = origin_match.substr(0, colon + 1); - if (!check_matches_component(_origin_protocol, protocol)) { - return false; - } - p = colon + 2; - // We'll support both http:hostname and http:hostname, in case the user is - // sloppy. - if (p < origin_match.length() && origin_match[p] == '/') { - ++p; - } - colon = origin_match.find(':', p); - } - - // Do we have a port? - if (colon < origin_match.length() && isdigit(origin_match[colon + 1])) { - // Yes. It should therefore match the port we have in the origin. - string port = origin_match.substr(colon + 1); - if (!check_matches_component(_origin_port, port)) { - return false; - } - } - - // The hostname should also match what we have in the origin. - string hostname = origin_match.substr(p, colon - p); - if (!check_matches_hostname(_origin_hostname, hostname)) { - return false; - } - - // Everything matches. - return true; -} - -/** - * Matches the hostname of check_matches_origin: the individual components of - * the hostname are matched independently, with '**.' allowed at the beginning - * to indicate zero or more prefixes. Returns true on match, false on - * failure. - */ -bool P3DInstance:: -check_matches_hostname(const string &orig, const string &match) { - // First, separate both strings up at the dots. - vector orig_components; - separate_components(orig_components, orig); - - vector match_components; - separate_components(match_components, match); - - // If the first component of match is "**", it means we accept any number, - // zero or more, of components at the beginning of the hostname. - if (!match_components.empty() && match_components[0] == "**") { - // Remove the leading "**" - match_components.erase(match_components.begin()); - // Then remove any extra components from the beginning of orig_components; - // we won't need to check them. - if (orig_components.size() > match_components.size()) { - size_t num_to_remove = orig_components.size() - match_components.size(); - orig_components.erase(orig_components.begin(), orig_components.begin() + num_to_remove); - } - } - - // Now match the remaining components one-to-one. - if (match_components.size() != orig_components.size()) { - return false; - } - - vector::const_iterator p = orig_components.begin(); - vector::const_iterator p2 = match_components.begin(); - - while (p != orig_components.end()) { - assert(p2 != match_components.end()); - if (!check_matches_component(*p, *p2)) { - return false; - } - ++p; - ++p2; - } - - assert(p2 == match_components.end()); - return true; -} - -/** - * Separates the indicated hostname into its components at the dots. - */ -void P3DInstance:: -separate_components(vector &components, const string &str) { - size_t p = 0; - size_t dot = str.find('.'); - while (dot != string::npos) { - components.push_back(str.substr(p, dot - p)); - p = dot + 1; - dot = str.find('.', p); - } - components.push_back(str.substr(p)); -} - -/** - * Matches a single component of check_matches_origin: either protocol or - * port, or a single component of the hostname. Case-insensitive, and - * supports the '*' wildcard operator to match the entire component. Returns - * true on match, false on failure. - */ -bool P3DInstance:: -check_matches_component(const string &orig, const string &match) { - if (match == "*") { - return true; - } - - // Case-insensitive compare. - if (orig.length() != match.length()) { - return false; - } - - string::const_iterator p = orig.begin(); - string::const_iterator p2 = match.begin(); - - while (p != orig.end()) { - assert(p2 != match.end()); - if (tolower(*p) != tolower(*p2)) { - return false; - } - ++p; - ++p2; - } - - assert(p2 == match.end()); - return true; -} - -/** - * Checks the signature(s) encoded in the p3d file, and looks to see if any of - * them are recognized. - * - * If the signature is recognized, calls mark_p3d_trusted(); otherwise, calls - * mark_p3d_untrusted(). - */ -void P3DInstance:: -check_p3d_signature() { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (inst_mgr->get_trusted_environment()) { - // If we're in a trusted environment (e.g. the panda3d command line, - // where we've already downloaded the p3d file separately), then - // everything is approved. - mark_p3d_trusted(); - return; - } - - // See if we've previously approved the certificate--any certificate--that's - // signing this p3d file. - int num_signatures = _mf_reader.get_num_signatures(); - for (int i = 0; i < num_signatures; ++i) { - const P3DMultifileReader::CertChain &chain = _mf_reader.get_signature(i); - - // Here's a certificate that has signed this multifile. - X509 *cert = chain[0]._cert; - - // Look up the certificate to see if we've stored a copy in our certs dir. - if (inst_mgr->find_cert(cert)) { - mark_p3d_trusted(); - return; - } - } - - // Check the list of pre-approved certificates. - if (_certlist_package == nullptr) { - // We have to go download this package. - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url()); - _certlist_package = host->get_package("certlist", "", "", ""); - if (_certlist_package != nullptr) { - _certlist_package->add_instance(this); - } - - // When the package finishes downloading, we will come back here. - return; - } - - if (!_certlist_package->get_ready() && !_certlist_package->get_failed()) { - // Wait for it to finish downloading. - return; - } - - // Couldn't find any approved certificates. - mark_p3d_untrusted(); - return; -} - -/** - * This is called internally when it has been determined that the p3d file - * can't (yet) be trusted, for instance because it lacks a signature, or - * because it is signed by an unrecognized certificate. This puts up the red - * "auth" button and waits for the user to approve the app before continuing. - */ -void P3DInstance:: -mark_p3d_untrusted() { - // Failed test. - nout << "p3d untrusted\n"; - if (is_failed()) { - return; - } - - if (_p3dcert_package == nullptr) { - // We have to go download this package. - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url()); - _p3dcert_package = host->get_package("p3dcert", "", "", ""); - if (_p3dcert_package != nullptr) { - _p3dcert_package->add_instance(this); - } - - // When the package finishes downloading, we will come back here. - return; - } - - if (_p3dcert_package->get_failed()) { - // Oh, too bad for us. We're dependent on this package which we weren't - // able to download for some reason. - set_failed(); - } - - if (!_p3dcert_package->get_ready()) { - // Wait for it to finish downloading. - return; - } - - // OK, we've got the authorization program; we can put up the red button - // now. - - // Notify JS that we've got no trust of the p3d file. - _main_object->set_bool_property("trusted", false); - send_notify("onunauth"); - set_background_image(IT_unauth); - set_button_image(IT_auth_ready); - make_splash_window(); -} - -/** - * This is called internally when it has been determined that the p3d file can - * be trusted and started. When this is called, the p3d file will be examined - * and made ready to start; it will not be started until this is called. - */ -void P3DInstance:: -mark_p3d_trusted() { - nout << "p3d trusted\n"; - // Only call this once. - if (_p3d_trusted) { - nout << "mark_p3d_trusted() called twice on " << _fparams.get_p3d_filename() - << "\n"; - return; - } - - // Extract the application desc file from the p3d file. - stringstream sstream; - if (!_mf_reader.extract_one(sstream, "p3d_info.xml")) { - nout << "No p3d_info.xml file found in " << _fparams.get_p3d_filename() << "\n"; - set_failed(); - - } else { - sstream.seekg(0); - TiXmlDocument doc; - sstream >> doc; - - scan_app_desc_file(&doc); - } - - // Now we've got no further need to keep the _mf_reader open. - _mf_reader.close(); - - // For the moment, all sessions will be unique. TODO: support multiple - // instances per session. - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - ostringstream strm; - strm << inst_mgr->get_unique_id(); - _session_key = strm.str(); - - // Notify JS that we've accepted the trust of the p3d file. - _main_object->set_bool_property("trusted", true); - send_notify("onauth"); - - // Now that we're all set up, grab the panda3d package. We need to examine - // this before we can start to download the remaining packages. - add_panda3d_package(); -} - -/** - * Reads the p3d_info.xml file at instance startup, to determine the set of - * required packages and so forth. - */ -void P3DInstance:: -scan_app_desc_file(TiXmlDocument *doc) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - TiXmlElement *xpackage = doc->FirstChildElement("package"); - if (xpackage == nullptr) { - return; - } - assert(_xpackage == nullptr); - _xpackage = (TiXmlElement *)xpackage->Clone(); - - TiXmlElement *xconfig = _xpackage->FirstChildElement("config"); - if (xconfig != nullptr) { - int hidden = 0; - if (xconfig->QueryIntAttribute("hidden", &hidden) == TIXML_SUCCESS) { - if (hidden != 0) { - _hidden = true; - } - } - - const char *log_basename = xconfig->Attribute("log_basename"); - if (log_basename != nullptr) { - _log_basename = log_basename; - } - - const char *prc_name = xconfig->Attribute("prc_name"); - if (prc_name != nullptr) { - _prc_name = prc_name; - } - - const char *start_dir = xconfig->Attribute("start_dir"); - if (start_dir != nullptr) { - _start_dir = start_dir; - } - - const char *run_origin = xconfig->Attribute("run_origin"); - if (run_origin != nullptr) { - _matches_run_origin = check_matches_origin(run_origin); - } - - const char *script_origin = xconfig->Attribute("script_origin"); - if (script_origin != nullptr) { - _matches_script_origin = check_matches_origin(script_origin); - } - - int allow_python_dev = 0; - if (xconfig->QueryIntAttribute("allow_python_dev", &allow_python_dev) == TIXML_SUCCESS) { - _allow_python_dev = (allow_python_dev != 0); - } - - int keep_user_env = 0; - if (xconfig->QueryIntAttribute("keep_user_env", &keep_user_env) == TIXML_SUCCESS) { - _keep_user_env = (keep_user_env != 0); - } - - int auto_start = 0; - if (xconfig->QueryIntAttribute("auto_start", &auto_start) == TIXML_SUCCESS) { - _auto_start = (auto_start != 0); - } - - int auto_install = 0; - if (xconfig->QueryIntAttribute("auto_install", &auto_install) == TIXML_SUCCESS) { - _auto_install = (auto_install != 0); - } - } - - nout << "_matches_run_origin = " << _matches_run_origin << "\n"; - nout << "_matches_script_origin = " << _matches_script_origin << "\n"; - - if (inst_mgr->get_trusted_environment()) { - // If we're in a trusted environment, it is as if the origin always - // matches. - _matches_run_origin = true; - _matches_script_origin = true; - } - - if (_auth_button_clicked) { - // But finally, if the user has already clicked through the red "auth" - // button, no need to present himher with another green "play" button as - // well. - _auto_install = true; - _auto_start = true; - } - - nout << "_auto_install = " << _auto_install - << ", _auto_start = " << _auto_start - << ", _stop_on_ready = " << _stop_on_ready - << "\n"; - - if (_hidden && _got_wparams) { - _wparams.set_window_type(P3D_WT_hidden); - } - - if (!_matches_run_origin) { - nout << "Cannot run " << _p3d_basename << " from origin " - << _origin_protocol << "//" << _origin_hostname - << ":" << _origin_port << "\n"; - set_failed(); - } -} - -/** - * Adds the "panda3d" package only. This package must be downloaded first, - * and its desc file examined, before we can begin downloading the other - * packages. - */ -void P3DInstance:: -add_panda3d_package() { - assert(!_packages_specified); - assert(_panda3d_package == nullptr); - if (_xpackage == nullptr) { - return; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - TiXmlElement *xrequires = _xpackage->FirstChildElement("requires"); - while (xrequires != nullptr) { - const char *name = xrequires->Attribute("name"); - const char *host_url = xrequires->Attribute("host"); - if (name != nullptr && host_url != nullptr && strcmp(name, "panda3d") == 0) { - const char *version = xrequires->Attribute("version"); - if (version == nullptr) { - version = ""; - } - const char *seq = xrequires->Attribute("seq"); - if (seq == nullptr) { - seq = ""; - } - P3DHost *host = inst_mgr->get_host(host_url); - add_package(name, version, seq, host); - return; - } - - xrequires = xrequires->NextSiblingElement("requires"); - } - - nout << "No panda3d package found in " << _fparams.get_p3d_filename() << "\n"; - set_failed(); -} - -/** - * Adds the set of packages required by this p3d file to the _packages member. - * If _auto_install is true, this will also start downloading them. - */ -void P3DInstance:: -add_packages() { - assert(!_packages_specified); - if (_xpackage == nullptr) { - return; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - TiXmlElement *xrequires = _xpackage->FirstChildElement("requires"); - while (xrequires != nullptr) { - const char *name = xrequires->Attribute("name"); - const char *host_url = xrequires->Attribute("host"); - if (name != nullptr && host_url != nullptr) { - const char *version = xrequires->Attribute("version"); - if (version == nullptr) { - version = ""; - } - const char *seq = xrequires->Attribute("seq"); - if (seq == nullptr) { - seq = ""; - } - P3DHost *host = inst_mgr->get_host(host_url); - add_package(name, version, seq, host); - } - - xrequires = xrequires->NextSiblingElement("requires"); - } - - _packages_specified = true; - - consider_start_download(); - - // Now that we've scanned the p3d file, and prepared the list of packages, - // it's safe to set the trusted flag. - _p3d_trusted = true; - - // If the packages are already downloaded, start the instance rolling. - if (get_packages_ready()) { - mark_download_complete(); - } -} - - -/** - * Looks in the p3d_info.xml file for the alt_host associated with the - * indicated host_url, if any. Returns empty string if there is no match. - */ -string P3DInstance:: -find_alt_host_url(const string &host_url, const string &alt_host) { - TiXmlElement *xhost = _xpackage->FirstChildElement("host"); - while (xhost != nullptr) { - const char *url = xhost->Attribute("url"); - if (url != nullptr && host_url == url) { - // This matches the host. Now do we have a matching alt_host keyword - // for this host? - TiXmlElement *xalt_host = xhost->FirstChildElement("alt_host"); - while (xalt_host != nullptr) { - const char *keyword = xalt_host->Attribute("keyword"); - if (keyword != nullptr && alt_host == keyword) { - const char *alt_host_url = xalt_host->Attribute("url"); - if (alt_host_url != nullptr) { - return alt_host_url; - } - } - xalt_host = xalt_host->NextSiblingElement("alt_host"); - } - } - xhost = xhost->NextSiblingElement("host"); - } - - return string(); -} - -/** - * Looks in the p3d_info.xml file for the auxiliary host information for the - * selected host. Some of this information is helpful to have before the host - * has read its own contents.xml file (particularly the host_dir - * specification). - */ -void P3DInstance:: -get_host_info(P3DHost *host) { - // We should only call this function if we haven't already read the host's - // more-authoritative contents.xml file. - assert(!host->has_contents_file()); - - TiXmlElement *xhost = _xpackage->FirstChildElement("host"); - while (xhost != nullptr) { - const char *url = xhost->Attribute("url"); - if (url != nullptr && host->get_host_url() == url) { - // Found the entry for this particular host. - host->read_xhost(xhost); - return; - } - xhost = xhost->NextSiblingElement("host"); - } - - // Didn't find an entry for this host; oh well. -} - -/** - * Determines the local path to the appropriate start directory for this - * instance, within the generic "start" directory. Returns empty string if - * this instance doesn't specify a custom start directory. - * - * If this is nonempty, it will begin with a slash--the intention is to append - * this to the end of the generic start_dir path. - */ -string P3DInstance:: -get_start_dir_suffix() const { - string start_dir_suffix; - - string start_dir = get_fparams().lookup_token("start_dir"); - if (start_dir.empty()) { - start_dir = _start_dir; - - if (!start_dir.empty()) { - // If the start_dir is taken from the p3d file (and not from the HTML - // tokens), then we also append the alt_host name to the start_dir, so - // that each alt_host variant will run in a different directory. - string alt_host = get_fparams().lookup_token("alt_host"); - if (!alt_host.empty()) { - start_dir += "_"; - start_dir += alt_host; - } - } - } - if (!start_dir.empty()) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - inst_mgr->append_safe_dir(start_dir_suffix, start_dir); - } - - return start_dir_suffix; -} - -/** - * Sends the XML sequence to inform the session of our browser's toplevel - * window object. - */ -void P3DInstance:: -send_browser_script_object() { - TiXmlDocument *doc = new TiXmlDocument; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "pyobj"); - xcommand->SetAttribute("op", "set_browser_script_object"); - if (_dom_object != nullptr) { - xcommand->LinkEndChild(_session->p3dobj_to_xml(_dom_object)); - } - - doc->LinkEndChild(xcommand); - - _session->send_command(doc); -} - -/** - * Creates a new P3D_request structure from the XML. Returns NULL if no - * request is needed. - */ -P3D_request *P3DInstance:: -make_p3d_request(TiXmlElement *xrequest) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3D_request *request = nullptr; - - const char *rtype = xrequest->Attribute("rtype"); - if (rtype != nullptr) { - if (strcmp(rtype, "notify") == 0) { - const char *message = xrequest->Attribute("message"); - if (message != nullptr) { - // A notify message from Python code. - request = new P3D_request; - request->_instance = nullptr; - request->_request_type = P3D_RT_notify; - request->_request._notify._message = strdup(message); - handle_notify_request(message); - } - - } else if (strcmp(rtype, "script") == 0) { - // We don't actually build a P3D_request for a script request; we always - // just handle it immediately. - const char *operation = xrequest->Attribute("operation"); - TiXmlElement *xobject = xrequest->FirstChildElement("object"); - const char *property_name = xrequest->Attribute("property_name"); - int needs_response = 0; - xrequest->Attribute("needs_response", &needs_response); - int unique_id = 0; - xrequest->Attribute("unique_id", &unique_id); - - P3D_object *value = nullptr; - TiXmlElement *xvalue = xrequest->FirstChildElement("value"); - if (xvalue != nullptr) { - value = _session->xml_to_p3dobj(xvalue); - } - if (value == nullptr) { - value = inst_mgr->new_none_object(); - } - - if (operation != nullptr && xobject != nullptr) { - P3D_object *object = _session->xml_to_p3dobj(xobject); - - if (property_name == nullptr) { - property_name = ""; - } - - handle_script_request(operation, object, property_name, value, - (needs_response != 0), unique_id); - } - - P3D_OBJECT_DECREF(value); - - } else if (strcmp(rtype, "drop_p3dobj") == 0) { - int object_id; - if (xrequest->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) { - // We no longer need to keep this reference. - _session->drop_p3dobj(object_id); - } - - } else if (strcmp(rtype, "stop") == 0) { - // A stop request from Python code. This is kind of weird, but OK. - request = new P3D_request; - request->_instance = nullptr; - request->_request_type = P3D_RT_stop; - - } else if (strcmp(rtype, "forget_package") == 0) { - const char *host_url = xrequest->Attribute("host_url"); - if (host_url != nullptr) { - // A Python-level request to remove a package from the cache. - request = new P3D_request; - request->_instance = nullptr; - request->_request_type = P3D_RT_forget_package; - request->_request._forget_package._host_url = strdup(host_url); - request->_request._forget_package._package_name = nullptr; - request->_request._forget_package._package_version = nullptr; - - const char *package_name = xrequest->Attribute("package_name"); - const char *package_version = xrequest->Attribute("package_version"); - if (package_name != nullptr) { - request->_request._forget_package._package_name = strdup(package_name); - if (package_version != nullptr) { - request->_request._forget_package._package_version = strdup(package_version); - } - } - } - - } else { - nout << "Ignoring request of type " << rtype << "\n"; - } - } - - if (request != nullptr) { - assert(request->_instance == nullptr); - request->_instance = this; - ref(); - } - return request; -} - -/** - * Called (in the main thread) when a notify request is received from the - * subprocess. - */ -void P3DInstance:: -handle_notify_request(const string &message) { - // We look for certain notify events that have particular meaning to this - // instance. - if (message == "onpythonload") { - // Once Python is up and running, we can get the actual main object from - // the Python side, and merge it with our own. - - TiXmlDocument *doc = new TiXmlDocument; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "pyobj"); - xcommand->SetAttribute("op", "get_panda_script_object"); - doc->LinkEndChild(xcommand); - TiXmlDocument *response = _session->command_and_response(doc); - - P3D_object *result = nullptr; - if (response != nullptr) { - TiXmlElement *xresponse = response->FirstChildElement("response"); - if (xresponse != nullptr) { - TiXmlElement *xvalue = xresponse->FirstChildElement("value"); - if (xvalue != nullptr) { - result = _session->xml_to_p3dobj(xvalue); - } - } - delete response; - } - - if (result != nullptr) { - if (_matches_script_origin) { - // We only actually merge the objects if this web page is allowed to - // call our scripting functions. - _main_object->set_pyobj(result); - } else { - // Otherwise, we just do a one-time application of the toplevel - // properties down to Python. - _main_object->apply_properties(result); - } - P3D_OBJECT_DECREF(result); - } - - _main_object->set_string_property("status", "starting"); - - } else if (message == "onwindowopen") { - // The process told us that it just successfully opened its window, for - // the first time. Hide the splash window. - _instance_window_opened = true; - if (_splash_window != nullptr) { - _splash_window->set_visible(false); - } - - // Guess we won't be using (most of) these images any more. - for (int i = 0; i < (int)IT_num_image_types; ++i) { - if (i != IT_active) { - _image_files[i].cleanup(); - } - } - - _main_object->set_string_property("status", "open"); - - } else if (message == "onwindowattach") { - // The graphics window has been attached to the browser frame (maybe - // initially, maybe later). Hide the splash window. - - // We don't actually hide the splash window immediately on OSX, because on - // that platform, we can hide it as soon as we render the first frame, - // avoiding an empty frame in that little period of time between the - // window opening and the first frame being drawn. - _instance_window_attached = true; -#ifndef __APPLE__ - if (_splash_window != nullptr) { - _splash_window->set_visible(false); - } -#endif // __APPLE__ - -#ifdef __APPLE__ - // Start a timer to update the frame repeatedly. This seems to be - // steadier than waiting for nullEvent. - if (_frame_timer == nullptr) { - CFRunLoopTimerContext timer_context; - memset(&timer_context, 0, sizeof(timer_context)); - timer_context.info = this; - _frame_timer = CFRunLoopTimerCreate - (nullptr, 0, 1.0 / 60.0, 0, 0, timer_callback, &timer_context); - CFRunLoopRef run_loop = CFRunLoopGetCurrent(); - CFRunLoopAddTimer(run_loop, _frame_timer, kCFRunLoopCommonModes); - } -#endif // __APPLE__ - - } else if (message == "onwindowdetach") { - // The graphics window has been removed from the browser frame. Restore - // the splash window. - _instance_window_opened = true; - _instance_window_attached = false; - set_background_image(IT_active); - if (_splash_window != nullptr) { - _splash_window->set_visible(true); - } - -#ifdef __APPLE__ - // Stop the frame timer; we don't need it any more. - if (_frame_timer != nullptr) { - CFRunLoopTimerInvalidate(_frame_timer); - CFRelease(_frame_timer); - _frame_timer = nullptr; - } -#endif // __APPLE__ - - } else if (message == "buttonclick") { - // We just got a special "button click" message from the sub-thread. This - // case is a little unusual, as it came from the splash window and not - // from Python (we presumably haven't even started Python yet). We use - // this as a sneaky way to forward the event from the sub-thread to the - // main thread. - splash_button_clicked_main_thread(); - - } else if (message == "authfinished") { - // Similarly for the "auth finished" message. - auth_finished_main_thread(); - - } else if (message == "keyboardfocus") { - if (_splash_window != nullptr) { - _splash_window->request_keyboard_focus(); - } - } -} - -/** - * Called (in the main thread) when a script request is received from the - * subprocess. - */ -void P3DInstance:: -handle_script_request(const string &operation, P3D_object *object, - const string &property_name, P3D_object *value, - bool needs_response, int unique_id) { - - TiXmlDocument *doc = new TiXmlDocument; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "script_response"); - xcommand->SetAttribute("unique_id", unique_id); - - doc->LinkEndChild(xcommand); - - if (operation == "get_property") { - P3D_object *result = P3D_OBJECT_GET_PROPERTY(object, property_name.c_str()); - - // We've got the property value; feed it back down to the subprocess. - - if (result != nullptr) { - xcommand->LinkEndChild(_session->p3dobj_to_xml(result)); - P3D_OBJECT_DECREF(result); - } - - } else if (operation == "set_property") { - bool result = - P3D_OBJECT_SET_PROPERTY(object, property_name.c_str(), true, value); - - TiXmlElement *xvalue = new TiXmlElement("value"); - xvalue->SetAttribute("type", "bool"); - xvalue->SetAttribute("value", (int)result); - xcommand->LinkEndChild(xvalue); - - } else if (operation == "del_property") { - bool result = P3D_OBJECT_SET_PROPERTY(object, property_name.c_str(), true, nullptr); - - TiXmlElement *xvalue = new TiXmlElement("value"); - xvalue->SetAttribute("type", "bool"); - xvalue->SetAttribute("value", (int)result); - xcommand->LinkEndChild(xvalue); - - } else if (operation == "has_method") { - bool result = P3D_OBJECT_HAS_METHOD(object, property_name.c_str()); - - TiXmlElement *xvalue = new TiXmlElement("value"); - xvalue->SetAttribute("type", "bool"); - xvalue->SetAttribute("value", (int)result); - xcommand->LinkEndChild(xvalue); - - } else if (operation == "call") { - // Convert the single value parameter into an array of parameters. - P3D_object **values = &value; - int num_values = 1; - if (value->_class == &P3DObject::_object_class) { - P3DObject *p3dobj = (P3DObject *)value; - if (p3dobj->get_object_array_size() != -1) { - values = p3dobj->get_object_array(); - num_values = p3dobj->get_object_array_size(); - } - } - - P3D_object *result = - P3D_OBJECT_CALL(object, property_name.c_str(), needs_response, - values, num_values); - - if (result != nullptr) { - xcommand->LinkEndChild(_session->p3dobj_to_xml(result)); - P3D_OBJECT_DECREF(result); - } - - } else if (operation == "eval") { - P3D_object *result; - int size = P3D_OBJECT_GET_STRING(value, nullptr, 0); - char *buffer = new char[size + 1]; - P3D_OBJECT_GET_STRING(value, buffer, size + 1); - result = P3D_OBJECT_EVAL(object, buffer); - delete[] buffer; - - if (result != nullptr) { - xcommand->LinkEndChild(_session->p3dobj_to_xml(result)); - P3D_OBJECT_DECREF(result); - } - } - - if (needs_response) { - _session->send_command(doc); - } else { - delete doc; - } -} - -/** - * Sets the "failed" indication to display sadness to the user--we're unable - * to launch the instance for some reason. - */ -void P3DInstance:: -set_failed() { - set_button_image(IT_none); - set_background_image(IT_failed); - _main_object->set_string_property("status", "failed"); - - if (!_failed) { - _failed = true; - make_splash_window(); - send_notify("onfail"); - } -} - -/** - * Creates the splash window to be displayed at startup, if it's time. - */ -void P3DInstance:: -make_splash_window() { - // Should we make the splash window visible? - bool make_visible = true; - if (_instance_window_opened) { - // Not once we've opened the main window. - make_visible = false; - } - - if (_wparams.get_window_type() != P3D_WT_embedded && - !_stuff_to_download && _auto_install && - (_auto_start || _stop_on_ready) && _p3d_trusted) { - // If it's a toplevel or fullscreen window, then we don't want a splash - // window unless we have stuff to download, or a button to display. - make_visible = false; - } - - if (is_failed()) { - // But, if we've failed to launch somehow, we need to let the user know. - make_visible = true; - } - - if (_splash_window != nullptr) { - // Already got one. - _splash_window->set_visible(make_visible); - return; - } - if (!_got_wparams) { - // Don't know where to put it yet. - return; - } - if (_wparams.get_window_type() == P3D_WT_hidden && !is_failed()) { - // We're hidden, and so is the splash window. (But if we've got a failure - // case to report, we don't care and create the splash window anyway.) - return; - } - - _splash_window = new SplashWindowType(this, make_visible); - - // Get the splash window colors. We must set these *before* we call - // set_wparams. - if (_fparams.has_token("fgcolor")) { - int r, g, b; - if (parse_color(r, g, b, _fparams.lookup_token("fgcolor"))) { - _splash_window->set_fgcolor(r, g, b); - } else { - nout << "parse failure on fgcolor " << _fparams.lookup_token("fgcolor") << "\n"; - } - } - if (_fparams.has_token("bgcolor")) { - int r, g, b; - if (parse_color(r, g, b, _fparams.lookup_token("bgcolor"))) { - _splash_window->set_bgcolor(r, g, b); - _splash_window->set_bar_bgcolor(r, g, b); - } else { - nout << "parse failure on bgcolor " << _fparams.lookup_token("bgcolor") << "\n"; - } - } - if (_fparams.has_token("barcolor")) { - int r, g, b; - if (parse_color(r, g, b, _fparams.lookup_token("barcolor"))) { - _splash_window->set_barcolor(r, g, b); - } else { - nout << "parse failure on barcolor " << _fparams.lookup_token("barcolor") << "\n"; - } - } - if (_fparams.has_token("bar_bgcolor")) { - int r, g, b; - if (parse_color(r, g, b, _fparams.lookup_token("bar_bgcolor"))) { - _splash_window->set_bar_bgcolor(r, g, b); - } else { - nout << "parse failure on bar_bgcolor " << _fparams.lookup_token("bar_bgcolor") << "\n"; - } - } - if (_fparams.has_token("bar_border")) { - int border = _fparams.lookup_token_int("bar_border"); - _splash_window->set_bar_border(border); - } - if (_fparams.has_token("bar_bottom")) { - int bottom = _fparams.lookup_token_int("bar_bottom"); - _splash_window->set_bar_bottom(bottom); - } - if (_fparams.has_token("bar_width")) { - string bar_width = _fparams.lookup_token("bar_width"); - char *endptr; - long width = strtol(bar_width.c_str(), &endptr, 10); - bool percent = false; - - if (*endptr == '%') { - percent = true; - ++endptr; - } - if (*endptr == '\0' && width >= 0 && width < 65536) { - _splash_window->set_bar_width((int)width, percent); - } else { - nout << "parse failure on bar_width " << bar_width << "\n"; - } - } - if (_fparams.has_token("bar_height")) { - string bar_height = _fparams.lookup_token("bar_height"); - char *endptr; - long height = strtol(bar_height.c_str(), &endptr, 10); - bool percent = false; - - if (*endptr == '%') { - percent = true; - ++endptr; - } - if (*endptr == '\0' && height >= 0 && height < 65536) { - _splash_window->set_bar_height((int)height, percent); - } else { - nout << "parse failure on bar_height " << bar_height << "\n"; - } - } - if (_fparams.has_token("font_family")) { - string family = _fparams.lookup_token("font_family"); - _splash_window->set_font_family(family); - } - if (_fparams.has_token("font_size")) { - int size = _fparams.lookup_token_int("font_size"); - _splash_window->set_font_size(size); - } - if (_fparams.has_token("font_style")) { - string style = _fparams.lookup_token("font_style"); - - if (style == "normal") { - _splash_window->set_font_style(P3DSplashWindow::FS_normal); - } else if (style == "oblique") { - _splash_window->set_font_style(P3DSplashWindow::FS_oblique); - } else if (style == "italic") { - _splash_window->set_font_style(P3DSplashWindow::FS_italic); - } else { - nout << "parse_failure on font_style " << style << "\n"; - } - } - if (_fparams.has_token("font_weight")) { - string weight = _fparams.lookup_token("font_weight"); - - if (weight == "normal") { - _splash_window->set_font_weight(400); - } else if (weight == "bold") { - _splash_window->set_font_weight(700); - } else if (weight == "bolder") { - _splash_window->set_font_weight(700); - } else if (weight == "lighter") { - _splash_window->set_font_weight(100); - } else if (weight.size() == 3 && - weight[0] >= '1' && weight[0] <= '9' && - weight[1] == '0' && weight[2] == '0') { - _splash_window->set_font_weight(((int)weight[0] - 48) * 100); - } else { - nout << "parse_failure on font_weight " << weight << "\n"; - } - } - - _splash_window->set_wparams(_wparams); - _splash_window->set_install_label(_install_label); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - // Go get the required images. - for (int i = 0; i < (int)IT_none; ++i) { - string token_keyword = string(_image_type_names[i]) + "_img"; - if (!_fparams.has_token(token_keyword) && i < (int)IT_auth_ready) { - token_keyword = "splash_img"; - } - - string image_url = _fparams.lookup_token(token_keyword); - if (image_url.empty()) { - // No specific image for this type is specified; get the default image. - // We do this via the P3DPackage interface, so we can use the cached - // version on disk if it's good. - _image_files[i]._use_standard_image = true; - - } else { - // We have an explicit image specified for this slot, so just download - // it directly. This one won't be cached locally (though the browser - // might be free to cache it). - _image_files[i]._use_standard_image = false; - _image_files[i]._filename.clear(); - - // Make a temporary file to receive the splash image. - assert(_image_files[i]._temp_filename == nullptr); - _image_files[i]._temp_filename = new P3DTemporaryFile(".jpg"); - - // Start downloading the requested image. - ImageDownload *download = new ImageDownload(this, i); - download->set_url(image_url); - download->set_filename(_image_files[i]._temp_filename->get_filename()); - - start_download(download); - } - } - - if (_current_background_image != IT_none) { - _splash_window->set_image_filename(_image_files[_current_background_image]._filename, P3DSplashWindow::IP_background); - } - - if (_current_button_image != IT_none) { - _splash_window->set_image_filename(_image_files[_current_button_image]._filename, P3DSplashWindow::IP_button_ready); - _splash_window->set_image_filename(_image_files[_current_button_image + 1]._filename, P3DSplashWindow::IP_button_rollover); - _splash_window->set_image_filename(_image_files[_current_button_image + 2]._filename, P3DSplashWindow::IP_button_click); - _splash_window->set_button_active(true); - } -} - -/** - * Specifies the particular image that should be displayed as the background - * image in the splash window. Specify IT_none to take the background image - * away. - */ -void P3DInstance:: -set_background_image(ImageType image_type) { - if (is_failed()) { - // Can't change the background again after we've failed. - return; - } - - if (image_type != _current_background_image) { - nout << "setting background to " << _image_type_names[image_type] - << ", splash_window = " << _splash_window << "\n"; - // Remove the previous image. - _image_files[_current_background_image]._image_placement = P3DSplashWindow::IP_none; - - // Install the new image. - _current_background_image = image_type; - if (_current_background_image != IT_none) { - _image_files[_current_background_image]._image_placement = P3DSplashWindow::IP_background; - } - - // Update the splash window. - if (_splash_window != nullptr) { - _splash_window->set_image_filename(_image_files[_current_background_image]._filename, P3DSplashWindow::IP_background); - } - } -} - -/** - * Specifies the particular image that should be displayed as the button image - * in the splash window. Specify IT_none to take the button image away. - * - * This actually defines a trilogy of button images: ready, rollover, click. - */ -void P3DInstance:: -set_button_image(ImageType image_type) { - if (is_failed()) { - // Can't set the button again after we've failed. - return; - } - - if (image_type != _current_button_image) { - nout << "setting button to " << _image_type_names[image_type] << "\n"; - // Remove the previous image. - _image_files[_current_button_image]._image_placement = P3DSplashWindow::IP_none; - if (_current_button_image != IT_none) { - _image_files[_current_button_image + 1]._image_placement = P3DSplashWindow::IP_none; - _image_files[_current_button_image + 2]._image_placement = P3DSplashWindow::IP_none; - } - - // Install the new image. - _current_button_image = image_type; - if (_current_button_image != IT_none) { - _image_files[_current_button_image]._image_placement = P3DSplashWindow::IP_button_ready; - _image_files[_current_button_image + 1]._image_placement = P3DSplashWindow::IP_button_rollover; - _image_files[_current_button_image + 2]._image_placement = P3DSplashWindow::IP_button_click; - } - - // Update the splash window. - if (_splash_window != nullptr) { - if (_current_button_image != IT_none) { - _splash_window->set_image_filename(_image_files[_current_button_image]._filename, P3DSplashWindow::IP_button_ready); - _splash_window->set_image_filename(_image_files[_current_button_image + 1]._filename, P3DSplashWindow::IP_button_rollover); - _splash_window->set_image_filename(_image_files[_current_button_image + 2]._filename, P3DSplashWindow::IP_button_click); - _splash_window->set_button_active(true); - } else { - _splash_window->set_button_active(false); - } - } - - } else { - // We're not changing the button graphic, but we might be re-activating - // it. - if (_splash_window != nullptr) { - if (_current_button_image != IT_none) { - _splash_window->set_button_active(true); - } else { - _splash_window->set_button_active(false); - } - } - } -} - -/** - * Notified when a package information has been successfully downloaded and - * the package is idle, waiting for activate_download() to be called. - */ -void P3DInstance:: -report_package_info_ready(P3DPackage *package) { - nout << "report_package_info_ready: " << package->get_package_name() << "\n"; - if (package == _image_package || package == _certlist_package || - package == _p3dcert_package) { - // A special case: these packages get immediately downloaded, without - // waiting for anything else. - if (package == _certlist_package || package == _p3dcert_package) { - // If we're downloading one of the two cert packages, though, put up a - // progress bar. - make_splash_window(); - if (_splash_window != nullptr) { - _splash_window->set_install_progress(0.0, true, 0); - } - if (package == _certlist_package) { - set_install_label("Getting Certificates"); - } else { - set_install_label("Getting Authorization Dialog"); - } - } - - package->activate_download(); - return; - } - - if (package == _panda3d_package && !_packages_specified) { - // Another special case. Once the special panda3d package is ready to - // download (and we know what platform it belongs to), we can begin to - // download the remaining required packages. - string package_platform = package->get_package_platform(); - if (!package_platform.empty() && _session_platform.empty()) { - // From now on, all platform-specific files downloaded by this session - // will be for this platform. - _session_platform = package_platform; - } - if (_session_platform != package_platform) { - nout << "Error: session is " << _session_platform - << ", but we somehow got panda3d for " << package_platform << "\n"; - set_failed(); - return; - } - - add_packages(); - } - - // Now that the package's info is ready, we know its set of required - // packages, and we can add these to the list. - P3DPackage::Requires::const_iterator ri; - for (ri = package->_requires.begin(); ri != package->_requires.end(); ++ri) { - const P3DPackage::RequiredPackage &rp = (*ri); - add_package(rp._package_name, rp._package_version, rp._package_seq, - rp._host); - } - - consider_start_download(); -} - -/** - * When all package info files have been obtained, begins downloading stuff. - */ -void P3DInstance:: -consider_start_download() { - if (get_packages_info_ready()) { - // All packages are ready to go. Let's start some download action. - _downloading_packages.clear(); - _prev_downloaded = 0; - _total_download_size = 0; - Packages::const_iterator pi; - for (pi = _packages.begin(); pi != _packages.end(); ++pi) { - P3DPackage *package = (*pi); - if (package->get_info_ready()) { - if (!package->get_ready()) { - _downloading_packages.push_back(package); - _total_download_size += package->get_download_size(); - } else { - _prev_downloaded += package->get_download_size(); - } - } - } - ready_to_install(); - } -} - -/** - * Called when it's time to start the package download process. - */ -void P3DInstance:: -ready_to_install() { - if (_downloading_packages.empty() && _download_complete) { - // We have already been here. Ignore it. - - } else if (!_auto_install && !_download_started) { - // Not authorized to download yet. We're waiting for the user to - // acknowledge the download. - set_background_image(IT_ready); - set_button_image(IT_play_ready); - - } else { - _download_started = true; - _download_complete = false; - _download_package_index = 0; - _total_downloaded = 0; - - // Record the time we started the package download, so we can report - // downloadElapsedTime and predict downloadRemainingTime. -#ifdef _WIN32 - _start_dl_tick = GetTickCount(); -#else - gettimeofday(&_start_dl_timeval, nullptr); -#endif - - nout << "Beginning install of " << _downloading_packages.size() - << " packages, total " << _total_download_size - << " bytes required (" << _prev_downloaded - << " previously downloaded).\n"; - - if (_downloading_packages.size() > 0) { - _stuff_to_download = true; - - // Maybe it's time to open a splash window now. - make_splash_window(); - } - - _main_object->set_string_property("status", "downloading"); - _main_object->set_int_property("numDownloadingPackages", _downloading_packages.size()); - _main_object->set_int_property("totalDownloadSize", _total_download_size); - _main_object->set_int_property("downloadElapsedSeconds", 0); - _main_object->set_undefined_property("downloadRemainingSeconds"); - - double progress = 0.0; - if (_prev_downloaded != 0) { - // We might start off with more than 0 progress, if we've already - // downloaded some of it previously. - progress = (_prev_downloaded) / (_total_download_size + _prev_downloaded); - progress = min(progress, 1.0); - - _main_object->set_float_property("downloadProgress", progress); - } - if (_splash_window != nullptr) { - _splash_window->set_install_progress(progress, true, 0); - } - - send_notify("ondownloadbegin"); - - start_next_download(); - } -} - -/** - * Checks whether all packages are ready and waiting to be downloaded; if so, - * starts the next package in sequence downloading. - */ -void P3DInstance:: -start_next_download() { - while (_download_package_index < (int)_downloading_packages.size()) { - P3DPackage *package = _downloading_packages[_download_package_index]; - if (package->get_failed()) { - send_notify("ondownloadfail"); - set_failed(); - return; - } - - if (!package->get_ready()) { - // This package is ready to download. Begin. - string name = package->get_formatted_name(); - _main_object->set_string_property("downloadPackageName", package->get_package_name()); - _main_object->set_string_property("downloadPackageDisplayName", name); - _main_object->set_int_property("downloadPackageNumber", _download_package_index + 1); - _main_object->set_int_property("downloadPackageSize", package->get_download_size()); - set_install_label("Installing " + name); - - nout << "Installing " << package->get_package_name() - << ", package " << _download_package_index + 1 - << " of " << _downloading_packages.size() - << ", " << package->get_download_size() - << " bytes.\n"; - - package->activate_download(); - send_notify("ondownloadnext"); - return; - } - - // This package has been downloaded. Move to the next. - _total_downloaded += package->get_download_size(); - ++_download_package_index; - } - - // Looks like we're all done downloading. Launch! - _downloading_packages.clear(); - - if (get_packages_ready()) { - mark_download_complete(); - } -} - -/** - * Called internally when all files needed to launch have been downloaded. - */ -void P3DInstance:: -mark_download_complete() { - if (_failed) { - return; - } - - if (!_download_complete) { - _download_complete = true; - _main_object->set_bool_property("downloadComplete", true); - _main_object->set_string_property("status", "downloadcomplete"); - send_notify("ondownloadcomplete"); - } - - // Take down the download progress bar. - if (_splash_window != nullptr) { - _splash_window->set_install_progress(0.0, true, 0); - } - set_install_label(""); - - if (_got_wparams && _p3d_trusted) { - ready_to_start(); - } -} - - -/** - * Called internally when we have got the wparams and fparams and we have - * downloaded all required packages. - */ -void P3DInstance:: -ready_to_start() { - if (_instance_started || is_failed()) { - // Already started--or never mind. - return; - } - - _main_object->set_string_property("status", "ready"); - send_notify("onready"); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (_stop_on_ready) { - // If we've got the "stop_on_ready" token, then exit abruptly now, instead - // of displaying the splash window. - request_stop_main_thread(); - return; - } - - if (_auto_start) { - set_background_image(IT_launch); - inst_mgr->start_instance(this); - - } else { - // We're fully downloaded, and waiting for the user to click play. - set_background_image(IT_ready); - set_button_image(IT_play_ready); - } -} - -/** - * Notified as the instance file is downloaded. - */ -void P3DInstance:: -report_instance_progress(double progress, bool is_progress_known, - size_t received_data) { - if (!_show_dl_instance_progress) { - // If we haven't yet set the download label, set it after a full second - // has elapsed. We don't want to set it too soon, because we're not - // really sure how long it will take to download (the instance file might - // be already in the browser cache). -#ifdef _WIN32 - int now = GetTickCount(); - double elapsed = (double)(now - _start_dl_tick) * 0.001; -#else - struct timeval now; - gettimeofday(&now, nullptr); - double elapsed = (double)(now.tv_sec - _start_dl_timeval.tv_sec) + - (double)(now.tv_usec - _start_dl_timeval.tv_usec) / 1000000.0; -#endif - - // Put up the progress bar after 2 seconds have elapsed, if we've still - // got some distance to go; or after 5 seconds have elapsed regardless. - if ((elapsed > 2.0 && progress < 0.7) || - (elapsed > 5.0)) { - _show_dl_instance_progress = true; - if (_fparams.has_token("p3d_install_label")) { - set_install_label(_fparams.lookup_token("p3d_install_label")); - } else { - set_install_label("Getting " + _p3d_basename); - } - } - } - - if (_splash_window != nullptr && _show_dl_instance_progress) { - _splash_window->set_install_progress(progress, is_progress_known, received_data); - } - _main_object->set_float_property("instanceDownloadProgress", progress); -} - -/** - * Notified as the packages required by the instance file are downloaded. - */ -void P3DInstance:: -report_package_progress(P3DPackage *package, double progress) { - if (package == _image_package) { - // Ignore this. - return; - } - if (package == _certlist_package || package == _p3dcert_package) { - // This gets its own progress bar. - if (_splash_window != nullptr) { - _splash_window->set_install_progress(progress, true, 0); - } - return; - } - - if (_download_package_index >= (int)_downloading_packages.size() || - package != _downloading_packages[_download_package_index]) { - // Quietly ignore a download progress report from an unexpected package. - return; - } - - // Scale the progress into the range appropriate to this package. - progress = (progress * package->get_download_size() + _total_downloaded + _prev_downloaded) / (_total_download_size + _prev_downloaded); - progress = min(progress, 1.0); - - if (_splash_window != nullptr) { - _splash_window->set_install_progress(progress, true, 0); - } - _main_object->set_float_property("downloadProgress", progress); - - static const size_t buffer_size = 256; - char buffer[buffer_size]; - - // Get the floating-point elapsed time. -#ifdef _WIN32 - int now = GetTickCount(); - double elapsed = (double)(now - _start_dl_tick) * 0.001; -#else - struct timeval now; - gettimeofday(&now, nullptr); - double elapsed = (double)(now.tv_sec - _start_dl_timeval.tv_sec) + - (double)(now.tv_usec - _start_dl_timeval.tv_usec) / 1000000.0; -#endif - - int ielapsed = (int)elapsed; - _main_object->set_int_property("downloadElapsedSeconds", ielapsed); - - sprintf(buffer, "%d:%02d", ielapsed / 60, ielapsed % 60); - _main_object->set_string_property("downloadElapsedFormatted", buffer); - - if (progress > 0 && (elapsed > 5.0 || progress > 0.2)) { - double this_total = elapsed / progress; - double this_remaining = max(this_total - elapsed, 0.0); - - // Age out any old time reports. - double old = elapsed - min(time_average, this_remaining); - while (!_time_reports.empty() && _time_reports.front()._report_time < old) { - TimeReport &tr0 = _time_reports.front(); - _total_time_reports -= tr0._total; - _time_reports.pop_front(); - } - if (_time_reports.empty()) { - _total_time_reports = 0.0; - } - - // Add a new time report. - TimeReport tr; - tr._total = this_total; - tr._report_time = elapsed; - _time_reports.push_back(tr); - _total_time_reports += tr._total; - - // Now get the average report. - if (!_time_reports.empty()) { - double total = _total_time_reports / (double)_time_reports.size(); - double remaining = max(total - elapsed, 0.0); - int iremaining = (int)(remaining + 0.5); - _main_object->set_int_property("downloadRemainingSeconds", iremaining); - sprintf(buffer, "%d:%02d", iremaining / 60, iremaining % 60); - _main_object->set_string_property("downloadRemainingFormatted", buffer); - } - } -} - -/** - * Notified when a required package is fully downloaded, or failed. - */ -void P3DInstance:: -report_package_done(P3DPackage *package, bool success) { - nout << "Done installing " << package->get_package_name() - << ": success = " << success << "\n"; - - if (package == _image_package) { - // A special case: we just downloaded the image package, so get the image - // files out of it and point them to the splash window. - string package_dir = package->get_package_dir(); - const TiXmlElement *xconfig = package->get_xconfig(); - if (xconfig == nullptr) { - nout << "No entry in image package\n"; - return; - } - package->mark_used(); - - for (int i = 0; i < (int)IT_none; ++i) { - if (_image_files[i]._use_standard_image) { - // This image indexes into the package. Go get the standard image - // filename. - string token = string(_image_type_names[i]) + "_img"; - const string *basename = xconfig->Attribute(token); - if (basename == nullptr) { - nout << "No entry in image package for " << token << "\n"; - } else { - string image_filename = package_dir + "/" + *basename; - _image_files[i]._filename = image_filename; - - // If the image should be on the window now, and the window still - // exists, put it up. - if (_splash_window != nullptr && - _image_files[i]._image_placement != P3DSplashWindow::IP_none) { - P3DSplashWindow::ImagePlacement image_placement = _image_files[i]._image_placement; - _splash_window->set_image_filename(image_filename, image_placement); - } - } - } - } - return; - } - - if (package == _certlist_package) { - // Another special case: successfully downloading certlist (or failing to - // download it) means we can finish checking the authenticity of the p3d - // file. - - package->mark_used(); - - // Take down the download progress. - if (_splash_window != nullptr) { - _splash_window->set_install_progress(0.0, true, 0); - } - set_install_label(""); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - inst_mgr->read_certlist(package); - check_p3d_signature(); - return; - } - - if (package == _p3dcert_package) { - // Another special case: successfully downloading p3dcert means we can - // enable the auth button. - - package->mark_used(); - - // Take down the download progress. - if (_splash_window != nullptr) { - _splash_window->set_install_progress(0.0, true, 0); - } - set_install_label(""); - mark_p3d_untrusted(); - return; - } - - if (success) { - report_package_progress(package, 1.0); - start_next_download(); - } else { - send_notify("ondownloadfail"); - set_failed(); - } -} - -/** - * Sets the install label that will be displayed on the splash window, if it - * is present. - */ -void P3DInstance:: -set_install_label(const string &install_label) { - _install_label = install_label; - if (_splash_window != nullptr) { - _splash_window->set_install_label(_install_label); - } -} - -/** - * Actually paints the rendered image to the browser window. This is only - * needed for OSX, where the child process isn't allowed to do it directly. - */ -void P3DInstance:: -paint_window() { -#ifdef __APPLE__ - const P3D_window_handle &handle = _wparams.get_parent_window(); - if (handle._window_handle_type == P3D_WHT_osx_port) { -#if !__LP64__ - paint_window_osx_port(); -#endif - - } else if (handle._window_handle_type == P3D_WHT_osx_cgcontext) { - const P3D_window_handle &handle = _wparams.get_parent_window(); - assert(handle._window_handle_type == P3D_WHT_osx_cgcontext); - CGContextRef context = handle._handle._osx_cgcontext._context; - - paint_window_osx_cgcontext(context); - } -#endif // __APPLE__ -} - -#if defined(__APPLE__) && !__LP64__ -/** - * Fills _reversed_buffer with the pixels from the current frame, suitable for - * rendering via the old QuickDraw interface. Returns true on success, or - * false if there is no Panda3D window visible. Only needed on OSX. - */ -bool P3DInstance:: -get_framebuffer_osx_port() { - if (_swbuffer == nullptr || !_instance_window_attached) { - // We don't have a Panda3D window yet. - return false; - } - - // blit rendered framebuffer into window backing store - int x_size = min(_wparams.get_win_width(), _swbuffer->get_x_size()); - int y_size = min(_wparams.get_win_height(), _swbuffer->get_y_size()); - size_t rowsize = _swbuffer->get_row_size(); - - if (_swbuffer->ready_for_read()) { - // Copy the new framebuffer image from the child process. - const void *framebuffer = _swbuffer->open_read_framebuffer(); - - // We have to reverse the image vertically first (different conventions - // between Panda and Mac). - for (int yi = 0; yi < y_size; ++yi) { -#ifndef __BIG_ENDIAN__ - // On a little-endian machine, we only have to reverse the order of the - // rows. - memcpy(_reversed_buffer + (y_size - 1 - yi) * rowsize, - (char *)framebuffer + yi * rowsize, - rowsize); - -#else // __BIG_ENDIAN__ - // On a big-endian machine, we need to do more work. - - // It appears that kBGRAPixelFormat, below, is ignored on big-endian - // machines, and it is treated as KARGBPixelFormat regardless of what we - // specify. Vexing. To compensate for this, we have to reverse the - // color channels ourselves on big-endian machines. - - const char *source = (const char *)framebuffer + yi * rowsize; - const char *stop = source + x_size * 4; - char *dest = (_reversed_buffer + (y_size - 1 - yi) * rowsize); - while (source < stop) { - char b = source[0]; - char g = source[1]; - char r = source[2]; - char a = source[3]; - dest[0] = a; - dest[1] = r; - dest[2] = g; - dest[3] = b; - dest += 4; - source += 4; - } -#endif - } - - _swbuffer->close_read_framebuffer(); - - if (_splash_window != nullptr && _splash_window->get_visible()) { - // If the splash window is up, time to hide it. We've just rendered a - // real frame. - _splash_window->set_visible(false); - } - - } else { - // No frame ready. Just re-paint the frame we had saved last time. - } - - return true; -} -#endif // __APPLE__ - -#ifdef __APPLE__ -/** - * Fills _reversed_buffer with the pixels from the current frame, suitable for - * rendering via the new CoreGraphics interface. Returns true on success, or - * false if there is no Panda3D window visible. Only needed on OSX. - */ -bool P3DInstance:: -get_framebuffer_osx_cgcontext() { - if (_swbuffer == nullptr || !_instance_window_attached) { - // We don't have a Panda3D window yet. - return false; - } - - // blit rendered framebuffer into window backing store - int x_size = min(_wparams.get_win_width(), _swbuffer->get_x_size()); - int y_size = min(_wparams.get_win_height(), _swbuffer->get_y_size()); - size_t rowsize = _swbuffer->get_row_size(); - - if (_swbuffer->ready_for_read()) { - // Copy the new framebuffer image from the child process. - const void *framebuffer = _swbuffer->open_read_framebuffer(); - memcpy(_reversed_buffer, framebuffer, y_size * rowsize); - _swbuffer->close_read_framebuffer(); - - if (_splash_window != nullptr && _splash_window->get_visible()) { - // If the splash window is up, time to hide it. We've just rendered a - // real frame. - _splash_window->set_visible(false); - } - - } else { - // No frame ready. Just re-paint the frame we had saved last time. - } - - return true; -} -#endif // __APPLE__ - -#if defined(__APPLE__) && !__LP64__ -/** - * Actually paints the rendered image to the browser window, using the OSX - * deprecated QuickDraw interfaces. - */ -void P3DInstance:: -paint_window_osx_port() { - if (!get_framebuffer_osx_port()) { - // No Panda3D window is showing. - return; - } - - int x_size = min(_wparams.get_win_width(), _swbuffer->get_x_size()); - int y_size = min(_wparams.get_win_height(), _swbuffer->get_y_size()); - size_t rowsize = _swbuffer->get_row_size(); - - Rect src_rect = {0, 0, (short)y_size, (short)x_size}; - Rect ddrc_rect = {0, 0, (short)y_size, (short)x_size}; - - QDErr err; - - GWorldPtr pGWorld; - err = NewGWorldFromPtr(&pGWorld, k32BGRAPixelFormat, &src_rect, 0, 0, 0, - _reversed_buffer, rowsize); - if (err != noErr) { - nout << " error in NewGWorldFromPtr, called from paint_window()\n"; - return; - } - - const P3D_window_handle &handle = _wparams.get_parent_window(); - assert(handle._window_handle_type == P3D_WHT_osx_port); - GrafPtr out_port = handle._handle._osx_port._port; - GrafPtr port_save = nullptr; - Boolean port_changed = QDSwapPort(out_port, &port_save); - - // Make sure the clipping rectangle isn't in the way. Is there a better way - // to eliminate the cliprect from consideration? - Rect r = { 0, 0, 0x7fff, 0x7fff }; - ClipRect(&r); - - CopyBits(GetPortBitMapForCopyBits(pGWorld), - GetPortBitMapForCopyBits(out_port), - &src_rect, &ddrc_rect, srcCopy, 0); - - if (port_changed) { - QDSwapPort(port_save, nullptr); - } - - DisposeGWorld(pGWorld); -} -#endif // __APPLE__ - -#ifdef __APPLE__ -/** - * Actually paints the rendered image to the browser window. This is the - * newer CoreGraphics implementation on OSX. - */ -void P3DInstance:: -paint_window_osx_cgcontext(CGContextRef context) { - if (!get_framebuffer_osx_cgcontext()) { - // No Panda3D window is showing. - return; - } - - int x_size = min(_wparams.get_win_width(), _swbuffer->get_x_size()); - int y_size = min(_wparams.get_win_height(), _swbuffer->get_y_size()); - - if (_buffer_image != nullptr) { - CGRect region = { { 0, 0 }, { (CGFloat)x_size, (CGFloat)y_size } }; - CGContextDrawImage(context, region, _buffer_image); - } -} -#endif // __APPLE__ - -/** - * Responds to the deprecated Carbon event types in Mac OSX. - */ -bool P3DInstance:: -handle_event_osx_event_record(const P3D_event_data &event) { - bool retval = false; - -#if defined(__APPLE__) && !__LP64__ - assert(event._event_type == P3D_ET_osx_event_record); - EventRecord *er = event._event._osx_event_record._event; - - Point pt = er->where; - - // Need to ensure we have the correct port set, in order to convert the - // mouse coordinates successfully via GlobalToLocal(). - const P3D_window_handle &handle = _wparams.get_parent_window(); - if (handle._window_handle_type == P3D_WHT_osx_port) { - GrafPtr out_port = handle._handle._osx_port._port; - GrafPtr port_save = nullptr; - Boolean port_changed = QDSwapPort(out_port, &port_save); - - GlobalToLocal(&pt); - - if (port_changed) { - QDSwapPort(port_save, nullptr); - } - } else { - // First, convert the coordinates from screen coordinates to browser - // window coordinates. - WindowRef window = handle._handle._osx_cgcontext._window; - CGPoint cgpt = { (CGFloat)pt.h, (CGFloat)pt.v }; - HIPointConvert(&cgpt, kHICoordSpaceScreenPixel, nullptr, - kHICoordSpaceWindow, window); - - // Then convert to plugin coordinates. - pt.h = (short)(cgpt.x - _wparams.get_win_x()); - pt.v = (short)(cgpt.y - _wparams.get_win_y()); - } - - SubprocessWindowBuffer::Event swb_event; - swb_event._source = SubprocessWindowBuffer::ES_none; - swb_event._type = SubprocessWindowBuffer::ET_none; - swb_event._code = 0; - swb_event._flags = 0; - add_carbon_modifier_flags(swb_event._flags, er->modifiers); - - bool trust_mouse_data = true; - - switch (er->what) { - case mouseDown: - swb_event._source = SubprocessWindowBuffer::ES_mouse; - swb_event._type = SubprocessWindowBuffer::ET_button_down; - retval = true; - break; - - case mouseUp: - swb_event._source = SubprocessWindowBuffer::ES_mouse; - swb_event._type = SubprocessWindowBuffer::ET_button_up; - retval = true; - break; - - case keyDown: - case keyUp: - case autoKey: - if (_swbuffer != nullptr) { - swb_event._source = SubprocessWindowBuffer::ES_keyboard; - swb_event._code = er->message; - if (er->what == keyUp) { - swb_event._type = SubprocessWindowBuffer::ET_button_up; - } else if (er->what == keyDown) { - swb_event._type = SubprocessWindowBuffer::ET_button_down; - } else { - swb_event._type = SubprocessWindowBuffer::ET_button_again; - } - retval = true; - } - break; - - case updateEvt: - paint_window(); - retval = true; - break; - - case activateEvt: - _mouse_active = ((er->modifiers & 1) != 0); - break; - - case osEvt: - // The mouse data sent with an "os event" seems to be in an indeterminate - // space. - trust_mouse_data = false; - break; - - default: - break; - } - - if (_mouse_active) { - swb_event._flags |= SubprocessWindowBuffer::EF_has_mouse; - if (trust_mouse_data) { - swb_event._x = pt.h; - swb_event._y = pt.v; - swb_event._flags |= SubprocessWindowBuffer::EF_mouse_position; - } - } - - if (_swbuffer != nullptr) { - _swbuffer->add_event(swb_event); - } -#endif // __APPLE__ - - return retval; -} - -/** - * Responds to the new Cocoa event types in Mac OSX. - */ -bool P3DInstance:: -handle_event_osx_cocoa(const P3D_event_data &event) { - bool retval = false; - -#ifdef __APPLE__ - assert(event._event_type == P3D_ET_osx_cocoa); - const P3DCocoaEvent &ce = event._event._osx_cocoa._event; - - SubprocessWindowBuffer::Event swb_event; - swb_event._source = SubprocessWindowBuffer::ES_none; - swb_event._type = SubprocessWindowBuffer::ET_none; - swb_event._code = 0; - swb_event._flags = 0; - - switch (ce.type) { - case P3DCocoaEventDrawRect: - { - CGContextRef context = ce.data.draw.context; - paint_window_osx_cgcontext(context); - retval = true; - } - break; - - case P3DCocoaEventMouseDown: - swb_event._source = SubprocessWindowBuffer::ES_mouse; - swb_event._type = SubprocessWindowBuffer::ET_button_down; - retval = true; - break; - - case P3DCocoaEventMouseUp: - swb_event._source = SubprocessWindowBuffer::ES_mouse; - swb_event._type = SubprocessWindowBuffer::ET_button_up; - retval = true; - break; - - case P3DCocoaEventKeyDown: - swb_event._source = SubprocessWindowBuffer::ES_keyboard; - swb_event._code = ce.data.key.keyCode << 8; - if (ce.data.key.isARepeat) { - swb_event._type = SubprocessWindowBuffer::ET_button_again; - } else { - swb_event._type = SubprocessWindowBuffer::ET_button_down; - if (ce.data.key.characters[0] > 0 & ce.data.key.characters[0] < 0x100) { - swb_event._code |= ce.data.key.characters[0]; - } - } - _modifiers = ce.data.key.modifierFlags; - retval = true; - break; - - case P3DCocoaEventKeyUp: - swb_event._source = SubprocessWindowBuffer::ES_keyboard; - swb_event._type = SubprocessWindowBuffer::ET_button_up; - swb_event._code = ce.data.key.keyCode << 8; - _modifiers = ce.data.key.modifierFlags; - retval = true; - break; - - case P3DCocoaEventFlagsChanged: - _modifiers = ce.data.key.modifierFlags; - retval = true; - break; - - case P3DCocoaEventFocusChanged: - _mouse_active = (ce.data.focus.hasFocus != 0); - retval = true; - break; - } - - add_cocoa_modifier_flags(swb_event._flags, _modifiers); - - switch (ce.type) { - case P3DCocoaEventMouseDown: - case P3DCocoaEventMouseMoved: - case P3DCocoaEventMouseDragged: - swb_event._x = (int)ce.data.mouse.pluginX; - swb_event._y = (int)ce.data.mouse.pluginY; - swb_event._flags |= SubprocessWindowBuffer::EF_mouse_position; - } - - if (_mouse_active) { - swb_event._flags |= SubprocessWindowBuffer::EF_has_mouse; - } - - if (_swbuffer != nullptr) { - _swbuffer->add_event(swb_event); - } -#endif // __APPLE__ - - return retval; -} - -/** - * OSX only: adds the appropriate bits to the Event flag bitmask to correspond - * to the modifier buttons held in the MacOS-style EventRecord::modifiers - * mask. - */ -void P3DInstance:: -add_carbon_modifier_flags(unsigned int &swb_flags, int modifiers) { -#if defined(__APPLE__) && !__LP64__ - if (modifiers & cmdKey) { - swb_flags |= SubprocessWindowBuffer::EF_meta_held; - } - if (modifiers & shiftKey) { - swb_flags |= SubprocessWindowBuffer::EF_shift_held; - } - if (modifiers & optionKey) { - swb_flags |= SubprocessWindowBuffer::EF_alt_held; - } - if (modifiers & controlKey) { - swb_flags |= SubprocessWindowBuffer::EF_control_held; - } -#endif // __APPLE__ -} - -/** - * OSX only: adds the appropriate bits to the Event flag bitmask to correspond - * to the modifier buttons held in the P3DCocoaEvent modifierFlags mask. - */ -void P3DInstance:: -add_cocoa_modifier_flags(unsigned int &swb_flags, int modifiers) { -#ifdef __APPLE__ - if (modifiers & NSCommandKeyMask) { - swb_flags |= SubprocessWindowBuffer::EF_meta_held; - } - if (modifiers & NSShiftKeyMask) { - swb_flags |= SubprocessWindowBuffer::EF_shift_held; - } - if (modifiers & NSAlternateKeyMask) { - swb_flags |= SubprocessWindowBuffer::EF_alt_held; - } - if (modifiers & NSControlKeyMask) { - swb_flags |= SubprocessWindowBuffer::EF_control_held; - } -#endif // __APPLE__ -} - -/** - * Generates a synthetic notify message here at the C++ level. - * - * Most notify messages are generated from within the Python code, and don't - * use this method; but a few have to be sent before Python has started, and - * those come through this method. - */ -void P3DInstance:: -send_notify(const string &message) { - nout << "send_notify(" << message << ")\n"; - P3D_request *request = new P3D_request; - request->_instance = nullptr; - request->_request_type = P3D_RT_notify; - request->_request._notify._message = strdup(message.c_str()); - add_baked_request(request); -} - -#ifdef __APPLE__ -/** - * OSX only: allocates the _swbuffer and associated support objects. If it - * was already allocated, deallocates the previous one first. - */ -void P3DInstance:: -alloc_swbuffer() { - free_swbuffer(); - - int x_size = _wparams.get_win_width(); - int y_size = _wparams.get_win_height(); - - _swbuffer = SubprocessWindowBuffer::new_buffer - (_shared_fd, _shared_mmap_size, _shared_filename, x_size, y_size); - if (_swbuffer != nullptr) { - _reversed_buffer = new char[_swbuffer->get_framebuffer_size()]; - memset(_reversed_buffer, 0, _swbuffer->get_row_size()); - size_t rowsize = _swbuffer->get_row_size(); - - _buffer_data = CFDataCreateWithBytesNoCopy(nullptr, (const UInt8 *)_reversed_buffer, - y_size * rowsize, kCFAllocatorNull); - - _data_provider = CGDataProviderCreateWithCFData(_buffer_data); - _buffer_color_space = CGColorSpaceCreateDeviceRGB(); - - _buffer_image = CGImageCreate(x_size, y_size, 8, 32, rowsize, _buffer_color_space, - kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, - _data_provider, nullptr, false, kCGRenderingIntentDefault); - - } -} -#endif // __APPLE__ - -#ifdef __APPLE__ -/** - * OSX only: releases the _swbuffer and associated support objects previously - * allocated by alloc_swbuffer(). - */ -void P3DInstance:: -free_swbuffer() { - if (_swbuffer != nullptr) { - SubprocessWindowBuffer::destroy_buffer(_shared_fd, _shared_mmap_size, - _shared_filename, _swbuffer); - _swbuffer = nullptr; - } - if (_reversed_buffer != nullptr) { - delete[] _reversed_buffer; - _reversed_buffer = nullptr; - } - - if (_buffer_image != nullptr) { - CGImageRelease(_buffer_image); - CGColorSpaceRelease(_buffer_color_space); - CGDataProviderRelease(_data_provider); - CFRelease(_buffer_data); - - _buffer_data = nullptr; - _data_provider = nullptr; - _buffer_color_space = nullptr; - _buffer_image = nullptr; - } -} -#endif // __APPLE__ - - -#ifdef __APPLE__ -/** - * OSX only: this callback is associated with a CFRunLoopTimer, to be called - * periodically for updating the frame. - */ -void P3DInstance:: -timer_callback(CFRunLoopTimerRef timer, void *info) { - P3DInstance *self = (P3DInstance *)info; - self->request_refresh(); -} -#endif // __APPLE__ - -/** - * - */ -P3DInstance::ImageDownload:: -ImageDownload(P3DInstance *inst, int index) : - _inst(inst), - _index(index) -{ -} - -/** - * Intended to be overloaded to generate a callback when the download - * finishes, either successfully or otherwise. The bool parameter is true if - * the download was successful. - */ -void P3DInstance::ImageDownload:: -download_finished(bool success) { - P3DFileDownload::download_finished(success); - if (success) { - // We've successfully downloaded the image (directly, not via the package - // interface). - _inst->_image_files[_index]._filename = get_filename(); - - // Put it onscreen if it's supposed to be onscreen now, and our splash - // window still exists. - if (_inst->_splash_window != nullptr && - _inst->_image_files[_index]._image_placement != P3DSplashWindow::IP_none) { - P3DSplashWindow::ImagePlacement image_placement = _inst->_image_files[_index]._image_placement; - _inst->_splash_window->set_image_filename(get_filename(), image_placement); - } - } -} - -/** - * - */ -P3DInstance::InstanceDownload:: -InstanceDownload(P3DInstance *inst) : - _inst(inst) -{ -} - -/** - * Intended to be overloaded to generate an occasional callback as new data - * comes in. - */ -void P3DInstance::InstanceDownload:: -download_progress() { - P3DFileDownload::download_progress(); - _inst->report_instance_progress(get_download_progress(), is_download_progress_known(), get_total_data()); -} - -/** - * Intended to be overloaded to generate a callback when the download - * finishes, either successfully or otherwise. The bool parameter is true if - * the download was successful. - */ -void P3DInstance::InstanceDownload:: -download_finished(bool success) { - P3DFileDownload::download_finished(success); - if (success) { - // We've successfully downloaded the instance data. - _inst->report_instance_progress(1.0, true, 0); - _inst->priv_set_p3d_filename(get_filename()); - } else { - // Oops, no joy on the instance data. - _inst->send_notify("ondownloadfail"); - _inst->set_failed(); - } -} diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h deleted file mode 100644 index 7972ef7fbe..0000000000 --- a/direct/src/plugin/p3dInstance.h +++ /dev/null @@ -1,385 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dInstance.h - * @author drose - * @date 2009-05-29 - */ - -#ifndef P3DINSTANCE_H -#define P3DINSTANCE_H - -#include "p3d_plugin_common.h" -#include "p3dFileDownload.h" -#include "p3dFileParams.h" -#include "p3dWindowParams.h" -#include "p3dReferenceCount.h" -#include "p3dSplashWindow.h" -#include "p3dTemporaryFile.h" -#include "p3dMultifileReader.h" -#include "get_tinyxml.h" - -#ifdef __APPLE__ -#include "subprocessWindowBuffer.h" -#include -#endif - -#ifndef _WIN32 -#include -#endif - -#include -#include - -class P3DSession; -class P3DSplashWindow; -class P3DDownload; -class P3DPackage; -class P3DObject; -class P3DMainObject; -class P3DTemporaryFile; - -/** - * This is an instance of a Panda3D window, as seen in the parent-level - * process. - */ -class P3DInstance : public P3D_instance, public P3DReferenceCount { -public: - P3DInstance(P3D_request_ready_func *func, - const P3D_token tokens[], size_t num_tokens, - int argc, const char *argv[], void *user_data); - ~P3DInstance(); - void cleanup(); - - void set_p3d_url(const std::string &p3d_url); - void set_p3d_filename(const std::string &p3d_filename, const int &p3d_offset = 0); - int make_p3d_stream(const std::string &p3d_url); - inline const P3DFileParams &get_fparams() const; - - void set_wparams(const P3DWindowParams &wparams); - inline const P3DWindowParams &get_wparams() const; - - P3D_object *get_panda_script_object() const; - void set_browser_script_object(P3D_object *object); - - bool has_request(); - P3D_request *get_request(); - void bake_requests(); - void add_raw_request(TiXmlDocument *doc); - void add_baked_request(P3D_request *request); - static void finish_request(P3D_request *request, bool handled); - - bool feed_url_stream(int unique_id, - P3D_result_code result_code, - int http_status_code, - size_t total_expected_data, - const unsigned char *this_data, - size_t this_data_size); - - bool handle_event(const P3D_event_data &event); - - inline int get_instance_id() const; - inline const std::string &get_session_key() const; - const std::string &get_log_pathname() const; - inline const std::string &get_session_platform() const; - - inline P3DSession *get_session() const; - - inline P3D_request_ready_func *get_request_ready_func() const; - - void add_package(const std::string &name, const std::string &version, - const std::string &seq, P3DHost *host); - void add_package(P3DPackage *package); - void remove_package(P3DPackage *package); - bool get_packages_info_ready() const; - bool get_packages_ready() const; - bool get_packages_failed() const; - - inline bool is_trusted() const; - inline bool get_matches_script_origin() const; - int start_download(P3DDownload *download, bool add_request = true); - inline bool is_started() const; - inline bool is_failed() const; - void request_stop_sub_thread(); - void request_stop_main_thread(); - void request_refresh(); - void request_callback(P3D_callback_func *func, void *data); - - TiXmlElement *make_xml(); - void splash_button_clicked_sub_thread(); - void splash_button_clicked_main_thread(); - void auth_button_clicked(); - void play_button_clicked(); - - void auth_finished_sub_thread(); - void auth_finished_main_thread(); - - bool uninstall_packages(); - bool uninstall_host(); - -private: - class ImageDownload : public P3DFileDownload { - public: - ImageDownload(P3DInstance *inst, int index); - protected: - virtual void download_finished(bool success); - private: - P3DInstance *_inst; - int _index; - }; - class InstanceDownload : public P3DFileDownload { - public: - InstanceDownload(P3DInstance *inst); - protected: - virtual void download_progress(); - virtual void download_finished(bool success); - private: - P3DInstance *_inst; - }; - - // The different kinds of image files we download for the splash window. - enum ImageType { - // Also update _image_type_names when you update this list. - IT_download, - IT_unauth, - IT_ready, - IT_failed, - IT_launch, - IT_active, - IT_auth_ready, - IT_auth_rollover, - IT_auth_click, - IT_play_ready, - IT_play_rollover, - IT_play_click, - IT_none, // Must be the last value - IT_num_image_types, // Not a real value - }; - - void priv_set_p3d_filename(const std::string &p3d_filename, const int &p3d_offset = -1); - void determine_p3d_basename(const std::string &p3d_url); - - bool check_matches_origin(const std::string &origin_match); - bool check_matches_origin_one(const std::string &origin_match); - bool check_matches_hostname(const std::string &orig, const std::string &match); - void separate_components(std::vector &components, const std::string &str); - bool check_matches_component(const std::string &orig, const std::string &match); - - void check_p3d_signature(); - void mark_p3d_untrusted(); - void mark_p3d_trusted(); - void scan_app_desc_file(TiXmlDocument *doc); - void add_panda3d_package(); - void add_packages(); - std::string find_alt_host_url(const std::string &host_url, const std::string &alt_host); - void get_host_info(P3DHost *host); - std::string get_start_dir_suffix() const; - - void send_browser_script_object(); - P3D_request *make_p3d_request(TiXmlElement *xrequest); - void handle_notify_request(const std::string &message); - void handle_script_request(const std::string &operation, P3D_object *object, - const std::string &property_name, P3D_object *value, - bool needs_response, int unique_id); - - void set_failed(); - void make_splash_window(); - void set_background_image(ImageType image_type); - void set_button_image(ImageType image_type); - void report_package_info_ready(P3DPackage *package); - void consider_start_download(); - void ready_to_install(); - void start_next_download(); - void mark_download_complete(); - void ready_to_start(); - void report_instance_progress(double progress, bool is_progress_known, - size_t received_data); - void report_package_progress(P3DPackage *package, double progress); - void report_package_done(P3DPackage *package, bool success); - void set_install_label(const std::string &install_label); - - void paint_window(); - -#ifdef __APPLE__ - bool get_framebuffer_osx_port(); - bool get_framebuffer_osx_cgcontext(); - void paint_window_osx_port(); - void paint_window_osx_cgcontext(CGContextRef context); -#endif // __APPLE__ - - bool handle_event_osx_event_record(const P3D_event_data &event); - bool handle_event_osx_cocoa(const P3D_event_data &event); - void add_carbon_modifier_flags(unsigned int &swb_flags, int modifiers); - void add_cocoa_modifier_flags(unsigned int &swb_flags, int modifiers); - - void send_notify(const std::string &message); - -#ifdef __APPLE__ - void alloc_swbuffer(); - void free_swbuffer(); - static void timer_callback(CFRunLoopTimerRef timer, void *info); -#endif // __APPLE__ - - P3D_request_ready_func *_func; - P3D_object *_dom_object; - P3DMainObject *_main_object; - std::string _p3d_basename; - std::string _origin_protocol; - std::string _origin_hostname; - std::string _origin_port; - - // We need a list of previous time reports so we can average the predicted - // download time over the past few seconds. - class TimeReport { - public: - double _total; - double _report_time; - }; - typedef std::deque TimeReports; - TimeReports _time_reports; - double _total_time_reports; - - P3DTemporaryFile *_temp_p3d_filename; - - // For downloading the various images used by the splash window. - P3DPackage *_image_package; - static const char *_image_type_names[IT_num_image_types]; - - class ImageFile { - public: - inline ImageFile(); - inline ~ImageFile(); - inline void cleanup(); - - bool _use_standard_image; - P3DTemporaryFile *_temp_filename; - std::string _filename; - P3DSplashWindow::ImagePlacement _image_placement; - }; - ImageFile _image_files[IT_num_image_types]; - ImageType _current_background_image; - ImageType _current_button_image; - - bool _got_fparams; - P3DFileParams _fparams; - P3DMultifileReader _mf_reader; - - bool _got_wparams; - P3DWindowParams _wparams; - - bool _p3d_trusted; - TiXmlElement *_xpackage; - - // Holds the list of certificates that are pre-approved by the plugin - // vendor. - P3DPackage *_certlist_package; - - // For downloading the p3dcert authorization program. - P3DPackage *_p3dcert_package; - - int _instance_id; - std::string _session_key; - std::string _log_basename; - std::string _session_platform; - std::string _prc_name; - std::string _start_dir; - bool _hidden; - bool _matches_run_origin; - bool _matches_script_origin; - bool _allow_python_dev; - bool _keep_user_env; - bool _auto_install; - bool _auto_start; - bool _stop_on_ready; - bool _auth_button_clicked; - bool _failed; - - P3DSession *_session; - P3DAuthSession *_auth_session; - std::string _log_pathname; - -#ifdef __APPLE__ - // On OSX, we have to get a copy of the framebuffer data back from the child - // process, and draw it to the window, here in the parent process. Crazy! - int _shared_fd; - size_t _shared_mmap_size; - std::string _shared_filename; - SubprocessWindowBuffer *_swbuffer; - char *_reversed_buffer; - CFDataRef _buffer_data; - CGDataProviderRef _data_provider; - CGColorSpaceRef _buffer_color_space; - CGImageRef _buffer_image; - - bool _mouse_active; - unsigned int _modifiers; - - CFRunLoopTimerRef _frame_timer; -#endif // __APPLE__ - - P3DSplashWindow *_splash_window; - std::string _install_label; - bool _instance_window_opened; - bool _instance_window_attached; - bool _stuff_to_download; - - // Keep track of when the download was started, for reporting purposes. - // These members are used both for the instance download, and for the later - // package download. -#ifdef _WIN32 - int _start_dl_tick; -#else - struct timeval _start_dl_timeval; -#endif - - // This is set false initially, but true if the instance download continues - // for more than a couple of seconds. - bool _show_dl_instance_progress; - - typedef std::vector Packages; - Packages _packages; - Packages _downloading_packages; - int _download_package_index; - size_t _prev_downloaded; - size_t _total_download_size; - size_t _total_downloaded; - bool _packages_specified; - bool _download_started; - bool _download_complete; - bool _instance_started; - - // We keep the _panda3d pointer separately because it's so important, but - // it's in the above vector also. - P3DPackage *_panda3d_package; - - typedef std::map Downloads; - Downloads _downloads; - - // The _raw_requests queue might be filled up by the read thread, so we - // protect it in a lock. - LOCK _request_lock; - typedef std::deque RawRequests; - RawRequests _raw_requests; - bool _requested_stop; - - // The _baked_requests queue is only touched in the main thread; no lock - // needed. - typedef std::deque BakedRequests; - BakedRequests _baked_requests; - - friend class P3DSession; - friend class P3DAuthSession; - friend class ImageDownload; - friend class InstanceDownload; - friend class P3DWindowParams; - friend class P3DPackage; -}; - -#include "p3dInstance.I" - -#endif diff --git a/direct/src/plugin/p3dInstanceManager.I b/direct/src/plugin/p3dInstanceManager.I deleted file mode 100644 index 3241fea0cf..0000000000 --- a/direct/src/plugin/p3dInstanceManager.I +++ /dev/null @@ -1,322 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dInstanceManager.I - * @author drose - * @date 2009-05-29 - */ - -/** - * Returns true if the instance manager is successfully initialized, false - * otherwise. - */ -inline bool P3DInstanceManager:: -is_initialized() const { - return _is_initialized; -} - -/** - * Recreates the runtime environment if a previous call to uninstall_all() - * removed it. Does nothing if the runtime environment is already correctly - * set up. - */ -inline void P3DInstanceManager:: -reconsider_runtime_environment() { - assert(_is_initialized); - if (!_created_runtime_environment) { - create_runtime_environment(); - } -} - -/** - * Returns the verify_contents setting. When this is set to P3D_VC_none, it - * indicates that we don't need to contact the server to verify that a - * contents.xml file is fresh before using it; we should just use it as it is. - */ -inline P3D_verify_contents P3DInstanceManager:: -get_verify_contents() const { - return _verify_contents; -} - -/** - * Resets the verify_contents flag to P3D_VC_normal, if it is P3D_VC_none. - * This should be done whenever we discover anything needs to be downloaded. - * At this point, we might as well verify everything. - */ -inline void P3DInstanceManager:: -reset_verify_contents() { - if (_verify_contents == P3D_VC_none) { - _verify_contents = P3D_VC_normal; - } -} - - -/** - * Returns the api_version number which was passed to P3D_initialize(). - * Client code may use this to determine how to interpret parameters to - * various functions whose interface may have changed over different versions. - */ -inline int P3DInstanceManager:: -get_api_version() const { - return _api_version; -} - -/** - * Returns the standard host_url which the instances should attempt to contact - * to download auxiliary packages associated with the core API, such as the - * p3dcert and images packages. This is normally the compiled-in - * PANDA_PACKAGE_HOST_URL, but it might be set to something different by the - * -u parameter on the panda3d executable. - */ -inline const std::string &P3DInstanceManager:: -get_host_url() const { - return _host_url; -} - -/** - * Returns the root directory into which all the P3D runtime files are - * downloaded and installed. This must be a writable directory or nothing - * will work. - */ -inline const std::string &P3DInstanceManager:: -get_root_dir() const { - return _root_dir; -} - -/** - * Returns the directory that the .p3d file should be mounted to and run from. - * This is usually the "start" subdirectory of the root_dir. - */ -inline const std::string &P3DInstanceManager:: -get_start_dir() const { - return _start_dir; -} - -/** - * Returns the string that corresponds to the platform on which we are - * running. This string will be used to determine the appropriate packages to - * download. - */ -inline const std::string &P3DInstanceManager:: -get_platform() const { - return _platform; -} - -/** - * Returns the pathname of the directory into which temporary files should be - * written. This filename will end with a slash, so that full pathnames may - * be made by concatenting directly with this string. - */ -inline const std::string &P3DInstanceManager:: -get_temp_directory() const { - return _temp_directory; -} - -/** - * Returns the pathname of the directory into which all log files should be - * written. This filename will end with a slash, so that full pathnames may - * be made by concatenting directly with this string. - */ -inline const std::string &P3DInstanceManager:: -get_log_directory() const { - return _log_directory; -} - -/** - * Returns the filename of the system log file; this file is responsible for - * downloading and installing updates, and launching applications. This is - * different from the session log file(s), which represent the output from a - * particular Python session. - */ -inline const std::string &P3DInstanceManager:: -get_log_pathname() const { - return _log_pathname; -} - -/** - * Returns the value of the trusted_environment flag passed to the - * constructor. If this is true, it means the environment we are running in - * is trusted and the p3d file is already vetted. This means the current - * working directory will remain unchanged, and the p3d file will be run - * without checking its signature. - * - * This should generally be true only when run by panda3d.exe or panda3dw.exe, - * and not when run by the web plugin. - */ -inline bool P3DInstanceManager:: -get_trusted_environment() const { - return _trusted_environment; -} - -/** - * Returns the value of the console_environment flag passed to the - * constructor. If this is true, it means we are running from a text-based - * console window, and not from a desktop environment. - * - * This should generally be true only when run by panda3d.exe, and not when - * run by the web plugin or by panda3dw.exe. - */ -inline bool P3DInstanceManager:: -get_console_environment() const { - return _console_environment; -} - -/** - * Returns the number of different supported platforms available in - * get_supported_platform(). - */ -inline int P3DInstanceManager:: -get_num_supported_platforms() const { - return (int)_supported_platforms.size(); -} - -/** - * Returns the nth supported platform, where 0 <= n < - * get_num_supported_platforms(). - * - * A given runtime environment may support multiple different platforms, e.g. - * win32 or win64, with the restriction that all platform-specific packages - * (beginning from panda3d), must be the same platform. - * - * This function enumerates the different platforms that the current runtime - * environment will support, in order of preference--preferred platforms - * appear first in the list. - */ -inline const std::string &P3DInstanceManager:: -get_supported_platform(int n) const { - return _supported_platforms.at(n); -} - -/** - * Returns the plugin's reported major version number. - */ -inline int P3DInstanceManager:: -get_plugin_major_version() const { - return _plugin_major_version; -} - -/** - * Returns the plugin's reported minor version number. - */ -inline int P3DInstanceManager:: -get_plugin_minor_version() const { - return _plugin_minor_version; -} - -/** - * Returns the plugin's reported sequence version number. - */ -inline int P3DInstanceManager:: -get_plugin_sequence_version() const { - return _plugin_sequence_version; -} - -/** - * Returns true if the plugin claims to be from an "official" build, and the - * its version number is authoritative; or false if it makes no such claim - * (for instance, it was built by someone checking out from cvs). - */ -inline bool P3DInstanceManager:: -get_plugin_official_version() const { - return _plugin_official_version; -} - -/** - * Returns the "distributor" reported by the plugin. This should represent - * the entity that built and hosted the plugin. - */ -inline const std::string &P3DInstanceManager:: -get_plugin_distributor() const { - return _plugin_distributor; -} - -/** - * Returns the host URL from which this Core API was downloaded (according to - * the plugin). This is for reporting purposes only; see get_host_url() for - * the URL to contact to actually download content. - */ -inline const std::string &P3DInstanceManager:: -get_coreapi_host_url() const { - return _coreapi_host_url; -} - -/** - * Returns the timestamp associated with this Core API DLL (according to the - * plugin). This is the timestamp shown in the contents.xml for this host, - * and is usually the time at which the plugin was built. - */ -inline time_t P3DInstanceManager:: -get_coreapi_timestamp() const { - return _coreapi_timestamp; -} - -/** - * Returns the version number associated with the Core API, if provided. Some - * early versions of the Core API, and some early versions of the plugin, did - * not provide a number here. If provided, this will be a string of dot- - * separated integers. - */ -inline const std::string &P3DInstanceManager:: -get_coreapi_set_ver() const { - return _coreapi_set_ver; -} - -/** - * Returns the "super mirror" URL. See p3d_plugin.h. - */ -inline const std::string &P3DInstanceManager:: -get_super_mirror() const { - return _super_mirror_url; -} - -/** - * Returns the number of instances currently running within the world. - */ -inline int P3DInstanceManager:: -get_num_instances() const { - return _instances.size(); -} - -/** - * Returns the singleton "undefined" object, as a new reference. - */ -inline P3D_object *P3DInstanceManager:: -new_undefined_object() { - P3D_OBJECT_INCREF(_undefined_object); - return _undefined_object; -} - -/** - * Returns the singleton "none" object, as a new reference. - */ -inline P3D_object *P3DInstanceManager:: -new_none_object() { - P3D_OBJECT_INCREF(_none_object); - return _none_object; -} - -/** - * Returns the singleton "true" or "false" object, as a new reference. - */ -inline P3D_object *P3DInstanceManager:: -new_bool_object(bool value) { - P3D_object *obj = (value) ? _true_object : _false_object; - P3D_OBJECT_INCREF(obj); - return obj; -} - -/** - * Returns the hex digit corresponding to the indicated integer value. - */ -inline char P3DInstanceManager:: -encode_hexdigit(int c) { - if (c >= 10) { - return c - 10 + 'a'; - } - return c + '0'; -} diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx deleted file mode 100644 index 93e2ffcfc2..0000000000 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ /dev/null @@ -1,1519 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dInstanceManager.cxx - * @author drose - * @date 2009-05-29 - */ - -#include "p3dInstanceManager.h" -#include "p3dInstance.h" -#include "p3dSession.h" -#include "p3dAuthSession.h" -#include "p3dHost.h" -#include "p3d_plugin_config.h" -#include "p3dWinSplashWindow.h" -#include "p3dUndefinedObject.h" -#include "p3dNoneObject.h" -#include "p3dBoolObject.h" -#include "p3dPackage.h" -#include "find_root_dir.h" -#include "fileSpec.h" -#include "get_tinyxml.h" -#include "binaryXml.h" -#include "mkdir_complete.h" -#include "wstring_encode.h" - -// We can include this header file to get the DTOOL_PLATFORM definition, even -// though we don't link with dtool. -#include "dtool_platform.h" - -#ifdef _WIN32 -#include -#include // chmod() -#include // rmdir() -#include // GetModuleHandle() etc. -#else -#include -#include -#include -#endif - -#ifdef __APPLE__ -#include -#endif - -#include - -using std::string; -using std::vector; -using std::wstring; - -static ofstream logfile; -std::ostream *nout_stream = &logfile; - -P3DInstanceManager *P3DInstanceManager::_global_ptr; - -/** - * - */ -P3DInstanceManager:: -P3DInstanceManager() { - init_xml(); - - _is_initialized = false; - _created_runtime_environment = false; - _api_version = 0; - _next_temp_filename_counter = 1; - _unique_id = 0; - _trusted_environment = false; - _console_environment = false; - - _plugin_major_version = 0; - _plugin_minor_version = 0; - _plugin_sequence_version = 0; - _plugin_official_version = false; - _coreapi_timestamp = 0; - - _notify_thread_continue = false; - _started_notify_thread = false; - INIT_THREAD(_notify_thread); - - // Initialize the singleton objects. - _undefined_object = new P3DUndefinedObject(); - _none_object = new P3DNoneObject(); - _true_object = new P3DBoolObject(true); - _false_object = new P3DBoolObject(false); - - _auth_session = nullptr; - - // Seed the lame random number generator in rand(); we use it to select a - // mirror for downloading. - srand((unsigned int)time(nullptr)); - -#ifdef _WIN32 - // Ensure the appropriate Windows common controls are available to this - // application. - INITCOMMONCONTROLSEX icc; - icc.dwSize = sizeof(icc); - icc.dwICC = ICC_PROGRESS_CLASS; - InitCommonControlsEx(&icc); -#endif - -#ifndef _WIN32 - // On Mac or Linux, we'd better ignore SIGPIPE, or this signal will shut - // down the browser if the plugin exits unexpectedly. - struct sigaction ignore; - memset(&ignore, 0, sizeof(ignore)); - ignore.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &ignore, &_old_sigpipe); -#endif // _WIN32 -} - -/** - * - */ -P3DInstanceManager:: -~P3DInstanceManager() { - if (_started_notify_thread) { - _notify_ready.acquire(); - _notify_thread_continue = false; - _notify_ready.notify(); - _notify_ready.release(); - JOIN_THREAD(_notify_thread); - _started_notify_thread = false; - } - -#ifndef _WIN32 - // Restore the original SIGPIPE handler. - sigaction(SIGPIPE, &_old_sigpipe, nullptr); -#endif // _WIN32 - - // force-finish any remaining instances. - while (!_instances.empty()) { - P3DInstance *inst = *(_instances.begin()); - finish_instance(inst); - } - - assert(_sessions.empty()); - assert(_instances.empty()); - - if (_auth_session != nullptr) { - p3d_unref_delete(_auth_session); - _auth_session = nullptr; - } - - Hosts::iterator hi; - for (hi = _hosts.begin(); hi != _hosts.end(); ++hi) { - delete (*hi).second; - } - _hosts.clear(); - - // Delete any remaining temporary files. - TempFilenames::iterator ti; - for (ti = _temp_filenames.begin(); ti != _temp_filenames.end(); ++ti) { - const string &filename = (*ti); - nout << "Removing delinquent temp file " << filename << "\n"; - unlink(filename.c_str()); - } - _temp_filenames.clear(); - - nout << "counts: " << _undefined_object->_ref_count - << " " << _none_object->_ref_count - << " " << _true_object->_ref_count - << " " << _false_object->_ref_count - << "\n"; - - /* - assert(_undefined_object->_ref_count == 1); - assert(_none_object->_ref_count == 1); - assert(_true_object->_ref_count == 1); - assert(_false_object->_ref_count == 1); - */ - - P3D_OBJECT_DECREF(_undefined_object); - P3D_OBJECT_DECREF(_none_object); - P3D_OBJECT_DECREF(_true_object); - P3D_OBJECT_DECREF(_false_object); - -#ifdef _WIN32 - P3DWinSplashWindow::unregister_window_class(); -#endif -} - -/** - * Called by the plugin host at application startup. It returns true if the - * DLL is successfully initialized, false if it should be immediately shut - * down and redownloaded. - */ -bool P3DInstanceManager:: -initialize(int api_version, const string &contents_filename, - const string &host_url, P3D_verify_contents verify_contents, - const string &platform, const string &log_directory, - const string &log_basename, bool trusted_environment, - bool console_environment, - const string &root_dir, const string &host_dir, - const string &start_dir) { - _api_version = api_version; - _host_url = host_url; - _verify_contents = verify_contents; - _platform = platform; - _log_directory = log_directory; - _log_basename = log_basename; - _trusted_environment = trusted_environment; - _console_environment = console_environment; - - if (_host_url.empty()) { - _host_url = PANDA_PACKAGE_HOST_URL; - } - - if (_platform.empty()) { - // If the platform is compiled in (as opposed to passed in by the caller), - // we might in fact support multiple platforms. - _platform = DTOOL_PLATFORM; -#ifdef _WIN32 - if (_platform == "win_amd64") { - _supported_platforms.push_back("win_amd64"); - _supported_platforms.push_back("win_i386"); - _supported_platforms.push_back("win32"); - - } else if (_platform == "win_i386" || _platform == "win32") { - // This is a WIN32 process, but determine if the underlying OS actually - // supports WIN64. - if (supports_win64()) { - _supported_platforms.push_back("win_amd64"); - } - _supported_platforms.push_back("win_i386"); - _supported_platforms.push_back("win32"); - } -#elif defined(__APPLE__) - if (_platform == "osx_amd64") { - _supported_platforms.push_back("osx_amd64"); - _supported_platforms.push_back("osx_i386"); - - } else if (_platform == "osx_i386") { - // This is a 32-bit process, but determine if the underlying OS supports - // 64-bit. - - int mib[2] = { CTL_HW, HW_MACHINE }; - char machine[512]; - size_t len = 511; - if (sysctl(mib, 2, (void *)machine, &len, nullptr, 0) == 0) { - if (strcmp(machine, "x86_64") == 0) { - _supported_platforms.push_back("osx_amd64"); - } - } - - _supported_platforms.push_back("osx_i386"); - } -#endif // _WIN32 - - // TODO: Linux multiplatform support. Just add the appropriate platform - // strings to _supported_platforms. - } else { - nout << "Platform string was set by plugin to " << _platform << "\n"; - } - - if (_supported_platforms.empty()) { - // Hack for older plug-ins, which should still remain compatible with - // newer versions of the runtime distribution. - if (_platform == "win32") { - _supported_platforms.push_back("win_i386"); - } - - // We always support at least the specific platform on which we're - // running. - _supported_platforms.push_back(_platform); - } - -#ifdef P3D_PLUGIN_LOG_DIRECTORY - if (_log_directory.empty()) { - _log_directory = P3D_PLUGIN_LOG_DIRECTORY; - } -#endif - -#ifdef P3D_PLUGIN_LOG_BASENAME2 - if (_log_basename.empty()) { - _log_basename = P3D_PLUGIN_LOG_BASENAME2; - } -#endif - if (_log_basename.empty()) { - _log_basename = "p3dcore"; - } - - if (root_dir.empty()) { - _root_dir = find_root_dir(); - if (_root_dir.empty()) { - std::cerr << "Could not find root directory.\n"; - return false; - } - } else { - _root_dir = root_dir; - } - - _host_dir = host_dir; - - if (start_dir.empty()) { - _start_dir = _root_dir + "/start"; - } else { - _start_dir = start_dir; - } - - // Allow the caller (e.g. panda3d.exe) to specify a log directory. Or, - // allow the developer to compile one in. Failing that, we write logfiles - // to Panda3Dlog. - if (_log_directory.empty()) { - _log_directory = _root_dir + "/log"; - } - - // Ensure that the log directory ends with a slash. - if (!_log_directory.empty() && _log_directory[_log_directory.size() - 1] != '/') { -#ifdef _WIN32 - if (_log_directory[_log_directory.size() - 1] != '\\') -#endif - _log_directory += "/"; - } - - // Construct the logfile pathname. - _log_pathname = _log_directory; - _log_pathname += _log_basename; - _log_pathname += ".log"; - - create_runtime_environment(); - _is_initialized = true; - - if (!host_url.empty() && !contents_filename.empty()) { - // Attempt to pre-read the supplied contents.xml file, to avoid an - // unnecessary download later. - P3DHost *host = get_host(host_url); - if (!host->read_contents_file(contents_filename, false)) { - nout << "Couldn't read " << contents_filename << "\n"; - } - } - - nout << "Supported platforms:"; - for (size_t pi = 0; pi < _supported_platforms.size(); ++pi) { - nout << " " << _supported_platforms[pi]; - } - nout << "\n"; - - return true; -} - -/** - * Specifies the version of the calling plugin, for reporting to JavaScript - * and the like. - */ -void P3DInstanceManager:: -set_plugin_version(int major, int minor, int sequence, - bool official, const string &distributor, - const string &coreapi_host_url, - time_t coreapi_timestamp, - const string &coreapi_set_ver) { - reconsider_runtime_environment(); - _plugin_major_version = major; - _plugin_minor_version = minor; - _plugin_sequence_version = sequence; - _plugin_official_version = official; - _plugin_distributor = distributor; - - // The Core API "host URL" is both compiled in, and comes in externally; we - // trust the external source in the case of a conflict. - string internal_host_url = PANDA_PACKAGE_HOST_URL; - if (coreapi_host_url != internal_host_url) { - nout << "Warning! Downloaded Core API from " << coreapi_host_url - << ", but its internal URL was " << internal_host_url << "\n"; - } - _coreapi_host_url = coreapi_host_url; - if (_coreapi_host_url.empty()) { - _coreapi_host_url = internal_host_url; - } - - // The Core API timestamp is only available externally. - _coreapi_timestamp = coreapi_timestamp; - - // The Core API "set ver", or version, is both compiled in and comes in - // externally; for this one we trust the internal version in the case of a - // conflict. - string internal_set_ver = P3D_COREAPI_VERSION_STR; - if (coreapi_set_ver != internal_set_ver && !coreapi_set_ver.empty() && !internal_set_ver.empty()) { - nout << "Warning! contents.xml reports Core API version number " - << coreapi_set_ver << ", but its actual version number is " - << internal_set_ver << "\n"; - } - _coreapi_set_ver = internal_set_ver; - if (_coreapi_set_ver.empty()) { - _coreapi_set_ver = coreapi_set_ver; - } - - nout << "Plugin version: " - << _plugin_major_version << "." - << _plugin_minor_version << "." - << _plugin_sequence_version; - if (!_plugin_official_version) { - nout << "c"; - } - nout << "\n"; - nout << "Plugin distributor: " << _plugin_distributor << "\n"; - nout << "Core API host URL: " << _coreapi_host_url << "\n"; - nout << "Core API version: " << _coreapi_set_ver << "\n"; - - const char *timestamp_string = ctime(&_coreapi_timestamp); - if (timestamp_string == nullptr) { - timestamp_string = ""; - } - nout << "Core API date: " << timestamp_string << "\n"; -} - -/** - * Specifies the "super mirror" URL. See p3d_plugin.h. - */ -void P3DInstanceManager:: -set_super_mirror(const string &super_mirror_url) { - reconsider_runtime_environment(); - if (!super_mirror_url.empty()) { - nout << "super_mirror = " << super_mirror_url << "\n"; - } - _super_mirror_url = super_mirror_url; - - // Make sure it ends with a slash. - if (!_super_mirror_url.empty() && _super_mirror_url[_super_mirror_url.size() - 1] != '/') { - _super_mirror_url += '/'; - } -} - -/** - * Returns a newly-allocated P3DInstance with the indicated startup - * information. - */ -P3DInstance *P3DInstanceManager:: -create_instance(P3D_request_ready_func *func, - const P3D_token tokens[], size_t num_tokens, - int argc, const char *argv[], void *user_data) { - reconsider_runtime_environment(); - P3DInstance *inst = new P3DInstance(func, tokens, num_tokens, argc, argv, - user_data); - inst->ref(); - _instances.insert(inst); - - return inst; -} - -/** - * Sets the p3d_filename (or p3d_url) on a particular instance. - */ -bool P3DInstanceManager:: -set_p3d_filename(P3DInstance *inst, bool is_local, - const string &p3d_filename, const int &p3d_offset) { - if (inst->is_started()) { - nout << "Instance started twice: " << inst << "\n"; - return false; - } - if (is_local) { - inst->set_p3d_filename(p3d_filename, p3d_offset); - } else { - inst->set_p3d_url(p3d_filename); - } - - return true; -} - -/** - * Indicates an intention to transmit the p3d data as a stream. Should return - * a new unique stream ID to receive it. - */ -int P3DInstanceManager:: -make_p3d_stream(P3DInstance *inst, const string &p3d_url) { - if (inst->is_started()) { - nout << "Instance started twice: " << inst << "\n"; - return -1; - } - return inst->make_p3d_stream(p3d_url); -} - - -/** - * Actually starts the instance running on a particular session. This is - * called by the P3DInstance when it successfully loads its instance file. - */ -bool P3DInstanceManager:: -start_instance(P3DInstance *inst) { - if (inst->is_failed()) { - // Don't bother trying again. - return false; - } - - if (inst->is_started()) { - // Already started. - return true; - } - - P3DSession *session; - Sessions::iterator si = _sessions.find(inst->get_session_key()); - if (si == _sessions.end()) { - session = new P3DSession(inst); - session->ref(); - bool inserted = _sessions.insert(Sessions::value_type(session->get_session_key(), session)).second; - assert(inserted); - } else { - session = (*si).second; - } - - session->start_instance(inst); - - return inst->is_started(); -} - -/** - * Terminates and removes a previously-returned instance. - */ -void P3DInstanceManager:: -finish_instance(P3DInstance *inst) { - nout << "finish_instance: " << inst << "\n"; - Instances::iterator ii; - ii = _instances.find(inst); - if (ii != _instances.end()) { - _instances.erase(ii); - } - - Sessions::iterator si = _sessions.find(inst->get_session_key()); - if (si != _sessions.end()) { - P3DSession *session = (*si).second; - session->terminate_instance(inst); - - // If that was the last instance in this session, terminate the session. - if (session->get_num_instances() == 0) { - _sessions.erase(session->get_session_key()); - session->shutdown(); - p3d_unref_delete(session); - } - } - - inst->cleanup(); - p3d_unref_delete(inst); -} - -/** - * Creates a new P3DAuthSession object, to pop up a window for the user to - * authorize the certificate on this instance. Automatically terminates any - * previously-created P3DAuthSession. - */ -P3DAuthSession *P3DInstanceManager:: -authorize_instance(P3DInstance *inst) { - if (_auth_session != nullptr) { - // We only want one auth_session window open at a time, to minimize user - // confusion, so close any previous window. - _auth_session->shutdown(true); - p3d_unref_delete(_auth_session); - _auth_session = nullptr; - } - - _auth_session = new P3DAuthSession(inst); - _auth_session->ref(); - return _auth_session; -} - -/** - * Returns the P3DInstance pointer corresponding to the indicated P3D_instance - * if it is valid, or NULL if it is not. - */ -P3DInstance *P3DInstanceManager:: -validate_instance(P3D_instance *instance) { - Instances::iterator ii; - ii = _instances.find((P3DInstance *)instance); - if (ii != _instances.end()) { - return (*ii); - } - - return nullptr; -} - -/** - * If a request is currently pending on any instance, returns its pointer. - * Otherwise, returns NULL. - */ -P3DInstance *P3DInstanceManager:: -check_request() { - Instances::iterator ii; - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - P3DInstance *inst = (*ii); - if (inst->has_request()) { - return inst; - } - } - - return nullptr; -} - -/** - * Does not return until a request is pending on some instance, or until no - * instances remain, or until the indicated time in seconds has elapsed. Use - * check_request to retrieve the pending request. Due to the possibility of - * race conditions, it is possible for this function to return when there is - * in fact no request pending (another thread may have extracted the request - * first). - */ -void P3DInstanceManager:: -wait_request(double timeout) { -#ifdef _WIN32 - int stop_tick = int(GetTickCount() + timeout * 1000.0); -#else - struct timeval stop_time; - gettimeofday(&stop_time, nullptr); - - int seconds = (int)floor(timeout); - stop_time.tv_sec += seconds; - stop_time.tv_usec += (int)((timeout - seconds) * 1000.0); - if (stop_time.tv_usec > 1000) { - stop_time.tv_usec -= 1000; - ++stop_time.tv_sec; - } -#endif - - _request_ready.acquire(); - if (check_request() != nullptr) { - _request_ready.release(); - return; - } - if (_instances.empty()) { - _request_ready.release(); - return; - } - - // No pending requests; go to sleep. - _request_ready.wait(timeout); - - while (true) { -#ifdef _WIN32 - int remaining_ticks = stop_tick - GetTickCount(); - if (remaining_ticks <= 0) { - break; - } - timeout = remaining_ticks * 0.001; -#else - struct timeval now; - gettimeofday(&now, nullptr); - - struct timeval remaining; - remaining.tv_sec = stop_time.tv_sec - now.tv_sec; - remaining.tv_usec = stop_time.tv_usec - now.tv_usec; - - if (remaining.tv_usec < 0) { - remaining.tv_usec += 1000; - --remaining.tv_sec; - } - if (remaining.tv_sec < 0) { - break; - } - timeout = remaining.tv_sec + remaining.tv_usec * 0.001; -#endif - - if (check_request() != nullptr) { - _request_ready.release(); - return; - } - if (_instances.empty()) { - _request_ready.release(); - return; - } - - // No pending requests; go to sleep. - _request_ready.wait(timeout); - } - _request_ready.release(); -} - -/** - * Returns a (possibly shared) pointer to the indicated download host. - */ -P3DHost *P3DInstanceManager:: -get_host(const string &host_url) { - Hosts::iterator pi = _hosts.find(host_url); - if (pi != _hosts.end()) { - return (*pi).second; - } - - P3DHost *host = new P3DHost(host_url, _host_dir); - bool inserted = _hosts.insert(Hosts::value_type(host_url, host)).second; - assert(inserted); - - return host; -} - -/** - * Removes the indicated host from the cache. - */ -void P3DInstanceManager:: -forget_host(P3DHost *host) { - const string &host_url = host->get_host_url(); - - nout << "Forgetting host " << host_url << "\n"; - - // Hmm, this is a memory leak. But we allow it to remain, since it's an - // unusual circumstance (uninstalling), and it's safer to leak than to risk - // a floating pointer. - _hosts.erase(host_url); -} - -/** - * Returns a number used to uniquify different instances. This number is - * guaranteed to be different at each call, at least until the int space rolls - * over. - */ -int P3DInstanceManager:: -get_unique_id() { - ++_unique_id; - return _unique_id; -} - -/** - * May be called in any thread to indicate that a new P3D_request is available - * in the indicated instance. - */ -void P3DInstanceManager:: -signal_request_ready(P3DInstance *inst) { - if (inst->get_request_ready_func() != nullptr) { - // This instance requires asynchronous notifications of requests. Thus, - // we should tell the notify thread to wake up and make the callback. - _notify_ready.acquire(); - _notify_instances.push_back(inst); - _notify_ready.notify(); - _notify_ready.release(); - - // Oh, and we should spawn the thread if we haven't already. - if (!_started_notify_thread) { - _notify_thread_continue = true; - SPAWN_THREAD(_notify_thread, nt_thread_run, this); - _started_notify_thread = true; - } - } - - // Then, wake up the main thread, in case it's sleeping on wait_request(). - _request_ready.acquire(); - _request_ready.notify(); - _request_ready.release(); -} - -/** - * - */ -P3D_class_definition *P3DInstanceManager:: -make_class_definition() const { - P3D_class_definition *new_class = new P3D_class_definition(P3DObject::_generic_class); - // TODO: save this pointer so we can delete it on destruction. - return new_class; -} - -/** - * Constructs a new, unique temporary filename with the indicated extension. - * You should use the P3DTemporaryFilename interface instead of calling this - * method directly. - */ -string P3DInstanceManager:: -make_temp_filename(const string &extension) { - string result; - bool exists; - - do { - int tid; -#ifdef _WIN32 - tid = GetCurrentProcessId(); -#else - tid = getpid(); -#endif - if (tid == 0) { - tid = 1; - } - int hash = ((clock() + _next_temp_filename_counter) * ((time(nullptr) * tid) >> 8)) & 0xffffff; - ++_next_temp_filename_counter; - char hex_code[10]; - sprintf(hex_code, "%06x", hash); - - result = _temp_directory; - result += "p3d_"; - result += hex_code; - result += extension; - - exists = false; - if (_temp_filenames.find(result) != _temp_filenames.end()) { - // We've previously allocated this file. - exists = true; - - } else { - - // Check if the file exists on disk. -#ifdef _WIN32 - DWORD results = GetFileAttributes(result.c_str()); - if (results != -1) { - exists = true; - } - -#else // _WIN32 - struct stat this_buf; - if (stat(result.c_str(), &this_buf) == 0) { - exists = true; - } -#endif - } - - } while (exists); - - nout << "make_temp_filename: " << result << "\n"; - return result; -} - -/** - * Releases a temporary filename assigned earlier via make_temp_filename(). - * If the file exists, it will be removed. You should use the - * P3DTemporaryFilename interface instead of calling this method directly. - */ -void P3DInstanceManager:: -release_temp_filename(const string &filename) { - nout << "release_temp_filename: " << filename << "\n"; - _temp_filenames.erase(filename); - unlink(filename.c_str()); -} - -/** - * Looks for the particular certificate in the cache of recognized - * certificates. Returns true if it is found, false if not. - */ -bool P3DInstanceManager:: -find_cert(X509 *cert) { - // First, we need the DER representation. - string der = cert_to_der(cert); - - // If we've previously found this certificate, we don't have to hit disk - // again. - ApprovedCerts::iterator ci = _approved_certs.find(der); - if (ci != _approved_certs.end()) { - return true; - } - - // Well, we haven't found it already. Look for it on disk. For this, we - // hash the cert into a hex string. This is similar to OpenSSL's - // get_by_subject() approach, except we hash the whole cert, not just the - // subject. (Since we also store self-signed certs in this list, we can't - // trust the subject name alone.) - string this_cert_dir = get_cert_dir(cert); - nout << "looking in " << this_cert_dir << "\n"; - - vector contents; - scan_directory(this_cert_dir, contents); - - // Now look at each of the files in this directory and see if any of them - // matches the certificate. - vector::iterator si; - for (si = contents.begin(); si != contents.end(); ++si) { - string filename = this_cert_dir + "/" + (*si); - X509 *x509 = nullptr; - FILE *fp = nullptr; -#ifdef _WIN32 - wstring filename_w; - if (string_to_wstring(filename_w, filename)) { - fp = _wfopen(filename_w.c_str(), L"r"); - } -#else // _WIN32 - fp = fopen(filename.c_str(), "r"); -#endif // _WIN32 - if (fp != nullptr) { - x509 = PEM_read_X509(fp, nullptr, nullptr, (void *)""); - fclose(fp); - } - - if (x509 != nullptr) { - string der2 = cert_to_der(x509); - // We might as well save this cert in the table for next time, even if - // it's not the one we're looking for right now. - _approved_certs.insert(der2); - - if (der == der2) { - return true; - } - } - } - - // Nothing matched. - return false; -} - -/** - * Reads the pre-approved certificates in the certlist package and adds them - * to the in-memory cache. - */ -void P3DInstanceManager:: -read_certlist(P3DPackage *package) { - nout << "reading certlist in " << package->get_package_dir() << "\n"; - - vector contents; - scan_directory(package->get_package_dir(), contents); - - vector::iterator si; - for (si = contents.begin(); si != contents.end(); ++si) { - const string &basename = (*si); - if (basename.length() > 4) { - string suffix = basename.substr(basename.length() - 4); - if (suffix == ".pem" || suffix == ".crt") { - string filename = package->get_package_dir() + "/" + basename; - X509 *x509 = nullptr; - FILE *fp = nullptr; -#ifdef _WIN32 - wstring filename_w; - if (string_to_wstring(filename_w, filename)) { - fp = _wfopen(filename_w.c_str(), L"r"); - } -#else // _WIN32 - fp = fopen(filename.c_str(), "r"); -#endif // _WIN32 - if (fp != nullptr) { - x509 = PEM_read_X509(fp, nullptr, nullptr, (void *)""); - fclose(fp); - } - - if (x509 != nullptr) { - string der2 = cert_to_der(x509); - _approved_certs.insert(der2); - } - } - } - } -} - -/** - * Returns the directory searched for this particular certificate. - */ -string P3DInstanceManager:: -get_cert_dir(X509 *cert) { - string der = cert_to_der(cert); - - static const size_t hash_size = 16; - unsigned char md[hash_size]; - - MD5_CTX ctx; - MD5_Init(&ctx); - MD5_Update(&ctx, der.data(), der.size()); - MD5_Final(md, &ctx); - - string basename; - static const size_t keep_hash = 6; - for (size_t i = 0; i < keep_hash; ++i) { - int high = (md[i] >> 4) & 0xf; - int low = md[i] & 0xf; - basename += P3DInstanceManager::encode_hexdigit(high); - basename += P3DInstanceManager::encode_hexdigit(low); - } - - return _certs_dir + "/" + basename; -} - -/** - * Converts the indicated certificate to its binary DER representation. - */ -string P3DInstanceManager:: -cert_to_der(X509 *cert) { - int buffer_size = i2d_X509(cert, nullptr); - unsigned char *buffer = new unsigned char[buffer_size]; - unsigned char *p = buffer; - i2d_X509(cert, &p); - - string result((char *)buffer, buffer_size); - delete[] buffer; - - return result; -} - -/** - * Stops all active instances and removes *all* downloaded files from all - * hosts, and empties the current user's Panda3D directory as much as - * possible. - * - * This cannot remove the coreapi dll or directory on Windows. - */ -void P3DInstanceManager:: -uninstall_all() { - Instances::iterator ii; - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - P3DInstance *inst = (*ii); - inst->uninstall_host(); - } - - Hosts::iterator hi; - for (hi = _hosts.begin(); hi != _hosts.end(); ++hi) { - P3DHost *host = (*hi).second; - host->uninstall(); - } - - // Close the logfile so we can remove that too. - logfile.close(); - - if (!_root_dir.empty()) { - // This won't be able to delete the coreapi directory on Windows, because - // we're running that DLL right now. But it will delete everything else. - delete_directory_recursively(_root_dir); - } - - _created_runtime_environment = false; -} - -/** - * - */ -P3DInstanceManager *P3DInstanceManager:: -get_global_ptr() { - if (_global_ptr == nullptr) { - _global_ptr = new P3DInstanceManager; - } - return _global_ptr; -} - -/** - * This is called only at plugin shutdown time; it deletes the global instance - * manager pointer and clears it to NULL. - */ -void P3DInstanceManager:: -delete_global_ptr() { - if (_global_ptr != nullptr) { - delete _global_ptr; - _global_ptr = nullptr; - } -} - -/** - * Attempts to open the named filename as if it were a directory and looks for - * the non-hidden files within the directory. Fills the given vector up with - * the sorted list of filenames that are local to this directory. - * - * It is the user's responsibility to ensure that the contents vector is empty - * before making this call; otherwise, the new files will be appended to it. - * - * Returns true on success, false if the directory could not be read for some - * reason. - */ -bool P3DInstanceManager:: -scan_directory(const string &dirname, vector &contents) { -#ifdef _WIN32 - // Use Windows' FindFirstFile() FindNextFile() to walk through the list of - // files in a directory. - size_t orig_size = contents.size(); - - string match = dirname + "\\*.*"; - WIN32_FIND_DATAW find_data; - - wstring match_w; - string_to_wstring(match_w, match); - - HANDLE handle = FindFirstFileW(match_w.c_str(), &find_data); - if (handle == INVALID_HANDLE_VALUE) { - if (GetLastError() == ERROR_NO_MORE_FILES) { - // No matching files is not an error. - return true; - } - return false; - } - - do { - string filename; - wstring_to_string(filename, find_data.cFileName); - if (filename != "." && filename != "..") { - contents.push_back(filename); - } - } while (FindNextFileW(handle, &find_data)); - - bool scan_ok = (GetLastError() == ERROR_NO_MORE_FILES); - FindClose(handle); - - sort(contents.begin() + orig_size, contents.end()); - return scan_ok; - -#else // _WIN32 - // Use Posix's opendir() readdir() to walk through the list of files in a - // directory. - size_t orig_size = contents.size(); - - DIR *root = opendir(dirname.c_str()); - if (root == nullptr) { - return false; - } - - struct dirent *d; - d = readdir(root); - while (d != nullptr) { - if (d->d_name[0] != '.') { - contents.push_back(d->d_name); - } - d = readdir(root); - } - - closedir(root); - - sort(contents.begin() + orig_size, contents.end()); - return true; - -#endif // _WIN32 -} - -/** - * Fills up filename_contents with the list of all files (but not - * directories), and dirname_contents with the list of all directories, rooted - * at the indicated dirname and below. The filenames generated are relative - * to the root of the dirname, with slashes (not backslashes) as the directory - * separator character. - * - * Returns true on success, false if the original dirname wasn't a directory - * or something like that. - */ -bool P3DInstanceManager:: -scan_directory_recursively(const string &dirname, - vector &filename_contents, - vector &dirname_contents, - const string &prefix) { - vector dir_contents; - if (!scan_directory(dirname, dir_contents)) { - // Apparently dirname wasn't a directory. - return false; - } - - // Walk through the contents of dirname. - vector::const_iterator si; - for (si = dir_contents.begin(); si != dir_contents.end(); ++si) { - // Here's a particular file within dirname. Is it another directory, or - // is it a regular file? - string pathname = dirname + "/" + (*si); - string rel_filename = prefix + (*si); - if (scan_directory_recursively(pathname, filename_contents, - dirname_contents, rel_filename + "/")) { - // It's a directory, and it's just added its results to the contents. - dirname_contents.push_back(rel_filename); - - } else { - // It's not a directory, so assume it's an ordinary file, and add it to - // the contents. - filename_contents.push_back(rel_filename); - } - } - - return true; -} - -/** - * Deletes all of the files and directories in the named directory and below, - * like rm -rf. Use with extreme caution. - */ -void P3DInstanceManager:: -delete_directory_recursively(const string &root_dir) { - vector contents, dirname_contents; - if (!scan_directory_recursively(root_dir, contents, dirname_contents)) { - // Maybe it's just a single file, not a directory. Delete it. -#ifdef _WIN32 - wstring root_dir_w; - string_to_wstring(root_dir_w, root_dir); - // Windows can't delete a file if it's read-only. - _wchmod(root_dir_w.c_str(), 0644); - int result = _wunlink(root_dir_w.c_str()); -#else // _WIN32 - int result = unlink(root_dir.c_str()); -#endif // _WIN32 - if (result == 0) { - nout << "Deleted " << root_dir << "\n"; - } else { -#ifdef _WIN32 - result = _waccess(root_dir_w.c_str(), 0); -#else // _WIN32 - result = access(root_dir.c_str(), 0); -#endif // _WIN32 - if (result == 0) { - nout << "Could not delete " << root_dir << "\n"; - } - } - return; - } - - vector::iterator ci; - for (ci = contents.begin(); ci != contents.end(); ++ci) { - string filename = (*ci); - string pathname = root_dir + "/" + filename; - -#ifdef _WIN32 - wstring pathname_w; - string_to_wstring(pathname_w, pathname); - // Windows can't delete a file if it's read-only. - _wchmod(pathname_w.c_str(), 0644); - int result = _wunlink(pathname_w.c_str()); -#else // _WIN32 - int result = unlink(pathname.c_str()); -#endif // _WIN32 - if (result == 0) { - nout << " Deleted " << filename << "\n"; - } else { - nout << " Could not delete " << filename << "\n"; - } - } - - // Now delete all of the directories too. They're already in reverse order, - // so we remove deeper directories first. - for (ci = dirname_contents.begin(); ci != dirname_contents.end(); ++ci) { - string filename = (*ci); - string pathname = root_dir + "/" + filename; - -#ifdef _WIN32 - wstring pathname_w; - string_to_wstring(pathname_w, pathname); - _wchmod(pathname_w.c_str(), 0755); - int result = _wrmdir(pathname_w.c_str()); -#else // _WIN32 - int result = rmdir(pathname.c_str()); -#endif // _WIN32 - if (result == 0) { - nout << " Removed directory " << filename << "\n"; - } else { - nout << " Could not remove directory " << filename << "\n"; - } - } - - // Finally, delete the root directory itself. - string pathname = root_dir; -#ifdef _WIN32 - wstring pathname_w; - string_to_wstring(pathname_w, pathname); - _wchmod(pathname_w.c_str(), 0755); - int result = _wrmdir(pathname_w.c_str()); -#else // _WIN32 - int result = rmdir(pathname.c_str()); -#endif // _WIN32 - if (result == 0) { - nout << "Removed directory " << root_dir << "\n"; - } else { -#ifdef _WIN32 - result = _waccess(pathname_w.c_str(), 0); -#else // _WIN32 - result = access(pathname.c_str(), 0); -#endif // _WIN32 - if (result == 0) { - nout << "Could not remove directory " << root_dir << "\n"; - } - } -} - -/** - * Removes the first instance of the indicated file from the given list. - * Returns true if removed, false if it was not found. - * - * On Windows, the directory separator characters are changed from backslash - * to forward slash before searching in the list; so it is assumed that the - * list contains filenames with a forward slash used as a separator. - */ -bool P3DInstanceManager:: -remove_file_from_list(vector &contents, const string &filename) { -#ifdef _WIN32 - // Convert backslashes to slashes. - string clean_filename; - for (string::const_iterator pi = filename.begin(); - pi != filename.end(); - ++pi) { - if ((*pi) == '\\') { - clean_filename += '/'; - } else { - clean_filename += (*pi); - } - } -#else - const string &clean_filename = filename; -#endif // _WIN32 - - vector::iterator ci; - for (ci = contents.begin(); ci != contents.end(); ++ci) { - if ((*ci) == clean_filename) { - contents.erase(ci); - return true; - } - } - - return false; -} - -/** - * Appends the indicated basename to the root directory name, which is - * modified in-place. The basename is allowed to contain nested slashes, but - * no directory component of the basename may begin with a ".", thus - * precluding ".." and hidden files. - */ -void P3DInstanceManager:: -append_safe_dir(string &root, const string &basename) { - if (basename.empty()) { - return; - } - - size_t p = 0; - while (p < basename.length()) { - size_t q = basename.find('/', p); - if (q == string::npos) { - if (q != p) { - append_safe_dir_component(root, basename.substr(p)); - } - return; - } - if (q != p) { - append_safe_dir_component(root, basename.substr(p, q - p)); - } - p = q + 1; - } -} - -/** - * Called during initialize, or after a previous call to uninstall_all(), to - * make sure all needed directories exist and the logfile is open. - */ -void P3DInstanceManager:: -create_runtime_environment() { - mkdir_complete(_log_directory, std::cerr); - - logfile.close(); - logfile.clear(); -#ifdef _WIN32 - wstring log_pathname_w; - string_to_wstring(log_pathname_w, _log_pathname); - logfile.open(log_pathname_w.c_str(), std::ios::out | std::ios::trunc); -#else - logfile.open(_log_pathname.c_str(), std::ios::out | std::ios::trunc); -#endif // _WIN32 - if (logfile) { - logfile.setf(std::ios::unitbuf); - nout_stream = &logfile; - } - - // Determine the temporary directory. -#ifdef _WIN32 - wchar_t buffer_1[MAX_PATH]; - wstring temp_directory_w; - - // Figuring out the correct path for temporary files is a real mess on - // Windows. We should be able to use GetTempPath(), but that relies on $TMP - // or $TEMP being defined, and it appears that Mozilla clears these - // environment variables for the plugin, which forces GetTempPath() into - // $USERPROFILE instead. This is really an inappropriate place for - // temporary files, so, GetTempPath() isn't a great choice. - - // We could use SHGetSpecialFolderPath() instead to get us the path to - // "Temporary Internet Files", which is acceptable. The trouble is, if we - // happen to be running in "Protected Mode" on Vista, this folder isn't - // actually writable by us! On Vista, we're supposed to use - // IEGetWriteableFolderPath() instead, but *this* function doesn't exist on - // XP and below. Good Lord. - - // We could go through a bunch of LoadLibrary() calls to try to find the - // right path, like we do in find_root_dir(), but I'm just tired of doing - // all that nonsense. We'll use a two-stage trick instead. We'll check for - // $TEMP or $TMP being defined specifically, and if they are, we'll use - // GetTempPath(); otherwise, we'll fall back to SHGetSpecialFolderPath(). - - if (getenv("TEMP") != nullptr || getenv("TMP") != nullptr) { - if (GetTempPathW(MAX_PATH, buffer_1) != 0) { - temp_directory_w = buffer_1; - } - } - if (temp_directory_w.empty()) { - if (SHGetSpecialFolderPathW(nullptr, buffer_1, CSIDL_INTERNET_CACHE, true)) { - temp_directory_w = buffer_1; - - // That just *might* return a non-writable folder, if we're in Protected - // Mode. We'll test this with GetTempFileName(). - wchar_t temp_buffer[MAX_PATH]; - if (!GetTempFileNameW(temp_directory_w.c_str(), L"p3d", 0, temp_buffer)) { - nout << "GetTempFileName failed on " << temp_directory_w - << ", switching to GetTempPath\n"; - temp_directory_w.clear(); - } else { - DeleteFileW(temp_buffer); - } - } - } - - // If both of the above failed, we'll fall back to GetTempPath() once again - // as a last resort, which is supposed to return *something* that works, - // even if $TEMP and $TMP are undefined. - if (temp_directory_w.empty()) { - if (GetTempPathW(MAX_PATH, buffer_1) != 0) { - temp_directory_w = buffer_1; - } - } - - // Also insist that the temp directory is fully specified. - size_t needs_size_2 = GetFullPathNameW(temp_directory_w.c_str(), 0, nullptr, nullptr); - wchar_t *buffer_2 = new wchar_t[needs_size_2]; - if (GetFullPathNameW(temp_directory_w.c_str(), needs_size_2, buffer_2, nullptr) != 0) { - temp_directory_w = buffer_2; - } - delete[] buffer_2; - - // And make sure the directory actually exists. - mkdir_complete_w(temp_directory_w, nout); - wstring_to_string(_temp_directory, temp_directory_w); - -#else - _temp_directory = "/tmp/"; -#endif // _WIN32 - - // Ensure that the temp directory ends with a slash. - if (!_temp_directory.empty() && _temp_directory[_temp_directory.size() - 1] != '/') { -#ifdef _WIN32 - if (_temp_directory[_temp_directory.size() - 1] != '\\') -#endif - _temp_directory += "/"; - } - - nout << "\n_root_dir = " << _root_dir - << ", _temp_directory = " << _temp_directory - << ", platform = " << _platform - << ", host_url = " << _host_url - << ", verify_contents = " << _verify_contents - << "\n"; - if (!_host_dir.empty()) { - nout << "_host_dir = " << _host_dir << "\n"; - } - nout << "api_version = " << _api_version << "\n"; - - // Make the certificate directory. - _certs_dir = _root_dir + "/certs"; - if (!get_trusted_environment()) { - if (!mkdir_complete(_certs_dir, nout)) { - nout << "Couldn't mkdir " << _certs_dir << "\n"; - } - } - -#ifndef _WIN32 - // If we're running from the console, make sure that terminating the parent - // process will cause the child process to terminate as well. - if (_console_environment) { - struct sigaction ignore; - memset(&ignore, 0, sizeof(ignore)); - ignore.sa_handler = SIG_IGN; - sigaction(SIGINT, &ignore, nullptr); - } -#endif - - _created_runtime_environment = true; -} - -/** - * Appends a single directory component, implementing append_safe_dir(), - * above. - */ -void P3DInstanceManager:: -append_safe_dir_component(string &root, const string &component) { - if (component.empty()) { - return; - } - root += '/'; - if (component[0] == '.') { - root += 'x'; - } - root += component; -} - -/** - * The main function for the notify thread. - */ -void P3DInstanceManager:: -nt_thread_run() { -/* - * The notify thread exists because we need to be able to send asynchronous - * notifications of request events. These request events were detected in the - * various read threads associated with each session, but we can't call back - * into the plugin host space from the read thread, since if the host - * immediately responds to a callback by calling back into the p3d_plugin - * space, we will have our read thread doing stuff in here that's not related - * to the read thread. Even worse, some of the things it might need to do - * might require a separate read thread to be running! - */ - - _notify_ready.acquire(); - while (_notify_thread_continue) { - NotifyInstances instances; - while (!_notify_instances.empty()) { - instances.clear(); - instances.swap(_notify_instances); - - // Go ahead and drop the lock while we make the callback, to reduce the - // risk of deadlock. We don't want to be holding any locks when we call - // into client code. - _notify_ready.release(); - NotifyInstances::iterator ni; - for (ni = instances.begin(); ni != instances.end(); ++ni) { - // TODO: a race condition here when instances are deleted. - P3DInstance *inst = (*ni); - assert(inst != nullptr); - P3D_request_ready_func *func = inst->get_request_ready_func(); - if (func != nullptr) { - (*func)(inst); - } - } - _notify_ready.acquire(); - } - - _notify_ready.wait(); - } - _notify_ready.release(); -} - -#ifdef _WIN32 -bool P3DInstanceManager:: -supports_win64() { - BOOL is_win64 = false; - - typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); - LPFN_ISWOW64PROCESS _IsWow64Process; - _IsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process"); - - if (_IsWow64Process != nullptr) { - if (!_IsWow64Process(GetCurrentProcess(), &is_win64)) { - is_win64 = false; - } - } - return (is_win64 != 0); -} -#endif // _WIN32 diff --git a/direct/src/plugin/p3dInstanceManager.h b/direct/src/plugin/p3dInstanceManager.h deleted file mode 100644 index 08591e14cc..0000000000 --- a/direct/src/plugin/p3dInstanceManager.h +++ /dev/null @@ -1,244 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dInstanceManager.h - * @author drose - * @date 2009-05-29 - */ - -#ifndef P3DINSTANCEMANAGER_H -#define P3DINSTANCEMANAGER_H - -#include "p3d_plugin_common.h" -#include "p3dConditionVar.h" - -#include -#include -#include - -#ifndef _WIN32 -#include -#endif - -#define OPENSSL_NO_KRB5 -#include -#include -#include - -class P3DInstance; -class P3DSession; -class P3DAuthSession; -class P3DHost; -class P3DPackage; -class FileSpec; -class TiXmlElement; - -/** - * This global class manages the set of instances in the universe. - */ -class P3DInstanceManager { -private: - P3DInstanceManager(); - ~P3DInstanceManager(); - -public: - bool initialize(int api_version, const std::string &contents_filename, - const std::string &host_url, - P3D_verify_contents verify_contents, - const std::string &platform, - const std::string &log_directory, - const std::string &log_basename, - bool trusted_environment, - bool console_environment, - const std::string &root_dir = "", - const std::string &host_dir = "", - const std::string &start_dir = ""); - - inline bool is_initialized() const; - inline void reconsider_runtime_environment(); - inline P3D_verify_contents get_verify_contents() const; - inline void reset_verify_contents(); - - inline int get_api_version() const; - inline const std::string &get_host_url() const; - inline const std::string &get_root_dir() const; - inline const std::string &get_start_dir() const; - inline const std::string &get_platform() const; - inline const std::string &get_temp_directory() const; - inline const std::string &get_log_directory() const; - inline const std::string &get_log_pathname() const; - inline bool get_trusted_environment() const; - inline bool get_console_environment() const; - - inline int get_num_supported_platforms() const; - inline const std::string &get_supported_platform(int n) const; - - void set_plugin_version(int major, int minor, int sequence, - bool official, const std::string &distributor, - const std::string &coreapi_host_url, - time_t coreapi_timestamp, - const std::string &coreapi_set_ver); - inline int get_plugin_major_version() const; - inline int get_plugin_minor_version() const; - inline int get_plugin_sequence_version() const; - inline bool get_plugin_official_version() const; - inline const std::string &get_plugin_distributor() const; - inline const std::string &get_coreapi_host_url() const; - inline time_t get_coreapi_timestamp() const; - inline const std::string &get_coreapi_set_ver() const; - - void set_super_mirror(const std::string &super_mirror_url); - inline const std::string &get_super_mirror() const; - - P3DInstance * - create_instance(P3D_request_ready_func *func, - const P3D_token tokens[], size_t num_tokens, - int argc, const char *argv[], void *user_data); - - bool set_p3d_filename(P3DInstance *inst, bool is_local, - const std::string &p3d_filename, const int &p3d_offset); - int make_p3d_stream(P3DInstance *inst, const std::string &p3d_url); - bool start_instance(P3DInstance *inst); - void finish_instance(P3DInstance *inst); - P3DAuthSession *authorize_instance(P3DInstance *inst); - - P3DInstance *validate_instance(P3D_instance *instance); - - P3DInstance *check_request(); - void wait_request(double timeout); - - P3DHost *get_host(const std::string &host_url); - void forget_host(P3DHost *host); - - inline int get_num_instances() const; - - int get_unique_id(); - void signal_request_ready(P3DInstance *inst); - - P3D_class_definition *make_class_definition() const; - - inline P3D_object *new_undefined_object(); - inline P3D_object *new_none_object(); - inline P3D_object *new_bool_object(bool value); - - std::string make_temp_filename(const std::string &extension); - void release_temp_filename(const std::string &filename); - - bool find_cert(X509 *cert); - void read_certlist(P3DPackage *package); - std::string get_cert_dir(X509 *cert); - static std::string cert_to_der(X509 *cert); - - void uninstall_all(); - - static P3DInstanceManager *get_global_ptr(); - static void delete_global_ptr(); - - static inline char encode_hexdigit(int c); - static bool scan_directory(const std::string &dirname, std::vector &contents); - static bool scan_directory_recursively(const std::string &dirname, - std::vector &filename_contents, - std::vector &dirname_contents, - const std::string &prefix = ""); - static void delete_directory_recursively(const std::string &root_dir); - static bool remove_file_from_list(std::vector &contents, const std::string &filename); - - static void append_safe_dir(std::string &root, const std::string &basename); - -private: - void create_runtime_environment(); - static void append_safe_dir_component(std::string &root, const std::string &component); - -private: - // The notify thread. This thread runs only for the purpose of generating - // asynchronous notifications of requests, to callers who ask for it. - THREAD_CALLBACK_DECLARATION(P3DInstanceManager, nt_thread_run); - void nt_thread_run(); - -#ifdef _WIN32 - static bool supports_win64(); -#endif // _WIN32 - -private: - bool _is_initialized; - bool _created_runtime_environment; - int _api_version; - std::string _host_url; - std::string _root_dir; - std::string _host_dir; - std::string _start_dir; - std::string _certs_dir; - P3D_verify_contents _verify_contents; - std::string _platform; - std::string _log_directory; - std::string _log_basename; - std::string _log_pathname; - std::string _temp_directory; - bool _trusted_environment; - bool _console_environment; - int _plugin_major_version; - int _plugin_minor_version; - int _plugin_sequence_version; - bool _plugin_official_version; - std::string _plugin_distributor; - std::string _coreapi_host_url; - time_t _coreapi_timestamp; - std::string _coreapi_set_ver; - std::string _super_mirror_url; - - typedef std::vector SupportedPlatforms; - SupportedPlatforms _supported_platforms; - - P3D_object *_undefined_object; - P3D_object *_none_object; - P3D_object *_true_object; - P3D_object *_false_object; - - typedef std::set ApprovedCerts; - ApprovedCerts _approved_certs; - - typedef std::set Instances; - Instances _instances; - P3DAuthSession *_auth_session; - - typedef std::map Sessions; - Sessions _sessions; - - typedef std::map Hosts; - Hosts _hosts; - - typedef std::set TempFilenames; - TempFilenames _temp_filenames; - int _next_temp_filename_counter; - - int _unique_id; - - // This condition var is waited on the main thread and signaled in a sub- - // thread when new request notices arrive. - P3DConditionVar _request_ready; - - // We may need a thread to send async request notices to callers. - bool _notify_thread_continue; - bool _started_notify_thread; - THREAD _notify_thread; - // This queue of instances that need to send notifications is protected by - // _notify_ready's mutex. - typedef std::vector NotifyInstances; - NotifyInstances _notify_instances; - P3DConditionVar _notify_ready; - -#ifndef _WIN32 - struct sigaction _old_sigpipe; -#endif - - static P3DInstanceManager *_global_ptr; -}; - -#include "p3dInstanceManager.I" - -#endif diff --git a/direct/src/plugin/p3dIntObject.cxx b/direct/src/plugin/p3dIntObject.cxx deleted file mode 100644 index 05ad970128..0000000000 --- a/direct/src/plugin/p3dIntObject.cxx +++ /dev/null @@ -1,66 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dIntObject.cxx - * @author drose - * @date 2009-06-30 - */ - -#include "p3dIntObject.h" - -/** - * - */ -P3DIntObject:: -P3DIntObject(int value) : _value(value) { -} - -/** - * - */ -P3DIntObject:: -P3DIntObject(const P3DIntObject ©) : - P3DObject(copy), - _value(copy._value) -{ -} - -/** - * Returns the fundamental type of this kind of object. - */ -P3D_object_type P3DIntObject:: -get_type() { - return P3D_OT_int; -} - -/** - * Returns the object value coerced to a boolean, if possible. - */ -bool P3DIntObject:: -get_bool() { - return (_value != 0); -} - -/** - * Returns the object value coerced to an integer, if possible. - */ -int P3DIntObject:: -get_int() { - return _value; -} - -/** - * Fills the indicated C++ string object with the value of this object coerced - * to a string. - */ -void P3DIntObject:: -make_string(std::string &value) { - std::ostringstream strm; - strm << _value; - value = strm.str(); -} diff --git a/direct/src/plugin/p3dIntObject.h b/direct/src/plugin/p3dIntObject.h deleted file mode 100644 index d77c0d689a..0000000000 --- a/direct/src/plugin/p3dIntObject.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dIntObject.h - * @author drose - * @date 2009-06-30 - */ - -#ifndef P3DINTOBJECT_H -#define P3DINTOBJECT_H - -#include "p3d_plugin_common.h" -#include "p3dObject.h" - -/** - * An object type that contains an integer value. - */ -class P3DIntObject : public P3DObject { -public: - P3DIntObject(int value); - P3DIntObject(const P3DIntObject ©); - -public: - virtual P3D_object_type get_type(); - virtual bool get_bool(); - virtual int get_int(); - virtual void make_string(std::string &value); - -private: - int _value; -}; - -#endif diff --git a/direct/src/plugin/p3dMainObject.cxx b/direct/src/plugin/p3dMainObject.cxx deleted file mode 100644 index 2fd8dba33d..0000000000 --- a/direct/src/plugin/p3dMainObject.cxx +++ /dev/null @@ -1,707 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dMainObject.cxx - * @author drose - * @date 2009-07-10 - */ - -#include "p3dMainObject.h" -#include "p3dPythonObject.h" -#include "p3dInstance.h" -#include "p3dSession.h" -#include "p3dStringObject.h" -#include "p3dInstanceManager.h" - -using std::ios; -using std::max; -using std::streamsize; -using std::string; - -/** - * - */ -P3DMainObject:: -P3DMainObject() : - _pyobj(nullptr), - _inst(nullptr), - _unauth_play(false) -{ -} - -/** - * - */ -P3DMainObject:: -~P3DMainObject() { - set_pyobj(nullptr); - - // Clear the local properties. - Properties::const_iterator pi; - for (pi = _properties.begin(); pi != _properties.end(); ++pi) { - P3D_object *value = (*pi).second; - P3D_OBJECT_DECREF(value); - } - _properties.clear(); -} - -/** - * Returns the fundamental type of this kind of object. - */ -P3D_object_type P3DMainObject:: -get_type() { - return P3D_OT_object; -} - -/** - * Returns the object value coerced to a boolean, if possible. - */ -bool P3DMainObject:: -get_bool() { - return true; -} - -/** - * Returns the object value coerced to an integer, if possible. - */ -int P3DMainObject:: -get_int() { - return 0; -} - -/** - * Returns the object value coerced to a floating-point value, if possible. - */ -double P3DMainObject:: -get_float() { - return 0.0; -} - -/** - * Fills the indicated C++ string object with the value of this object coerced - * to a string. - */ -void P3DMainObject:: -make_string(string &value) { - if (_pyobj == nullptr) { - value = "P3DMainObject"; - } else { - int size = P3D_OBJECT_GET_STRING(_pyobj, nullptr, 0); - char *buffer = new char[size]; - P3D_OBJECT_GET_STRING(_pyobj, buffer, size); - value = string(buffer, size); - delete[] buffer; - } -} - -/** - * Returns the named property element in the object. The return value is a - * new-reference P3D_object, or NULL on error. - */ -P3D_object *P3DMainObject:: -get_property(const string &property) { - if (_pyobj == nullptr) { - // Without a pyobj, we just report whatever's been stored locally. - Properties::const_iterator pi; - pi = _properties.find(property); - if (pi != _properties.end()) { - P3D_object *result = (*pi).second; - P3D_OBJECT_INCREF(result); - return result; - } - return nullptr; - } - - // With a pyobj, we pass the query down to it. - return P3D_OBJECT_GET_PROPERTY(_pyobj, property.c_str()); -} - -/** - * Modifies (or deletes, if value is NULL) the named property element in the - * object. Returns true on success, false on failure. - */ -bool P3DMainObject:: -set_property(const string &property, bool needs_response, P3D_object *value) { - // First, we set the property locally. - if (value != nullptr) { - Properties::iterator pi; - pi = _properties.insert(Properties::value_type(property, nullptr)).first; - assert(pi != _properties.end()); - P3D_object *orig_value = (*pi).second; - if (orig_value != value) { - P3D_OBJECT_XDECREF(orig_value); - (*pi).second = value; - P3D_OBJECT_INCREF(value); - } - } else { - // (Or delete the property locally.) - Properties::iterator pi; - pi = _properties.find(property); - if (pi != _properties.end()) { - P3D_object *orig_value = (*pi).second; - P3D_OBJECT_DECREF(orig_value); - _properties.erase(pi); - } - } - - if (_pyobj == nullptr) { - // Without a pyobj, that's all we do. - return true; - } - - // With a pyobj, we also pass this request down. - return P3D_OBJECT_SET_PROPERTY(_pyobj, property.c_str(), needs_response, value); -} - -/** - * Returns true if the named method exists on this object, false otherwise. - */ -bool P3DMainObject:: -has_method(const string &method_name) { - // Some special-case methods implemented in-place. - if (method_name == "play") { - return true; - } else if (method_name == "read_game_log") { - return true; - } else if (method_name == "read_system_log") { - return true; - } else if (method_name == "read_log") { - return true; - } else if (method_name == "uninstall") { - return true; - } - - if (_pyobj == nullptr) { - // No methods until we get our pyobj. - return false; - } - - return P3D_OBJECT_HAS_METHOD(_pyobj, method_name.c_str()); -} - -/** - * Invokes the named method on the object, passing the indicated parameters. - * If the method name is empty, invokes the object itself. - * - * If needs_response is true, the return value is a new-reference P3D_object - * on success, or NULL on failure. If needs_response is false, the return - * value is always NULL, and there is no way to determine success or failure. - */ -P3D_object *P3DMainObject:: -call(const string &method_name, bool needs_response, - P3D_object *params[], int num_params) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - nout << "main." << method_name << "("; - for (int i = 0; i < num_params; ++i) { - if (i != 0) { - nout << ", "; - } - int buffer_size = P3D_OBJECT_GET_REPR(params[i], nullptr, 0); - char *buffer = new char[buffer_size]; - P3D_OBJECT_GET_REPR(params[i], buffer, buffer_size); - nout.write(buffer, buffer_size); - delete[] buffer; - } - nout << ")\n"; - - if (method_name == "play") { - return call_play(params, num_params); - } else if (method_name == "read_game_log") { - return call_read_game_log(params, num_params); - } else if (method_name == "read_system_log") { - return call_read_system_log(params, num_params); - } else if (method_name == "read_log") { - return call_read_log(params, num_params); - } else if (method_name == "uninstall") { - return call_uninstall(params, num_params); - } - - if (_pyobj == nullptr) { - // No methods until we get our pyobj. - return nullptr; - } - - return P3D_OBJECT_CALL(_pyobj, method_name.c_str(), needs_response, - params, num_params); -} - -/** - * Writes a formatted representation of the value to the indicated string. - * This is intended for developer assistance. - */ -void P3DMainObject:: -output(std::ostream &out) { - out << "P3DMainObject"; -} - -/** - * Changes the internal pyobj pointer. This is the P3D_object that references - * the actual PyObject held within the child process, corresponding to the - * true main object there. The new object's reference count is incremented, - * and the previous object's is decremented. - */ -void P3DMainObject:: -set_pyobj(P3D_object *pyobj) { - if (pyobj == this) { - // We are setting a reference directly to ourselves. This happens when - // the application has accepted the main object we gave it in - // set_instance_info(). This means the application is directly - // manipulating this object as its appRunner.main. In this case, we don't - // actually need to set the reference; instead, we clear anything we had - // set. - nout << "application shares main object\n"; - pyobj = nullptr; - - } else if (pyobj != nullptr) { - // In the alternate case, the application has its own, separate - // appRunner.main object. Thus, we do need to set the pointer. - nout << "application has its own main object\n"; - } - - if (_pyobj != pyobj) { - P3D_OBJECT_XDECREF(_pyobj); - _pyobj = pyobj; - if (_pyobj != nullptr) { - P3D_OBJECT_INCREF(_pyobj); - - // Now that we have a pyobj, we have to transfer down all of the - // properties we'd set locally. - apply_properties(_pyobj); - } - } -} - -/** - * Returns the internal pyobj pointer, or NULL if it has not yet been set. - */ -P3D_object *P3DMainObject:: -get_pyobj() const { - return _pyobj; -} - -/** - * Applies the locally-set properties onto the indicated Python object, but - * does not store the object. This is a one-time copy of the locally-set - * properties (like "coreapiHostUrl" and the like) onto the indicated Python - * object. - */ -void P3DMainObject:: -apply_properties(P3D_object *pyobj) { - P3DPythonObject *p3dpyobj = nullptr; - if (pyobj->_class == &P3DObject::_object_class) { - p3dpyobj = ((P3DObject *)pyobj)->as_python_object(); - } - - Properties::const_iterator pi; - for (pi = _properties.begin(); pi != _properties.end(); ++pi) { - const string &property_name = (*pi).first; - P3D_object *value = (*pi).second; - if (p3dpyobj != nullptr && P3D_OBJECT_GET_TYPE(value) != P3D_OT_object) { - // If we know we have an actual P3DPythonObject (we really expect this), - // then we can call set_property_insecure() directly, because we want to - // allow setting the initial properties even if Javascript has no - // permissions to write into Python. But we don't allow setting objects - // this way in any event. - p3dpyobj->set_property_insecure(property_name, false, value); - } else { - // Otherwise, we go through the generic interface. - P3D_OBJECT_SET_PROPERTY(pyobj, property_name.c_str(), false, value); - } - } -} - -/** - * Sets a callback pointer to the instance that owns this object. When this - * instance destructs, it clears this pointer to NULL. - */ -void P3DMainObject:: -set_instance(P3DInstance *inst) { - if (_inst != nullptr) { - // Save the game log filename of the instance just before it goes away, in - // case JavaScript asks for it later. - _game_log_pathname = _inst->get_log_pathname(); - } - - _inst = inst; -} - -/** - * Starts the process remotely, as if the play button had been clicked. If - * the application has not yet been validated, this pops up the validation - * dialog. - * - * Only applicable if the application was in the ready state, or the unauth - * state. Returns true if the application is now started, false otherwise. - * - * This may be invoked from the unauth state only once. If the user chooses - * not to authorize the plugin at that time, it may not be invoked - * automatically again. - */ -P3D_object *P3DMainObject:: -call_play(P3D_object *params[], int num_params) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (_inst == nullptr) { - return inst_mgr->new_bool_object(false); - } - - // I guess there's no harm in allowing JavaScript to call play(), with or - // without explicit scripting authorization. - nout << "play() called from JavaScript\n"; - - if (!_inst->is_trusted()) { - // Requires authorization. We allow this only once; beyond that, and - // you're only annoying the user. - if (!_unauth_play) { - _unauth_play = true; - _inst->splash_button_clicked_main_thread(); - } - - } else if (!_inst->is_started()) { - // We allow calling play() from a ready state without limit, but probably - // only once will be necessary. - _inst->splash_button_clicked_main_thread(); - } - - return inst_mgr->new_bool_object(_inst->is_started()); -} - -/** - * Reads the entire logfile as a string, and returns it to the calling - * JavaScript process. - */ -P3D_object *P3DMainObject:: -call_read_game_log(P3D_object *params[], int num_params) { - if (_inst != nullptr) { - string log_pathname = _inst->get_log_pathname(); - return read_log(log_pathname, params, num_params); - } - - if (!_game_log_pathname.empty()) { - // The instance has already finished, but we saved its log filename. - return read_log(_game_log_pathname, params, num_params); - } - - // No log available for us. - nout << "read_game_log: error: game log name unknown" << "\n"; - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - return inst_mgr->new_undefined_object(); -} - -/** - * As above, but reads the system log, the logfile for the installation - * process. - */ -P3D_object *P3DMainObject:: -call_read_system_log(P3D_object *params[], int num_params) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - string log_pathname = inst_mgr->get_log_pathname(); - return read_log(log_pathname, params, num_params); -} - -/** - * Reads a named logfile. The filename must end in ".log" and must not - * contain any slashes or colons (it must be found within the log directory). - */ -P3D_object *P3DMainObject:: -call_read_log(P3D_object *params[], int num_params) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - if (num_params < 1) { - nout << "read_log: error: not enough parameters" << "\n"; - return inst_mgr->new_undefined_object(); - } - - int size = P3D_OBJECT_GET_STRING(params[0], nullptr, 0); - char *buffer = new char[size]; - P3D_OBJECT_GET_STRING(params[0], buffer, size); - string log_filename = string(buffer, size); - delete[] buffer; - - if (log_filename.size() < 4 || log_filename.substr(log_filename.size() - 4) != string(".log")) { - // Wrong filename extension. - nout << "read_log: error: invalid filename" << "\n"; - return inst_mgr->new_undefined_object(); - } - - size_t slash = log_filename.find('/'); - if (slash != string::npos) { - // No slashes allowed. - nout << "read_log: error: invalid filename" << "\n"; - return inst_mgr->new_undefined_object(); - } - - slash = log_filename.find('\\'); - if (slash != string::npos) { - // Nor backslashes. - nout << "read_log: error: invalid filename" << "\n"; - return inst_mgr->new_undefined_object(); - } - - size_t colon = log_filename.find(':'); - if (colon != string::npos) { - // Nor colons, for that matter. - nout << "read_log: error: invalid filename" << "\n"; - return inst_mgr->new_undefined_object(); - } - - string log_pathname = inst_mgr->get_log_directory() + log_filename; - P3D_object *result = read_log(log_pathname, params + 1, num_params - 1); - return result; -} - -/** - * log-reader meta function that handles reading previous log files in - * addition to the present one - */ -P3D_object *P3DMainObject:: -read_log(const string &log_pathname, P3D_object *params[], int num_params) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - string log_directory = inst_mgr->get_log_directory(); - std::ostringstream log_data; - - // Check the first parameter, if any--if given, it specifies the last n - // bytes to retrieve. - size_t tail_bytes = 0; - if (num_params > 0) { - tail_bytes = (size_t)max(P3D_OBJECT_GET_INT(params[0]), 0); - } - // Check the second parameter, if any--if given, it specifies the first n - // bytes to retrieve. - size_t head_bytes = 0; - if (num_params > 1) { - head_bytes = (size_t)max(P3D_OBJECT_GET_INT(params[1]), 0); - } - // Check the third parameter, if any--if given, it specifies the last n - // bytes to retrieve from previous copies of this file. - size_t tail_bytes_prev = 0; - if (num_params > 2) { - tail_bytes_prev = (size_t)max(P3D_OBJECT_GET_INT(params[2]), 0); - } - // Check the fourth parameter, if any--if given, it specifies the first n - // bytes to retrieve from previous copies of this file. - size_t head_bytes_prev = 0; - if (num_params > 3) { - head_bytes_prev = (size_t)max(P3D_OBJECT_GET_INT(params[3]), 0); - } - - // Determine the base of the log file names - nout << "log_pathname: " << log_pathname << "\n"; - string log_basename = log_pathname; - size_t slash = log_basename.rfind('/'); - if (slash != string::npos) { - log_basename = log_basename.substr(slash + 1); - } -#ifdef _WIN32 - slash = log_basename.rfind('\\'); - if (slash != string::npos) { - log_basename = log_basename.substr(slash + 1); - } -#endif // _WIN32 - string log_leafname_primary = log_basename; - int dash = log_basename.rfind("-"); - if (dash != string::npos) { - log_basename = log_basename.substr(0, dash+1); - } else { - int dotLog = log_basename.rfind(".log"); - if (dotLog != string::npos) { - log_basename = log_basename.substr(0, dotLog); - log_basename += "-"; - } - } - - // Read matching files - std::vector all_logs; - int log_matches_found = 0; - string log_matching_pathname; - inst_mgr->scan_directory(log_directory, all_logs); - for (int i = (int)all_logs.size() - 1; i >= 0; --i) { - if (all_logs[i] == log_leafname_primary || - (all_logs[i].find(log_basename) == 0 && - all_logs[i].size() > 4 && - all_logs[i].substr(all_logs[i].size() - 4) == string(".log"))) { - log_matches_found++; - log_matching_pathname = (log_directory + all_logs[i]); - read_log_file(log_matching_pathname, tail_bytes, head_bytes, log_data); - tail_bytes = tail_bytes_prev; - head_bytes = head_bytes_prev; - } - } - - if (log_matches_found == 0) { - nout << "read_log: warning: no matching file(s) on disk." << "\n"; - } - - string log_data_str = log_data.str(); - P3D_object *result = new P3DStringObject(log_data_str); - return result; -} - -/** - * The generic log-reader function. - */ -void P3DMainObject:: -read_log_file(const string &log_pathname, - size_t tail_bytes, size_t head_bytes, - std::ostringstream &log_data) { - - // Get leaf name - string log_leafname = log_pathname; - size_t slash = log_leafname.rfind('/'); - if (slash != string::npos) { - log_leafname = log_leafname.substr(slash + 1); - } -#ifdef _WIN32 - slash = log_leafname.rfind('\\'); - if (slash != string::npos) { - log_leafname = log_leafname.substr(slash + 1); - } -#endif // _WIN32 - - // Render log file header to log_data - log_data << "======================================="; - log_data << "=======================================" << "\n"; - log_data << "== PandaLog-" << log_pathname << "\n"; - - // load file - ifstream log(log_pathname.c_str(), ios::in); - if (!log) { - log_data << "== PandaLog-" << "Error opening file"; - log_data << " " << "(" << log_leafname << ")" << "\n"; - return; - } - - // Get the size of the file. - log.seekg(0, ios::end); - size_t file_size = (size_t)log.tellg(); - nout << "read_log: " << log_pathname << " is " << file_size - << " bytes, tail_bytes = " << tail_bytes << ", head_bytes = " - << head_bytes << "\n"; - - // Early out if the file is empty - if (file_size == (size_t)0) { - log_data << "== PandaLog-" << "Empty File"; - log_data << " " << "(" << log_leafname << ")" << "\n"; - return; - } - - // Check if we are getting the full file - size_t full_bytes = 0; - if (file_size <= head_bytes + tail_bytes) { - // We will return the entire log. - full_bytes = file_size; - head_bytes = 0; - tail_bytes = 0; - } - - // Allocate a temp buffer to hold file data - size_t buffer_bytes = max(max(full_bytes, head_bytes), tail_bytes) + 1; - nout << "allocating " << buffer_bytes << " bytes to read at a time from file of size " << file_size << ".\n"; - char *buffer = new char[buffer_bytes]; - if (buffer == nullptr) { - log_data << "== PandaLog-" << "Error allocating buffer"; - log_data << " " << "(" << log_leafname << ")" << "\n"; - return; - } - - // Render log data if full file is to be fetched - if (full_bytes > 0) { - log.seekg(0, ios::beg); - log.read(buffer, full_bytes); - streamsize read_bytes = log.gcount(); - assert(read_bytes < (streamsize)buffer_bytes); - buffer[read_bytes] = '\0'; - log_data << "== PandaLog-" << "Full Start"; - log_data << " " << "(" << log_leafname << ")" << "\n"; - log_data << buffer; - log_data << "== PandaLog-" << "Full End"; - log_data << " " << "(" << log_leafname << ")" << "\n"; - } - - // Render log data if head bytes are to be fetched - if (head_bytes > 0) { - log.seekg(0, ios::beg); - log.read(buffer, head_bytes); - streamsize read_bytes = log.gcount(); - assert(read_bytes < (streamsize)buffer_bytes); - buffer[read_bytes] = '\0'; - log_data << "== PandaLog-" << "Head Start"; - log_data << " " << "(" << log_leafname << ")" << "\n"; - log_data << buffer << "\n"; - log_data << "== PandaLog-" << "Head End"; - log_data << " " << "(" << log_leafname << ")" << "\n"; - } - - // Render separator if head & tail bytes are to be fetched - if ((head_bytes > 0) && (tail_bytes > 0)) { - log_data << "== PandaLog-" << "truncated"; - log_data << " " << "(" << log_leafname << ")" << "\n"; - } - - // Render log data if tail bytes are to be fetched - if (tail_bytes > 0) { - log.seekg(file_size - tail_bytes, ios::beg); - log.read(buffer, tail_bytes); - streamsize read_bytes = log.gcount(); - assert(read_bytes < (streamsize)buffer_bytes); - buffer[read_bytes] = '\0'; - log_data << "== PandaLog-" << "Tail Start"; - log_data << " " << "(" << log_leafname << ")" << "\n"; - log_data << buffer; - log_data << "== PandaLog-" << "Tail End"; - log_data << " " << "(" << log_leafname << ")" << "\n"; - } - - // Render log file footer to log_data log_data << - // "======================================="; log_data << - // "=======================================" << "\n"; - - // cleanup - delete[] buffer; - buffer = nullptr; -} - -/** - * Implements the uninstall() plugin method, which removes all Panda installed - * files for a particular host, or referenced by a particular p3d file. - */ -P3D_object *P3DMainObject:: -call_uninstall(P3D_object *params[], int num_params) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - // Get the first parameter, the uninstall mode. - string mode; - if (num_params > 0) { - int size = P3D_OBJECT_GET_STRING(params[0], nullptr, 0); - char *buffer = new char[size]; - P3D_OBJECT_GET_STRING(params[0], buffer, size); - mode = string(buffer, size); - delete[] buffer; - } - - if (mode == "all") { - nout << "uninstall all\n"; - inst_mgr->uninstall_all(); - return inst_mgr->new_bool_object(true); - } - - if (_inst != nullptr) { - nout << "uninstall " << mode << " for " << _inst << "\n"; - bool success = false; - if (mode == "host") { - success = _inst->uninstall_host(); - } else { - success = _inst->uninstall_packages(); - } - return inst_mgr->new_bool_object(success); - } - - nout << "couldn't uninstall; no instance.\n"; - return inst_mgr->new_bool_object(false); -} diff --git a/direct/src/plugin/p3dMainObject.h b/direct/src/plugin/p3dMainObject.h deleted file mode 100644 index fafad0ff16..0000000000 --- a/direct/src/plugin/p3dMainObject.h +++ /dev/null @@ -1,92 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dMainObject.h - * @author drose - * @date 2009-07-10 - */ - -#ifndef P3DMAINOBJECT_H -#define P3DMAINOBJECT_H - -#include "p3d_plugin_common.h" -#include "p3dObject.h" -#include -#include - -class P3DSession; -class P3DInstance; - -/** - * This corresponds to the "main" object exposed by a particular instance, as - * returned by P3DInstance::get_panda_script_object(). This object - * corresponds to the appRunner.main object in Python, and the - * document.pluginobject.main object in JavaScript. - * - * This is mostly a wrapper around a P3DPythonObject pointer, and therefore - * functions like any other P3DPythonObject; but it also handles the special - * case of being available before Python has been started; and it furthermore - * reports properties that are generated directly by the core API (like - * downloadProgress and such). - */ -class P3DMainObject : public P3DObject { -public: - P3DMainObject(); - virtual ~P3DMainObject(); - -public: - virtual P3D_object_type get_type(); - virtual bool get_bool(); - virtual int get_int(); - virtual double get_float(); - - virtual void make_string(std::string &value); - - virtual P3D_object *get_property(const std::string &property); - virtual bool set_property(const std::string &property, bool needs_response, - P3D_object *value); - - virtual bool has_method(const std::string &method_name); - virtual P3D_object *call(const std::string &method_name, bool needs_response, - P3D_object *params[], int num_params); - - virtual void output(std::ostream &out); - - void set_pyobj(P3D_object *pyobj); - P3D_object *get_pyobj() const; - void apply_properties(P3D_object *pyobj); - - void set_instance(P3DInstance *inst); - -private: - P3D_object *call_play(P3D_object *params[], int num_params); - P3D_object *call_read_game_log(P3D_object *params[], int num_params); - P3D_object *call_read_system_log(P3D_object *params[], int num_params); - P3D_object *call_read_log(P3D_object *params[], int num_params); - P3D_object *read_log(const std::string &log_pathname, - P3D_object *params[], int num_params); - void read_log_file(const std::string &log_pathname, - size_t tail_bytes, size_t head_bytes, - std::ostringstream &log_data); - P3D_object *call_uninstall(P3D_object *params[], int num_params); - -private: - P3D_object *_pyobj; - P3DInstance *_inst; - - bool _unauth_play; - std::string _game_log_pathname; - - // This map is used to store properties and retrieve until set_pyobj() is - // called for the firs ttime. At that point, the properties stored here are - // transferred down to the internal PyObject. - typedef std::map Properties; - Properties _properties; -}; - -#endif diff --git a/direct/src/plugin/p3dMultifileReader.I b/direct/src/plugin/p3dMultifileReader.I deleted file mode 100644 index ff3daf31b8..0000000000 --- a/direct/src/plugin/p3dMultifileReader.I +++ /dev/null @@ -1,79 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dMultifileReader.I - * @author drose - * @date 2009-06-15 - */ - -/** - * Returns true if the reader is open, false otherwise. - */ -inline bool P3DMultifileReader:: -is_open() const { - return _is_open; -} - -/** - * Extracts an unsigned short from the file. - */ -inline unsigned int P3DMultifileReader:: -read_uint16() { - unsigned int a = _in.get(); - unsigned int b = _in.get(); - return (b << 8) | a; -} - -/** - * Extracts an unsigned long from the file. - */ -inline unsigned int P3DMultifileReader:: -read_uint32() { - unsigned int a = _in.get(); - unsigned int b = _in.get(); - unsigned int c = _in.get(); - unsigned int d = _in.get(); - return (d << 24) | (c << 16) | (b << 8) | a; -} - -/** - * Returns the byte position within the Multifile of the last byte that - * contributes to this Subfile, either in the index record or in the subfile - * data. - */ -inline size_t P3DMultifileReader::Subfile:: -get_last_byte_pos() const { - return std::max(_index_start + _index_length, _data_start + _data_length) - 1; -} - -/** - * Ownership of the X509 object is passed into the CertRecord; it will be - * freed when the CertRecord destructs. - */ -inline P3DMultifileReader::CertRecord:: -CertRecord(X509 *cert) : - _cert(cert) -{ -} - -/** - * - */ -inline P3DMultifileReader::CertRecord:: -CertRecord(const P3DMultifileReader::CertRecord ©) : - _cert(X509_dup(copy._cert)) -{ -} - -/** - * - */ -inline P3DMultifileReader::CertRecord:: -~CertRecord() { - X509_free(_cert); -} diff --git a/direct/src/plugin/p3dMultifileReader.cxx b/direct/src/plugin/p3dMultifileReader.cxx deleted file mode 100644 index e47400bdb6..0000000000 --- a/direct/src/plugin/p3dMultifileReader.cxx +++ /dev/null @@ -1,487 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dMultifileReader.cxx - * @author drose - * @date 2009-06-15 - */ - -#include "p3dMultifileReader.h" -#include "p3dPackage.h" -#include "mkdir_complete.h" -#include "wstring_encode.h" - -#include - -#ifdef _WIN32 -#include -#include -#endif - -using std::ios; -using std::max; -using std::min; -using std::streampos; -using std::streamsize; -using std::string; - -// This sequence of bytes begins each Multifile to identify it as a Multifile. -const char P3DMultifileReader::_header[] = "pmf\0\n\r"; -const size_t P3DMultifileReader::_header_size = 6; - -const int P3DMultifileReader::_current_major_ver = 1; -const int P3DMultifileReader::_current_minor_ver = 1; - -/** - * - */ -P3DMultifileReader:: -P3DMultifileReader() { - _is_open = false; - _read_offset = 0; -} - -/** - * Opens the indicated file for reading. Returns true on success, false on - * failure. - */ -bool P3DMultifileReader:: -open_read(const string &pathname, const int &offset) { - if (_is_open) { - close(); - } - - _read_offset = offset; - if (!read_header(pathname)) { - return false; - } - - _is_open = true; - return true; -} - -/** - * Closes the previously-opened file. - */ -void P3DMultifileReader:: -close() { - _in.close(); - _is_open = false; -} - -/** - * Reads the multifile, and extracts all the expected extractable components - * within it to the indicated directory. Returns true on success, false on - * failure. - * - * Upates the "step" object with the progress through this operation. - */ -bool P3DMultifileReader:: -extract_all(const string &to_dir, P3DPackage *package, - P3DPackage::InstallStepThreaded *step) { - assert(_is_open); - if (_in.fail()) { - return false; - } - - // Now walk through all of the files, and extract only the ones we expect to - // encounter. - Subfiles::iterator si; - for (si = _subfiles.begin(); si != _subfiles.end(); ++si) { - const Subfile &s = (*si); - FileSpec file; - if (package != nullptr && !package->is_extractable(file, s._filename)) { - continue; - } - - string output_pathname = to_dir + "/" + s._filename; - if (!mkfile_complete(output_pathname, nout)) { - return false; - } - - ofstream out; -#ifdef _WIN32 - std::wstring output_pathname_w; - if (string_to_wstring(output_pathname_w, output_pathname)) { - out.open(output_pathname_w.c_str(), ios::out | ios::binary); - } -#else // _WIN32 - out.open(output_pathname.c_str(), ios::out | ios::binary); -#endif // _WIN32 - if (!out) { - nout << "Unable to write to " << output_pathname << "\n"; - return false; - } - - if (!extract_subfile(out, s)) { - return false; - } - out.close(); - - // Check that the file was extracted correctly (and also set the correct - // timestamp). - if (!file.full_verify(to_dir)) { - nout << "After extracting, " << s._filename << " is still incorrect.\n"; - return false; - } - - // Be sure to set execute permissions on the file, in case it's a program - // or something. - chmod(output_pathname.c_str(), 0555); - - if (step != nullptr && package != nullptr) { - step->thread_add_bytes_done(s._data_length); - } - } - - return true; -} - -/** - * Reads the multifile, and extracts only the named component to the indicated - * stream. Returns true on success, false on failure. - */ -bool P3DMultifileReader:: -extract_one(std::ostream &out, const string &filename) { - assert(_is_open); - if (_in.fail()) { - return false; - } - - // Look for the named component. - Subfiles::iterator si; - for (si = _subfiles.begin(); si != _subfiles.end(); ++si) { - const Subfile &s = (*si); - if (s._filename == filename) { - return extract_subfile(out, s); - } - } - - nout << "Could not extract " << filename << ": not found.\n"; - return false; -} - -/** - * Returns the number of matching signatures found on the Multifile. These - * signatures may be iterated via get_signature() and related methods. - * - * A signature on this list is guaranteed to match the Multifile contents, - * proving that the Multifile has been unmodified since the signature was - * applied. However, this does not guarantee that the certificate itself is - * actually from who it says it is from; only that it matches the Multifile - * contents. See validate_signature_certificate() to authenticate a - * particular certificate. - */ -int P3DMultifileReader:: -get_num_signatures() const { - if (_is_open) { - ((P3DMultifileReader *)this)->check_signatures(); - } - - return _signatures.size(); -} - -/** - * Returns the nth signature found on the Multifile. See the comments in - * get_num_signatures(). - */ -const P3DMultifileReader::CertChain &P3DMultifileReader:: -get_signature(int n) const { - static CertChain error_chain; - assert(n >= 0 && n < (int)_signatures.size()); - return _signatures[n]; -} - -/** - * Opens the named multifile and reads the header information and index, - * returning true on success, false on failure. - */ -bool P3DMultifileReader:: -read_header(const string &pathname) { - assert(!_is_open); - _subfiles.clear(); - _cert_special.clear(); - _signatures.clear(); - -#ifdef _WIN32 - std::wstring pathname_w; - if (string_to_wstring(pathname_w, pathname)) { - _in.open(pathname_w.c_str(), ios::in | ios::binary); - } -#else // _WIN32 - _in.open(pathname.c_str(), ios::in | ios::binary); -#endif // _WIN32 - if (!_in) { - nout << "Couldn't open " << pathname << "\n"; - return false; - } - - char this_header[_header_size]; - _in.seekg(_read_offset); - - // Here's a special case: if the multifile begins with a hash character, - // then we continue reading and discarding lines of ASCII text, until we - // come across a nonempty line that does not begin with a hash character. - // This allows a P3D application (which is a multifile) to be run directly - // on the command line on Unix-based systems. - int ch = _in.get(); - - if (ch == '#') { - while (ch != EOF && ch == '#') { - // Skip to the end of the line. - while (ch != EOF && ch != '\n') { - ch = _in.get(); - } - // Skip to the first non-whitespace character of the line. - while (ch != EOF && (isspace(ch) || ch == '\r')) { - ch = _in.get(); - } - } - } - - // Now read the actual Multifile header. - this_header[0] = ch; - _in.read(this_header + 1, _header_size - 1); - if (_in.fail() || _in.gcount() != (unsigned)(_header_size - 1)) { - nout << "Unable to read Multifile header: " << pathname << "\n"; - return false; - } - - if (memcmp(this_header, _header, _header_size) != 0) { - nout << "Failed header check: " << pathname << "\n"; - return false; - } - - unsigned int major = read_uint16(); - unsigned int minor = read_uint16(); - if (major != _current_major_ver || minor != _current_minor_ver) { - nout << "Incompatible multifile version: " << pathname << "\n"; - return false; - } - - unsigned int scale = read_uint32(); - if (scale != 1) { - nout << "Unsupported scale factor in " << pathname << "\n"; - return false; - } - - // We don't care about the overall timestamp. - read_uint32(); - - if (!read_index()) { - nout << "Error reading multifile index\n"; - return false; - } - - return true; -} - -/** - * Assuming the file stream is positioned at the first record, reads all of - * the records into the _subfiles list. Returns true on success, false on - * failure. - */ -bool P3DMultifileReader:: -read_index() { - _last_data_byte = 0; - unsigned int next_entry = read_uint32(); - if (!_in) { - return false; - } - while (next_entry != 0) { - Subfile s; - s._index_start = (size_t)_in.tellg() - _read_offset; - s._index_length = 0; - s._data_start = read_uint32(); - s._data_length = read_uint32(); - unsigned int flags = read_uint16(); - if ((flags & (SF_compressed | SF_encrypted)) != 0) { - // Skip over the uncompressed length. - read_uint32(); - } - - s._timestamp = read_uint32(); - size_t name_length = read_uint16(); - char *buffer = new char[name_length]; - _in.read(buffer, name_length); - - // The filenames are xored with 0xff just for fun. - for (size_t ni = 0; ni < name_length; ++ni) { - buffer[ni] ^= 0xff; - } - - s._filename = string(buffer, name_length); - delete[] buffer; - - s._index_length = (size_t)_in.tellg() - s._index_start - _read_offset; - - if (flags & SF_signature) { - // A subfile with this bit set is a signature. - _cert_special.push_back(s); - } else { - // Otherwise, it's a regular file. - _last_data_byte = max(_last_data_byte, s.get_last_byte_pos()); - - if ((flags & SF_ignore) == 0) { - // We can only support subfiles with none of SF_ignore set. - _subfiles.push_back(s); - } - } - - _in.seekg(next_entry + _read_offset); - next_entry = read_uint32(); - if (!_in) { - return false; - } - } - - return true; -} - -/** - * Extracts the indicated subfile and writes it to the indicated stream. - * Returns true on success, false on failure. - */ -bool P3DMultifileReader:: -extract_subfile(std::ostream &out, const Subfile &s) { - _in.seekg(s._data_start + _read_offset); - - static const streamsize buffer_size = 4096; - char buffer[buffer_size]; - - streamsize remaining_data = s._data_length; - _in.read(buffer, min(buffer_size, remaining_data)); - streamsize count = _in.gcount(); - while (count != 0) { - remaining_data -= count; - out.write(buffer, count); - _in.read(buffer, min(buffer_size, remaining_data)); - count = _in.gcount(); - } - - if (remaining_data != 0) { - nout << "Unable to extract " << s._filename << "\n"; - return false; - } - - return true; -} - - -/** - * Walks through the list of _cert_special entries in the Multifile, moving - * any valid signatures found to _signatures. After this call, _cert_special - * will be empty. - * - * This does not check the validity of the certificates themselves. It only - * checks that they correctly sign the Multifile contents. - */ -void P3DMultifileReader:: -check_signatures() { - Subfiles::iterator pi; - - for (pi = _cert_special.begin(); pi != _cert_special.end(); ++pi) { - Subfile *subfile = &(*pi); - - // Extract the signature data and certificate separately. - _in.seekg(subfile->_data_start + _read_offset); - size_t sig_size = read_uint32(); - char *sig = new char[sig_size]; - _in.read(sig, sig_size); - if (_in.gcount() != sig_size) { - nout << "read failure\n"; - delete[] sig; - return; - } - - size_t num_certs = read_uint32(); - - // Read the remaining buffer of certificate data. - size_t bytes_read = (size_t)_in.tellg() - subfile->_data_start - _read_offset; - size_t buffer_size = subfile->_data_length - bytes_read; - char *buffer = new char[buffer_size]; - _in.read(buffer, buffer_size); - if (_in.gcount() != buffer_size) { - nout << "read failure\n"; - delete[] sig; - delete[] buffer; - return; - } - - // Now convert each of the certificates to an X509 object, and store it in - // our CertChain. - CertChain chain; - EVP_PKEY *pkey = nullptr; - if (buffer_size > 0) { -#if OPENSSL_VERSION_NUMBER >= 0x00908000L - // Beginning in 0.9.8, d2i_X509() accepted a const unsigned char **. - const unsigned char *bp, *bp_end; -#else - // Prior to 0.9.8, d2i_X509() accepted an unsigned char **. - unsigned char *bp, *bp_end; -#endif - bp = (unsigned char *)&buffer[0]; - bp_end = bp + buffer_size; - X509 *x509 = d2i_X509(nullptr, &bp, bp_end - bp); - while (num_certs > 0 && x509 != nullptr) { - chain.push_back(CertRecord(x509)); - --num_certs; - x509 = d2i_X509(nullptr, &bp, bp_end - bp); - } - if (num_certs != 0 || x509 != nullptr) { - nout << "Extra data in signature record.\n"; - } - } - - delete[] buffer; - - if (!chain.empty()) { - pkey = X509_get_pubkey(chain[0]._cert); - } - - if (pkey != nullptr) { - EVP_MD_CTX *md_ctx; -#if OPENSSL_VERSION_NUMBER >= 0x00907000L - md_ctx = EVP_MD_CTX_create(); -#else - md_ctx = new EVP_MD_CTX; -#endif - EVP_VerifyInit(md_ctx, EVP_sha1()); - - // Read and hash the multifile contents, but only up till - // _last_data_byte. - _in.seekg(_read_offset); - streampos bytes_remaining = (streampos)_last_data_byte; - static const streamsize buffer_size = 4096; - char buffer[buffer_size]; - _in.read(buffer, min((streampos)buffer_size, bytes_remaining)); - streamsize count = _in.gcount(); - while (count != 0) { - assert(count <= buffer_size); - EVP_VerifyUpdate(md_ctx, buffer, (size_t)count); - bytes_remaining -= count; - _in.read(buffer, min((streampos)buffer_size, bytes_remaining)); - count = _in.gcount(); - } - assert(bytes_remaining == (streampos)0); - - // Now check that the signature matches the hash. - int verify_result = - EVP_VerifyFinal(md_ctx, (unsigned char *)sig, - sig_size, pkey); - if (verify_result == 1) { - // The signature matches; save the certificate and its chain. - _signatures.push_back(chain); - } - } - - delete[] sig; - } - - _cert_special.clear(); -} diff --git a/direct/src/plugin/p3dMultifileReader.h b/direct/src/plugin/p3dMultifileReader.h deleted file mode 100644 index 8f80a1f67c..0000000000 --- a/direct/src/plugin/p3dMultifileReader.h +++ /dev/null @@ -1,104 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dMultifileReader.h - * @author drose - * @date 2009-06-15 - */ - -#ifndef P3DMULTIFILEREADER_H -#define P3DMULTIFILEREADER_H - -#include "p3d_plugin_common.h" -#include "p3dInstanceManager.h" // for openssl -#include "p3dPackage.h" - -/** - * A way-simple implementation of Panda's multifile reader. See - * panda/src/express/multifile.cxx for a full description of the binary - * format. This implementation doesn't support per-subfile compression or - * encryption. - */ -class P3DMultifileReader { -public: - P3DMultifileReader(); - bool open_read(const std::string &pathname, const int &offset = 0); - inline bool is_open() const; - void close(); - - bool extract_all(const std::string &to_dir, P3DPackage *package, - P3DPackage::InstallStepThreaded *step); - - bool extract_one(std::ostream &out, const std::string &filename); - - class CertRecord { - public: - inline CertRecord(X509 *cert); - inline CertRecord(const CertRecord ©); - inline ~CertRecord(); - X509 *_cert; - }; - typedef std::vector CertChain; - int get_num_signatures() const; - const CertChain &get_signature(int n) const; - -private: - class Subfile; - - bool read_header(const std::string &pathname); - bool read_index(); - bool extract_subfile(std::ostream &out, const Subfile &s); - - void check_signatures(); - - inline unsigned int read_uint16(); - inline unsigned int read_uint32(); - - enum SubfileFlags { - // If any of these bits are set, we can't read the subfile. - SF_ignore = 0x003f, - - // These bits are also relevant, and specifically so. - SF_compressed = 0x0008, - SF_encrypted = 0x0010, - SF_signature = 0x0020, - }; - - class Subfile { - public: - inline size_t get_last_byte_pos() const; - - std::string _filename; - size_t _index_start; - size_t _index_length; - size_t _data_start; - size_t _data_length; - size_t _timestamp; - }; - - ifstream _in; - bool _is_open; - int _read_offset; - - typedef std::vector Subfiles; - Subfiles _subfiles; - Subfiles _cert_special; - size_t _last_data_byte; - - typedef std::vector Certificates; - Certificates _signatures; - - static const char _header[]; - static const size_t _header_size; - static const int _current_major_ver; - static const int _current_minor_ver; -}; - -#include "p3dMultifileReader.I" - -#endif diff --git a/direct/src/plugin/p3dNoneObject.cxx b/direct/src/plugin/p3dNoneObject.cxx deleted file mode 100644 index 2a1653a2b8..0000000000 --- a/direct/src/plugin/p3dNoneObject.cxx +++ /dev/null @@ -1,46 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dNoneObject.cxx - * @author drose - * @date 2009-06-30 - */ - -#include "p3dNoneObject.h" - -/** - * - */ -P3DNoneObject:: -P3DNoneObject() { -} - -/** - * Returns the fundamental type of this kind of object. - */ -P3D_object_type P3DNoneObject:: -get_type() { - return P3D_OT_none; -} - -/** - * Returns the object value coerced to a boolean, if possible. - */ -bool P3DNoneObject:: -get_bool() { - return false; -} - -/** - * Fills the indicated C++ string object with the value of this object coerced - * to a string. - */ -void P3DNoneObject:: -make_string(std::string &value) { - value = "None"; -} diff --git a/direct/src/plugin/p3dNoneObject.h b/direct/src/plugin/p3dNoneObject.h deleted file mode 100644 index 06fffe89f9..0000000000 --- a/direct/src/plugin/p3dNoneObject.h +++ /dev/null @@ -1,34 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dNoneObject.h - * @author drose - * @date 2009-06-30 - */ - -#ifndef P3DNONEOBJECT_H -#define P3DNONEOBJECT_H - -#include "p3d_plugin_common.h" -#include "p3dObject.h" - -/** - * An object type that contains no value, similar to Python's None type, or - * JavaScript's null type. - */ -class P3DNoneObject : public P3DObject { -public: - P3DNoneObject(); - -public: - virtual P3D_object_type get_type(); - virtual bool get_bool(); - virtual void make_string(std::string &value); -}; - -#endif diff --git a/direct/src/plugin/p3dObject.I b/direct/src/plugin/p3dObject.I deleted file mode 100644 index 2911760832..0000000000 --- a/direct/src/plugin/p3dObject.I +++ /dev/null @@ -1,33 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dObject.I - * @author drose - * @date 2009-06-30 - */ - -/** - * - */ -inline P3DObject:: -P3DObject() { - _class = &_object_class; - - // The reference count is initially 1. - _ref_count = 1; -} - -/** - * - */ -inline P3DObject:: -P3DObject(const P3DObject ©) { - assert(copy._class == &_object_class); - _class = copy._class; - _ref_count = 1; -} diff --git a/direct/src/plugin/p3dObject.cxx b/direct/src/plugin/p3dObject.cxx deleted file mode 100644 index f34f2d6d2d..0000000000 --- a/direct/src/plugin/p3dObject.cxx +++ /dev/null @@ -1,459 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dObject.cxx - * @author drose - * @date 2009-06-30 - */ - -#include "p3dObject.h" -#include "p3dBoolObject.h" -#include "p3dIntObject.h" -#include "p3dFloatObject.h" -#include "p3dStringObject.h" -#include "p3dInstanceManager.h" -#include // strncpy - -using std::string; - -// The following functions are C-style wrappers around the below P3DObject -// virtual methods; they are defined to allow us to create the C-style -// P3D_class_definition method table to store in the P3D_object structure. -static void -object_finish(P3D_object *object) { - delete (P3DObject *)object; -} - -static P3D_object_type -object_get_type(P3D_object *object) { - return ((P3DObject *)object)->get_type(); -} - -static bool -object_get_bool(P3D_object *object) { - return ((P3DObject *)object)->get_bool(); -} - -static int -object_get_int(P3D_object *object) { - return ((P3DObject *)object)->get_int(); -} - -static double -object_get_float(P3D_object *object) { - return ((P3DObject *)object)->get_float(); -} - -static int -object_get_string(P3D_object *object, char *buffer, int buffer_length) { - return ((P3DObject *)object)->get_string(buffer, buffer_length); -} - -static int -object_get_repr(P3D_object *object, char *buffer, int buffer_length) { - return ((P3DObject *)object)->get_repr(buffer, buffer_length); -} - -static P3D_object * -object_get_property(P3D_object *object, const char *property) { - return ((P3DObject *)object)->get_property(property); -} - -static bool -object_set_property(P3D_object *object, const char *property, - bool needs_response, P3D_object *value) { - return ((P3DObject *)object)->set_property(property, needs_response, value); -} - -static bool -object_has_method(P3D_object *object, const char *method_name) { - return ((P3DObject *)object)->has_method(method_name); -} - -static P3D_object * -object_call(P3D_object *object, const char *method_name, - bool needs_response, - P3D_object *params[], int num_params) { - if (method_name == nullptr) { - method_name = ""; - } - return ((P3DObject *)object)->call(method_name, needs_response, params, num_params); -} - -static P3D_object * -object_eval(P3D_object *object, const char *expression) { - return ((P3DObject *)object)->eval(expression); -} - -P3D_class_definition P3DObject::_object_class = { - &object_finish, - &object_get_type, - &object_get_bool, - &object_get_int, - &object_get_float, - &object_get_string, - &object_get_repr, - &object_get_property, - &object_set_property, - &object_has_method, - &object_call, - &object_eval, -}; - -// The next functions are used to construct the generic P3D_class_definition -// class returned by P3D_make_class_definition(). These are pointers to no-op -// functions, which the host may or may not choose to override. -static void -generic_finish(P3D_object *object) { - // You must override finish(), though, otherwise it's a leak. The core API - // has no idea how to delete your object. - nout << "Warning! default object_finish() method does nothing; object will leak.\n"; -} - -static P3D_object_type -generic_get_type(P3D_object *object) { - // We assume anyone going through the trouble of subclassing this will want - // to return an object, not one of the other fundamental types. - return P3D_OT_object; -} - -static bool -generic_get_bool(P3D_object *object) { - return false; -} - -static int -generic_get_int(P3D_object *object) { - return 0; -} - -static double -generic_get_float(P3D_object *object) { - return 0.0; -} - -static int -generic_get_string(P3D_object *object, char *buffer, int buffer_length) { - return 0; -} - -static int -generic_get_repr(P3D_object *object, char *buffer, int buffer_length) { - return 0; -} - -static P3D_object * -generic_get_property(P3D_object *object, const char *property) { - return nullptr; -} - -static bool -generic_set_property(P3D_object *object, const char *property, - bool needs_response, P3D_object *value) { - return false; -} - -static bool -generic_has_method(P3D_object *object, const char *method_name) { - return false; -} - -static P3D_object * -generic_call(P3D_object *object, const char *method_name, - bool needs_response, P3D_object *params[], int num_params) { - return nullptr; -} - -static P3D_object * -generic_eval(P3D_object *object, const char *expression) { - return nullptr; -} - -P3D_class_definition P3DObject::_generic_class = { - &generic_finish, - &generic_get_type, - &generic_get_bool, - &generic_get_int, - &generic_get_float, - &generic_get_string, - &generic_get_repr, - &generic_get_property, - &generic_set_property, - &generic_has_method, - &generic_call, - &generic_eval, -}; - -/** - * - */ -P3DObject:: -~P3DObject() { - assert(_ref_count == 0); -} - -/** - * Returns the object value coerced to an integer, if possible. - */ -int P3DObject:: -get_int() { - return 0; -} - -/** - * Returns the object value coerced to a floating-point value, if possible. - */ -double P3DObject:: -get_float() { - return get_int(); -} - -/** - * Stores a string that represents the object value in the indicated buffer; a - * null character is included if there is space. Returns the number of - * characters needed in the output (which might be more than the actual number - * of characters stored if buffer_length was too small). - */ -int P3DObject:: -get_string(char *buffer, int buffer_length) { - string result; - make_string(result); - strncpy(buffer, result.c_str(), buffer_length); - return (int)result.size(); -} - -/** - * Returns a user-friendly representation of the object, similar to - * get_string(), above. - */ -int P3DObject:: -get_repr(char *buffer, int buffer_length) { - std::ostringstream strm; - output(strm); - string result = strm.str(); - strncpy(buffer, result.c_str(), buffer_length); - return (int)result.size(); -} - -/** - * Returns the named property element in the object. The return value is a - * new-reference P3D_object, or NULL on error. - */ -P3D_object *P3DObject:: -get_property(const string &property) { - return nullptr; -} - -/** - * Modifies (or deletes, if value is NULL) the named property element in the - * object. Returns true on success, false on failure. - */ -bool P3DObject:: -set_property(const string &property, bool needs_response, P3D_object *value) { - return false; -} - -/** - * Returns true if the named method exists on this object, false otherwise. - */ -bool P3DObject:: -has_method(const string &method_name) { - return false; -} - -/** - * Invokes the named method on the object, passing the indicated parameters. - * If the method name is empty, invokes the object itself. - * - * If needs_response is true, the return value is a new-reference P3D_object - * on success, or NULL on failure. If needs_response is false, the return - * value is always NULL, and there is no way to determine success or failure. - */ -P3D_object *P3DObject:: -call(const string &method_name, bool needs_response, - P3D_object *params[], int num_params) { - return nullptr; -} - -/** - * Evaluates an arbitrary JavaScript expression. None of the P3DObject - * classes implement this. - */ -P3D_object *P3DObject:: -eval(const string &expression) { - return nullptr; -} - -/** - * Writes a formatted representation of the value to the indicated string. - * This is intended for developer assistance. - */ -void P3DObject:: -output(std::ostream &out) { - string value; - make_string(value); - out << value; -} - -/** - * If this object has a valid XML representation for the indicated session - * (that hasn't already been implemented by the generic code in P3DSession), - * this method will apply it to the indicated "value" element and return true. - * Otherwise, this method will leave the element unchanged and return false. - */ -bool P3DObject:: -fill_xml(TiXmlElement *xvalue, P3DSession *session) { - return false; -} - -/** - * Returns a pointer to the array of objects represented by this object, if - * any, or NULL if the object does not represent an array of objects. This - * may also return NULL for a zero-length array; use get_object_array_size() - * to differentiate. - */ -P3D_object **P3DObject:: -get_object_array() { - return nullptr; -} - -/** - * Returns the number of elements in the array returned by get_object_array(), - * or -1 if this object does not representan array of objects. - */ -int P3DObject:: -get_object_array_size() { - return -1; -} - -/** - * Returns this object, downcast to a P3DPythonObject, if it is in fact an - * object of that type; or NULL if it is not. - */ -P3DPythonObject *P3DObject:: -as_python_object() { - return nullptr; -} - -/** - * Returns the value of the named property, as a boolean. Returns 0 if the - * property does not exist. - */ -bool P3DObject:: -get_bool_property(const string &property) { - P3D_object *result = get_property(property); - if (result == nullptr) { - return 0; - } - bool bresult = P3D_OBJECT_GET_BOOL(result); - P3D_OBJECT_DECREF(result); - return bresult; -} - -/** - * Changes the value of the named property to the indicated boolean value. - */ -void P3DObject:: -set_bool_property(const string &property, bool value) { - P3D_object *bvalue = new P3DBoolObject(value); - set_property(property, false, bvalue); - P3D_OBJECT_DECREF(bvalue); -} - -/** - * Returns the value of the named property, as an integer. Returns 0 if the - * property does not exist. - */ -int P3DObject:: -get_int_property(const string &property) { - P3D_object *result = get_property(property); - if (result == nullptr) { - return 0; - } - int iresult = P3D_OBJECT_GET_INT(result); - P3D_OBJECT_DECREF(result); - return iresult; -} - -/** - * Changes the value of the named property to the indicated integer value. - */ -void P3DObject:: -set_int_property(const string &property, int value) { - P3D_object *ivalue = new P3DIntObject(value); - set_property(property, false, ivalue); - P3D_OBJECT_DECREF(ivalue); -} - -/** - * Returns the value of the named property, as a floating-point number. - * Returns 0.0 if the property does not exist. - */ -double P3DObject:: -get_float_property(const string &property) { - P3D_object *result = get_property(property); - if (result == nullptr) { - return 0.0; - } - double fresult = P3D_OBJECT_GET_FLOAT(result); - P3D_OBJECT_DECREF(result); - return fresult; -} - -/** - * Changes the value of the named property to the indicated floating-point - * value. - */ -void P3DObject:: -set_float_property(const string &property, double value) { - P3D_object *fvalue = new P3DFloatObject(value); - set_property(property, false, fvalue); - P3D_OBJECT_DECREF(fvalue); -} - -/** - * Returns the value of the named property, as a string. Returns empty string - * if the property does not exist. - */ -string P3DObject:: -get_string_property(const string &property) { - P3D_object *result = get_property(property); - if (result == nullptr) { - return string(); - } - - int size = P3D_OBJECT_GET_STRING(result, nullptr, 0); - char *buffer = new char[size]; - P3D_OBJECT_GET_STRING(result, buffer, size); - string sresult(buffer, size); - delete[] buffer; - - P3D_OBJECT_DECREF(result); - return sresult; -} - -/** - * Changes the value of the named property to the indicated string value. - */ -void P3DObject:: -set_string_property(const string &property, const string &value) { - P3D_object *svalue = new P3DStringObject(value); - set_property(property, false, svalue); - P3D_OBJECT_DECREF(svalue); -} - -/** - * Changes the value of the named property to the undefined value. - */ -void P3DObject:: -set_undefined_property(const string &property) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3D_object *uvalue = inst_mgr->new_undefined_object(); - set_property(property, false, uvalue); - P3D_OBJECT_DECREF(uvalue); -} diff --git a/direct/src/plugin/p3dObject.h b/direct/src/plugin/p3dObject.h deleted file mode 100644 index 8e69e5bec7..0000000000 --- a/direct/src/plugin/p3dObject.h +++ /dev/null @@ -1,91 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dObject.h - * @author drose - * @date 2009-06-30 - */ - -#ifndef P3DOBJECT_H -#define P3DOBJECT_H - -#include "p3d_plugin_common.h" - -class P3DPythonObject; - -/** - * The C++ implementation of P3D_value, corresponding to a single atomic value - * that is passed around between scripting languages. This is an abstract - * base class; the actual implementations are provided by the various - * specialized classes. - */ -class P3DObject : public P3D_object { -protected: - inline P3DObject(); - inline P3DObject(const P3DObject ©); - -public: - virtual ~P3DObject(); - - virtual P3D_object_type get_type()=0; - virtual bool get_bool()=0; - virtual int get_int(); - virtual double get_float(); - - int get_string(char *buffer, int buffer_length); - int get_repr(char *buffer, int buffer_length); - virtual void make_string(std::string &value)=0; - - virtual P3D_object *get_property(const std::string &property); - virtual bool set_property(const std::string &property, bool needs_response, - P3D_object *value); - - virtual bool has_method(const std::string &method_name); - virtual P3D_object *call(const std::string &method_name, bool needs_response, - P3D_object *params[], int num_params); - virtual P3D_object *eval(const std::string &expression); - - virtual void output(std::ostream &out); - virtual bool fill_xml(TiXmlElement *xvalue, P3DSession *session); - virtual P3D_object **get_object_array(); - virtual int get_object_array_size(); - - virtual P3DPythonObject *as_python_object(); - - // Convenience functions. - bool get_bool_property(const std::string &property); - void set_bool_property(const std::string &property, bool value); - - int get_int_property(const std::string &property); - void set_int_property(const std::string &property, int value); - - double get_float_property(const std::string &property); - void set_float_property(const std::string &property, double value); - - std::string get_string_property(const std::string &property); - void set_string_property(const std::string &property, const std::string &value); - - void set_undefined_property(const std::string &property); - -public: - static P3D_class_definition _object_class; - static P3D_class_definition _generic_class; -}; - -#include "p3dObject.I" - -// For classes that inherit from P3DObject, above, we can use the virtual -// method to write the output simply. (For classes that inherit only from -// P3D_object, we have to use the generic C method defined in -// p3d_plugin_common.h, a little clumsier.) -inline std::ostream &operator << (std::ostream &out, P3DObject &value) { - value.output(out); - return out; -} - -#endif diff --git a/direct/src/plugin/p3dOsxSplashWindow.I b/direct/src/plugin/p3dOsxSplashWindow.I deleted file mode 100644 index a9573dafa4..0000000000 --- a/direct/src/plugin/p3dOsxSplashWindow.I +++ /dev/null @@ -1,32 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dOsxSplashWindow.I - * @author drose - * @date 2009-07-16 - */ - -/** - * - */ -inline P3DOsxSplashWindow::OsxImageData:: -OsxImageData() { - _raw_data = nullptr; - _image = nullptr; - _color_space = nullptr; - _provider = nullptr; - _data = nullptr; -} - -/** - * - */ -inline P3DOsxSplashWindow::OsxImageData:: -~OsxImageData() { - dump_image(); -} diff --git a/direct/src/plugin/p3dOsxSplashWindow.cxx b/direct/src/plugin/p3dOsxSplashWindow.cxx deleted file mode 100644 index 4139a9629d..0000000000 --- a/direct/src/plugin/p3dOsxSplashWindow.cxx +++ /dev/null @@ -1,827 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dOsxSplashWindow.cxx - * @author drose - * @date 2009-07-16 - */ - -#include "p3dOsxSplashWindow.h" - -#if defined(__APPLE__) && !__LP64__ - -#include -#include - -#ifndef CGFLOAT_DEFINED - #if defined(__LP64__) && __LP64__ - typedef double CGFloat; - #else - typedef float CGFloat; - #endif -#endif - -using std::string; - -/** - * - */ -P3DOsxSplashWindow:: -P3DOsxSplashWindow(P3DInstance *inst, bool make_visible) : - P3DSplashWindow(inst, make_visible) -{ - _font_attribs = nullptr; - _install_progress = 0; - _progress_known = true; - _received_data = 0; - _got_wparams = false; - // We have to start with _mouse_active true; firefox doesn't send activate - // events. - _mouse_active = true; - _toplevel_window = nullptr; -} - -/** - * - */ -P3DOsxSplashWindow:: -~P3DOsxSplashWindow() { - if (_toplevel_window != nullptr) { - SetWRefCon(_toplevel_window, 0); - HideWindow(_toplevel_window); - DisposeWindow(_toplevel_window); - _toplevel_window = nullptr; - } - if (_font_attribs != nullptr) { - CFRelease(_font_attribs); - } -} - -/** - * Changes the window parameters, e.g. to resize or reposition the window; or - * sets the parameters for the first time, creating the initial window. - */ -void P3DOsxSplashWindow:: -set_wparams(const P3DWindowParams &wparams) { - P3DSplashWindow::set_wparams(wparams); - _got_wparams = true; - - if (_wparams.get_window_type() == P3D_WT_toplevel || - _wparams.get_window_type() == P3D_WT_fullscreen) { - // Creating a toplevel splash window. - if (_toplevel_window == nullptr) { - Rect r; - r.top = _wparams.get_win_y(); - r.left = _wparams.get_win_x(); - - // These are the same defaults used by Panda's osxGraphicsWindow. - if (r.left == -1) r.left = 10; - if (r.top == -1) r.top = 50; - // A coordinate of -2 means to center the window on the screen. - CGRect display_bounds = CGDisplayBounds(kCGDirectMainDisplay); - if (r.left == -2) { - r.left = (short)(0.5 * (CGRectGetWidth(display_bounds) - _win_width)); - } - if (r.top == -2) { - r.top = (short)(0.5 * (CGRectGetHeight(display_bounds) - _win_height)); - } - - r.right = r.left + _win_width; - r.bottom = r.top + _win_height; - WindowAttributes attrib = - kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute; - CreateNewWindow(kDocumentWindowClass, attrib, &r, &_toplevel_window); - - EventHandlerRef application_event_ref_ref1; - EventTypeSpec list1[] = { - { kEventClassWindow, kEventWindowDrawContent }, - { kEventClassWindow, kEventWindowBoundsChanged }, - { kEventClassWindow, kEventWindowClose }, - { kEventClassMouse, kEventMouseUp }, - { kEventClassMouse, kEventMouseDown }, - { kEventClassMouse, kEventMouseMoved }, - { kEventClassMouse, kEventMouseDragged }, - }; - - EventHandlerUPP gEvtHandler = NewEventHandlerUPP(st_event_callback); - InstallWindowEventHandler(_toplevel_window, gEvtHandler, - GetEventTypeCount(list1), list1, this, &application_event_ref_ref1); - - ProcessSerialNumber psn = { 0, kCurrentProcess }; - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - SetFrontProcess(&psn); - - if (_visible) { - ShowWindow(_toplevel_window); - } - } - } - - // Determine the attributes of the font we're going to use. - int symbolic = 0; - if (_font_style != FS_normal) { - symbolic |= kCTFontItalicTrait; - } - if (_font_weight > 500) { - symbolic |= kCTFontBoldTrait; - } - CFNumberRef symbolic_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &symbolic); - - CFStringRef traits_keys[1] = { kCTFontSymbolicTrait }; - CFTypeRef traits_values[1] = { symbolic_ref }; - CFDictionaryRef traits = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&traits_keys, (const void **)&traits_values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - CFStringRef family = CFStringCreateWithCString(nullptr, _font_family.c_str(), kCFStringEncodingUTF8); - - CFStringRef attribs_keys[2] = { kCTFontFamilyNameAttribute, kCTFontTraitsAttribute }; - CFTypeRef attribs_values[2] = { family, traits }; - CFDictionaryRef attribs = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&attribs_keys, (const void **)&attribs_values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - // Create the font object. - CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes(attribs); - CTFontRef font = CTFontCreateWithFontDescriptor(font_desc, _font_size, nullptr); - - CFStringRef keys[1] = { kCTFontAttributeName }; - CFTypeRef values[1] = { font }; - _font_attribs = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&keys, (const void **)&values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - CFRelease(font); - CFRelease(font_desc); - CFRelease(attribs); - CFRelease(traits); - CFRelease(family); - CFRelease(symbolic_ref); -} - -/** - * Makes the splash window visible or invisible, so as not to compete with the - * embedded Panda window in the same space. - */ -void P3DOsxSplashWindow:: -set_visible(bool visible) { - P3DSplashWindow::set_visible(visible); - - if (_toplevel_window != nullptr) { - if (_visible) { - ShowWindow(_toplevel_window); - } else { - HideWindow(_toplevel_window); - } - } - refresh(); -} - -/** - * Specifies the name of a JPEG image file that is displayed in the center of - * the splash window. - */ -void P3DOsxSplashWindow:: -set_image_filename(const string &image_filename, ImagePlacement image_placement) { - switch (image_placement) { - case IP_background: - load_image(_background_image, image_filename); - break; - - case IP_button_ready: - load_image(_button_ready_image, image_filename); - set_button_range(_button_ready_image); - break; - - case IP_button_rollover: - load_image(_button_rollover_image, image_filename); - break; - - case IP_button_click: - load_image(_button_click_image, image_filename); - break; - - default: - return; - } - - refresh(); -} - -/** - * Specifies the text that is displayed above the install progress bar. - */ -void P3DOsxSplashWindow:: -set_install_label(const string &install_label) { - _install_label = install_label; - refresh(); -} - -/** - * Moves the install progress bar from 0.0 to 1.0. - */ -void P3DOsxSplashWindow:: -set_install_progress(double install_progress, - bool is_progress_known, size_t received_data) { - // Only request a refresh if we're changing substantially. - if (is_progress_known != _progress_known) { - refresh(); - } else if (_progress_known) { - if ((int)(install_progress * 500.0) != (int)(_install_progress * 500.0)) { - refresh(); - } - } else { - if ((int)(received_data * _unknown_progress_rate) != - (int)(_received_data * _unknown_progress_rate)) { - refresh(); - } - } - - _install_progress = install_progress; - _progress_known = is_progress_known; - _received_data = received_data; -} - -/** - * Deals with the event callback from the OS window system. Returns true if - * the event is handled, false if ignored. - */ -bool P3DOsxSplashWindow:: -handle_event(const P3D_event_data &event) { - bool retval = false; - - if (event._event_type == P3D_ET_osx_event_record) { - retval = handle_event_osx_event_record(event); - } else if (event._event_type == P3D_ET_osx_cocoa) { - retval = handle_event_osx_cocoa(event); - } else { - assert(false); - } - - return retval; -} - -/** - * Requests that the window will be repainted. - */ -void P3DOsxSplashWindow:: -refresh() { - if (!_visible) { - return; - } - if (_toplevel_window != nullptr) { - Rect r = { 0, 0, (short)_win_height, (short)_win_width }; - InvalWindowRect(_toplevel_window, &r); - - } else { - _inst->request_refresh(); - } -} - -/** - * Redraws the current splash window. - */ -void P3DOsxSplashWindow:: -paint_window() { - if (!_visible) { - return; - } - - if (_toplevel_window != nullptr || - _wparams.get_parent_window()._window_handle_type == P3D_WHT_osx_port) { - - // The old QuickDraw-style window handle. We use CreateCGContextForPort() - // to map this to the new CoreGraphics-style. - GrafPtr out_port = nullptr; - if (_toplevel_window != nullptr) { - GetPort(&out_port); - - } else { - const P3D_window_handle &handle = _wparams.get_parent_window(); - assert(handle._window_handle_type == P3D_WHT_osx_port); - out_port = handle._handle._osx_port._port; - } - - CGContextRef context; - OSStatus err = CreateCGContextForPort(out_port, &context); - if (err != noErr) { - nout << "Couldn't create CG context\n"; - return; - } - - // Adjust for any SetOrigin calls on out_port - SyncCGContextOriginWithPort(context, out_port); - - // Move the CG origin to the upper left of the port - Rect port_rect; - GetPortBounds(out_port, &port_rect); - CGContextTranslateCTM(context, 0, (float)(port_rect.bottom - port_rect.top)); - - // Flip the y axis so that positive Y points down - CGContextScaleCTM(context, 1.0, -1.0); - - paint_window_osx_cgcontext(context); - - // We need to synchronize, or we don't see the update every frame. - CGContextSynchronize(context); - CGContextRelease(context); - - } else { - // The new CoreGraphics-style window handle. We can draw to this - // directly. - - const P3D_window_handle &handle = _wparams.get_parent_window(); - assert(handle._window_handle_type == P3D_WHT_osx_cgcontext); - CGContextRef context = handle._handle._osx_cgcontext._context; - - paint_window_osx_cgcontext(context); - } -} - -/** - * Redraws the current splash window, using the new CoreGraphics interface. - */ -void P3DOsxSplashWindow:: -paint_window_osx_cgcontext(CGContextRef context) { - // Clear the whole region to the background color before beginning. - CGFloat bg_components[] = { _bgcolor_r / 255.0f, _bgcolor_g / 255.0f, _bgcolor_b / 255.0f, 1 }; - CGColorSpaceRef rgb_space = CGColorSpaceCreateDeviceRGB(); - CGColorRef bg = CGColorCreate(rgb_space, bg_components); - - CGRect region = { { 0, 0 }, { (CGFloat)_win_width, (CGFloat)_win_height } }; - CGContextSetFillColorWithColor(context, bg); - CGContextFillRect(context, region); - - CGColorRelease(bg); - CGColorSpaceRelease(rgb_space); - - // Now paint in the image(s). - paint_image(context, _background_image); - switch (_bstate) { - case BS_hidden: - break; - case BS_ready: - paint_image(context, _button_ready_image); - break; - case BS_rollover: - if (!paint_image(context, _button_rollover_image)) { - paint_image(context, _button_ready_image); - } - break; - case BS_click: - if (!paint_image(context, _button_click_image)) { - paint_image(context, _button_ready_image); - } - break; - } - - // Draw the progress bar. We don't draw this bar at all unless we have - // nonzero progress. - if (!_progress_known || _install_progress != 0.0) { - paint_progress_bar(context); - } -} - -/** - * Responds to the deprecated Carbon event types in Mac OSX. - */ -bool P3DOsxSplashWindow:: -handle_event_osx_event_record(const P3D_event_data &event) { - assert(event._event_type == P3D_ET_osx_event_record); - EventRecord *er = event._event._osx_event_record._event; - - Point pt = er->where; - - // Need to ensure we have the correct port set, in order to convert the - // mouse coordinates successfully via GlobalToLocal(). - const P3D_window_handle &handle = _wparams.get_parent_window(); - if (handle._window_handle_type == P3D_WHT_osx_port) { - GrafPtr out_port = handle._handle._osx_port._port; - GrafPtr port_save = nullptr; - Boolean port_changed = QDSwapPort(out_port, &port_save); - - GlobalToLocal(&pt); - - if (port_changed) { - QDSwapPort(port_save, nullptr); - } - - } else if (handle._window_handle_type == P3D_WHT_osx_cgcontext) { - // First, convert the coordinates from screen coordinates to browser - // window coordinates. - WindowRef window = handle._handle._osx_cgcontext._window; - CGPoint cgpt = { (CGFloat)pt.h, (CGFloat)pt.v }; - HIPointConvert(&cgpt, kHICoordSpaceScreenPixel, nullptr, - kHICoordSpaceWindow, window); - - // Then convert to plugin coordinates. - pt.h = (short)(cgpt.x - _wparams.get_win_x()); - pt.v = (short)(cgpt.y - _wparams.get_win_y()); - } - - switch (er->what) { - case updateEvt: - paint_window(); - break; - - case mouseDown: - set_mouse_data(_mouse_x, _mouse_y, true); - break; - - case mouseUp: - set_mouse_data(_mouse_x, _mouse_y, false); - break; - - case activateEvt: - _mouse_active = ((er->modifiers & 1) != 0); - break; - - default: - break; - } - - if (_mouse_active) { - set_mouse_data(pt.h, pt.v, _mouse_down); - } - - return false; -} - -/** - * Responds to the new Cocoa event types in Mac OSX. - */ -bool P3DOsxSplashWindow:: -handle_event_osx_cocoa(const P3D_event_data &event) { - assert(event._event_type == P3D_ET_osx_cocoa); - const P3DCocoaEvent &ce = event._event._osx_cocoa._event; - - switch (ce.type) { - case P3DCocoaEventDrawRect: - if (_visible) { - CGContextRef context = ce.data.draw.context; - paint_window_osx_cgcontext(context); - return true; - } else { - return false; - } - - case P3DCocoaEventMouseDown: - set_mouse_data((int)ce.data.mouse.pluginX, (int)ce.data.mouse.pluginY, true); - return true; - - case P3DCocoaEventMouseUp: - set_mouse_data((int)ce.data.mouse.pluginX, (int)ce.data.mouse.pluginY, false); - return true; - - case P3DCocoaEventMouseMoved: - case P3DCocoaEventMouseDragged: - set_mouse_data((int)ce.data.mouse.pluginX, (int)ce.data.mouse.pluginY, _mouse_down); - return true; - - case P3DCocoaEventFocusChanged: - _mouse_active = (ce.data.focus.hasFocus != 0); - return true; - - default: - return false; - } -} - -/** - * Loads the named image file into an OsxImageData object. - */ -void P3DOsxSplashWindow:: -load_image(OsxImageData &image, const string &image_filename) { - image.dump_image(); - string string_data; - if (!read_image_data(image, string_data, image_filename)) { - return; - } - - // Now we need to copy from the RGB (or RGBA) source image into the BGRA - // target image. We also flip the image upside-down here to compensate for - // the upside-down vertical scale on CGContextScaleCTM. - int row_stride = image._width * image._num_channels; - int new_row_stride = image._width * 4; - image._raw_data = new char[new_row_stride * image._height]; - for (int yi = 0; yi < image._height; ++yi) { - char *dest = image._raw_data + yi * new_row_stride; - const char *source = string_data.data() + (image._height - 1 - yi) * row_stride; - if (image._num_channels == 3) { - // Source is RGB. - for (int xi = 0; xi < image._width; ++xi) { - char r = source[0]; - char g = source[1]; - char b = source[2]; - dest[0] = b; - dest[1] = g; - dest[2] = r; - dest[3] = 0xff; - source += 3; - dest += 4; - } - } else if (image._num_channels == 4) { - // Source is RGBA. - for (int xi = 0; xi < image._width; ++xi) { - char r = source[0]; - char g = source[1]; - char b = source[2]; - char a = source[3]; - // Little-endian. - dest[0] = b; - dest[1] = g; - dest[2] = r; - dest[3] = a; - source += 4; - dest += 4; - } - } - } - - image._data = - CFDataCreateWithBytesNoCopy(nullptr, (const UInt8 *)image._raw_data, - image._height * new_row_stride, kCFAllocatorNull); - image._provider = CGDataProviderCreateWithCFData(image._data); - image._color_space = CGColorSpaceCreateDeviceRGB(); - - image._image = - CGImageCreate(image._width, image._height, 8, 32, - new_row_stride, image._color_space, - kCGImageAlphaFirst | kCGBitmapByteOrder32Little, - image._provider, nullptr, false, kCGRenderingIntentDefault); -} - -/** - * Draws the indicated image, centered within the window. Returns true on - * success, false if the image is not defined. - */ -bool P3DOsxSplashWindow:: -paint_image(CGContextRef context, const OsxImageData &image) { - if (image._image == nullptr) { - return false; - } - - // Determine the relative size of image and window. - int win_cx = _win_width / 2; - int win_cy = _win_height / 2; - - CGRect rect = { { 0, 0 }, { 0, 0 } }; - - if (image._width <= _win_width && image._height <= _win_height) { - // The bitmap fits within the window; center it. - - // This is the top-left corner of the bitmap in window coordinates. - int p_x = win_cx - image._width / 2; - int p_y = win_cy - image._height / 2; - - rect.origin.x += p_x; - rect.origin.y += p_y; - rect.size.width = image._width; - rect.size.height = image._height; - - } else { - // The bitmap is larger than the window; scale it down. - double x_scale = (double)_win_width / (double)image._width; - double y_scale = (double)_win_height / (double)image._height; - double scale = std::min(x_scale, y_scale); - int sc_width = (int)(image._width * scale); - int sc_height = (int)(image._height * scale); - - int p_x = win_cx - sc_width / 2; - int p_y = win_cy - sc_height / 2; - - rect.origin.x += p_x; - rect.origin.y += p_y; - rect.size.width = sc_width; - rect.size.height = sc_height; - } - - CGContextDrawImage(context, rect, image._image); - - return true; -} - -/** - * Draws the progress bar and the label within the window. - */ -void P3DOsxSplashWindow:: -paint_progress_bar(CGContextRef context) { - CGFloat fg_components[] = { _fgcolor_r / 255.0f, _fgcolor_g / 255.0f, _fgcolor_b / 255.0f, 1 }; - CGFloat bg_components[] = { _bgcolor_r / 255.0f, _bgcolor_g / 255.0f, _bgcolor_b / 255.0f, 1 }; - CGFloat bar_components[] = { _barcolor_r / 255.0f, _barcolor_g / 255.0f, _barcolor_b / 255.0f, 1 }; - CGFloat bar_bg_components[] = { _bar_bgcolor_r / 255.0f, _bar_bgcolor_g / 255.0f, _bar_bgcolor_b / 255.0f, 1 }; - CGColorSpaceRef rgb_space = CGColorSpaceCreateDeviceRGB(); - CGColorRef fg = CGColorCreate(rgb_space, fg_components); - CGColorRef bg = CGColorCreate(rgb_space, bg_components); - CGColorRef bar = CGColorCreate(rgb_space, bar_components); - CGColorRef bar_bg = CGColorCreate(rgb_space, bar_bg_components); - - // Get the proper placement for the progress bar. - int bar_x, bar_y, bar_width, bar_height; - get_bar_placement(bar_x, bar_y, bar_width, bar_height); - - CGRect bar_rect = { { (CGFloat)bar_x, (CGFloat)bar_y }, { (CGFloat)bar_width, (CGFloat)bar_height } }; - - // Clear the entire progress bar to white (or the background color). - CGContextSetFillColorWithColor(context, bar_bg); - CGContextFillRect(context, bar_rect); - - // Draw the interior of the progress bar in blue (or the bar color). - if (_progress_known) { - int progress_width = (int)(bar_width * _install_progress + 0.5); - if (progress_width != 0) { - CGRect prog = { { (CGFloat)bar_x, (CGFloat)bar_y }, { (CGFloat)progress_width, (CGFloat)bar_height } }; - CGContextSetFillColorWithColor(context, bar); - CGContextFillRect(context, prog); - } - } else { - // Progress is unknown. Draw a moving block, not a progress bar filling - // up. - int block_width = (int)(bar_width * 0.1 + 0.5); - int block_travel = bar_width - block_width; - int progress = (int)(_received_data * _unknown_progress_rate); - progress = progress % (block_travel * 2); - if (progress > block_travel) { - progress = block_travel * 2 - progress; - } - - CGRect prog = { { (CGFloat)(bar_x + progress), (CGFloat)bar_y }, { (CGFloat)block_width, (CGFloat)bar_height } }; - CGContextSetFillColorWithColor(context, bar); - CGContextFillRect(context, prog); - } - - // Draw the black stroke around the progress bar. - if (_bar_border > 0) { - // We offset the border by half a pixel, so we'll be drawing the one-pixel - // line through the middle of a pixel, and it won't try to antialias - // itself into a half-black two-pixel line. - CGRect border_rect = { { (CGFloat)(bar_x - 0.5), (CGFloat)(bar_y - 0.5) }, - { (CGFloat)(bar_width + 1), (CGFloat)(bar_height + 1) } }; - - CGContextBeginPath(context); - CGContextSetLineWidth(context, 1); - CGContextSetStrokeColorWithColor(context, fg); - - for (int i = 0; i < _bar_border; ++i) { - CGContextAddRect(context, border_rect); - border_rect.origin.x -= 1; - border_rect.origin.y -= 1; - border_rect.size.width += 2; - border_rect.size.height += 2; - } - CGContextStrokePath(context); - } - - if (!_install_label.empty()) { - // Need to invert the text so it won't be upside-down. - CGAffineTransform text_xform = CGAffineTransformMakeScale(1, -1); - CGContextSetTextMatrix(context, text_xform); - - // Now draw the install_label right above it. - CFStringRef string = CFStringCreateWithCString(nullptr, _install_label.c_str(), kCFStringEncodingUTF8); - CFAttributedStringRef attr_string = CFAttributedStringCreate(nullptr, string, _font_attribs); - CTLineRef line = CTLineCreateWithAttributedString(attr_string); - - // Determine the placement based on the size of the text. - CGRect bounds = CTLineGetImageBounds(line, context); - float text_x = (_win_width - bounds.size.width) / 2.0f - bounds.origin.x; - float text_y = bar_y + bounds.origin.y - 4 - _bar_border; - - // And finally, draw the text. - CGContextSetTextPosition(context, text_x, text_y); - CTLineDraw(line, context); - - CFRelease(line); - CFRelease(attr_string); - CFRelease(string); - } - - CGColorRelease(bar_bg); - CGColorRelease(bar); - CGColorRelease(bg); - CGColorRelease(fg); - CGColorSpaceRelease(rgb_space); -} - -/** - * The event callback on the toplevel window. - */ -pascal OSStatus P3DOsxSplashWindow:: -st_event_callback(EventHandlerCallRef my_handler, EventRef event, - void *user_data) { - return ((P3DOsxSplashWindow *)user_data)->event_callback(my_handler, event); -} - -/** - * The event callback on the toplevel window. - */ -OSStatus P3DOsxSplashWindow:: -event_callback(EventHandlerCallRef my_handler, EventRef event) { - OSStatus result = eventNotHandledErr; - - WindowRef window = nullptr; - UInt32 the_class = GetEventClass(event); - UInt32 kind = GetEventKind(event); - GetEventParameter(event, kEventParamWindowRef, typeWindowRef, nullptr, - sizeof(WindowRef), nullptr, (void*) &window); - switch (the_class) { - case kEventClassWindow: - switch (kind) { - case kEventWindowBoundsChanged: - // If the window changes size, we have to repaint it. - refresh(); - - // Also determine the new size. - { - Rect port_rect; - GrafPtr out_port = GetWindowPort(_toplevel_window); - GetPortBounds(out_port, &port_rect); - int width = port_rect.right - port_rect.left; - int height = port_rect.bottom - port_rect.top; - if (width != _win_width || height != _win_height) { - _win_width = width; - _win_height = height; - set_button_range(_button_ready_image); - } - } - - // We seem to get the mouse-down, but lose the mouse-up, event in this - // case, so infer it. - set_mouse_data(_mouse_x, _mouse_y, false); - result = noErr; - break; - - case kEventWindowDrawContent: - paint_window(); - break; - - case kEventWindowClose: - // When the user closes the splash window, stop the instance. - _inst->request_stop_sub_thread(); - break; - }; - break; - - case kEventClassMouse: - switch (kind) { - case kEventMouseUp: - set_mouse_data(_mouse_x, _mouse_y, false); - break; - - case kEventMouseDown: - set_mouse_data(_mouse_x, _mouse_y, true); - break; - - case kEventMouseMoved: - case kEventMouseDragged: - { - Point point; - GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, nullptr, - sizeof(Point), nullptr, (void *)&point); - - GrafPtr port; - assert(_toplevel_window != nullptr); - port = GetWindowPort(_toplevel_window); - GrafPtr port_save = nullptr; - Boolean port_changed = QDSwapPort(port, &port_save); - GlobalToLocal(&point); - if (port_changed) { - QDSwapPort(port_save, nullptr); - } - - set_mouse_data(point.h, point.v, _mouse_down); - } - break; - } - } - - return result; -} - -/** - * Frees the previous image data. - */ -void P3DOsxSplashWindow::OsxImageData:: -dump_image() { - if (_image != nullptr) { - CGImageRelease(_image); - _image = nullptr; - } - if (_color_space != nullptr) { - CGColorSpaceRelease(_color_space); - _color_space = nullptr; - } - if (_provider != nullptr) { - CGDataProviderRelease(_provider); - _provider = nullptr; - } - if (_data != nullptr) { - CFRelease(_data); - _data = nullptr; - } - if (_raw_data != nullptr) { - delete[] _raw_data; - _raw_data = nullptr; - } -} - -#endif // __APPLE__ diff --git a/direct/src/plugin/p3dOsxSplashWindow.h b/direct/src/plugin/p3dOsxSplashWindow.h deleted file mode 100644 index 9a2a6225bc..0000000000 --- a/direct/src/plugin/p3dOsxSplashWindow.h +++ /dev/null @@ -1,101 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dOsxSplashWindow.h - * @author drose - * @date 2009-07-16 - */ - -#ifndef P3DOSXSPLASHWINDOW_H -#define P3DOSXSPLASHWINDOW_H - -#include "p3d_plugin_common.h" - -#if defined(__APPLE__) && !__LP64__ - -#include "p3dSplashWindow.h" - -#include - -/** - * This is the OSX implementation of the initial-download window. - */ -class P3DOsxSplashWindow : public P3DSplashWindow { -public: - P3DOsxSplashWindow(P3DInstance *inst, bool make_visible); - virtual ~P3DOsxSplashWindow(); - - virtual void set_wparams(const P3DWindowParams &wparams); - virtual void set_visible(bool visible); - virtual void set_image_filename(const std::string &image_filename, - ImagePlacement image_placement); - virtual void set_install_label(const std::string &install_label); - virtual void set_install_progress(double install_progress, - bool is_progress_known, size_t received_data); - - virtual bool handle_event(const P3D_event_data &event); - -protected: - virtual void refresh(); - -private: - void paint_window(); - void paint_window_osx_cgcontext(CGContextRef context); - bool handle_event_osx_event_record(const P3D_event_data &event); - bool handle_event_osx_cocoa(const P3D_event_data &event); - class OsxImageData; - - void load_image(OsxImageData &image, const std::string &image_filename); - bool paint_image(CGContextRef context, const OsxImageData &image); - void paint_progress_bar(CGContextRef context); - - static pascal OSStatus - st_event_callback(EventHandlerCallRef my_handler, EventRef event, - void *user_data); - OSStatus event_callback(EventHandlerCallRef my_handler, EventRef event); - -private: - bool _got_wparams; - - class OsxImageData : public ImageData { - public: - inline OsxImageData(); - inline ~OsxImageData(); - void dump_image(); - - char *_raw_data; - CFDataRef _data; - CGDataProviderRef _provider; - CGColorSpaceRef _color_space; - CGImageRef _image; - }; - - OsxImageData _background_image; - OsxImageData _button_ready_image; - OsxImageData _button_rollover_image; - OsxImageData _button_click_image; - - CFDictionaryRef _font_attribs; - - std::string _install_label; - double _install_progress; - bool _progress_known; - size_t _received_data; - - // Used to track the mouse within the window in the embedded case. - bool _mouse_active; - - // Filled only in the non-embedded case. - WindowRef _toplevel_window; -}; - -#include "p3dOsxSplashWindow.I" - -#endif // __APPLE__ - -#endif diff --git a/direct/src/plugin/p3dPackage.I b/direct/src/plugin/p3dPackage.I deleted file mode 100644 index 371491f5c2..0000000000 --- a/direct/src/plugin/p3dPackage.I +++ /dev/null @@ -1,179 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPackage.I - * @author drose - * @date 2009-06-12 - */ - -/** - * Returns true if the package file information has been downloaded and - * verified and is ready to be consulted, false if it is not yet available. - */ -inline bool P3DPackage:: -get_info_ready() const { - return _info_ready; -} - -/** - * Returns the number of bytes that will need to be downloaded, when this - * package is downloaded. This is intended to be used to estimate the - * download time for this package relative to other packages, for instance to - * update a progress bar sensibly. - */ -inline size_t P3DPackage:: -get_download_size() const { - return _compressed_archive.get_size(); -} - -/** - * Returns true if the package has been downloaded and verified and is ready - * to be used, false if it has not. - */ -inline bool P3DPackage:: -get_ready() const { - return _ready; -} - -/** - * Returns true if the package cannot be made ready, for instance because the - * download server is down. - */ -inline bool P3DPackage:: -get_failed() const { - return _failed; -} - -/** - * Returns the host server which offers this package for download. - */ -inline P3DHost *P3DPackage:: -get_host() const { - return _host; -} - -/** - * Returns the directory into which this package is installed. - */ -inline const std::string &P3DPackage:: -get_package_dir() const { - return _package_dir; -} - -/** - * Returns the name of this package. This is an internal name, used to - * generate filenames and the like; it will generally be all-lowercase and - * will not contain spaces. See also get_package_display_name() for a name - * suitable for displaying to the user. - */ -inline const std::string &P3DPackage:: -get_package_name() const { - return _package_name; -} - -/** - * Returns the version string of this package. - */ -inline const std::string &P3DPackage:: -get_package_version() const { - return _package_version; -} - -/** - * Returns the platform string of this package. - */ -inline const std::string &P3DPackage:: -get_package_platform() const { - return _package_platform; -} - -/** - * Returns the display_name name of this package, as set in the desc file. - */ -inline const std::string &P3DPackage:: -get_package_display_name() const { - return _package_display_name; -} - -/** - * Returns the entry of the package desc file, if any, or NULL if it - * was not present. - */ -inline const TiXmlElement *P3DPackage:: -get_xconfig() const { - return _xconfig; -} - -/** - * Returns the full path to the package's desc file. If this is a "solo" type - * package, the desc file itself represents the entire contents of the - * package. - */ -inline const std::string &P3DPackage:: -get_desc_file_pathname() const { - return _desc_file_pathname; -} - -/** - * Returns the relative path, on the host, of the directory that contains the - * desc file (and to which all of the paths in the desc file are relative). - */ -inline const std::string &P3DPackage:: -get_desc_file_dirname() const { - return _desc_file_dirname; -} - -/** - * Returns the full path to the package's uncompressed archive file. This is - * only valid if get_ready() is true and the package is not a "solo" package. - */ -inline std::string P3DPackage:: -get_archive_file_pathname() const { - return _uncompressed_archive.get_pathname(_package_dir); -} - - -/** - * Returns the relative amount of effort of this step. - */ -inline double P3DPackage::InstallStep:: -get_effort() const { - return _bytes_needed * _bytes_factor; -} - -/** - * Returns the progress of this step, in the range 0..1. - */ -inline double P3DPackage::InstallStep:: -get_progress() const { - if (_bytes_needed == 0) { - return 1.0; - } - return std::min((double)_bytes_done / (double)_bytes_needed, 1.0); -} - -/** - * Notifies the Package that progress has been made on this particular step. - */ -inline void P3DPackage::InstallStep:: -report_step_progress() { - _package->report_progress(this); -} - -/** - * - */ -inline P3DPackage::RequiredPackage:: -RequiredPackage(const std::string &package_name, const std::string &package_version, - const std::string &package_seq, P3DHost *host) : - _package_name(package_name), - _package_version(package_version), - _package_seq(package_seq), - _host(host) -{ -} diff --git a/direct/src/plugin/p3dPackage.cxx b/direct/src/plugin/p3dPackage.cxx deleted file mode 100644 index 4ea29f339d..0000000000 --- a/direct/src/plugin/p3dPackage.cxx +++ /dev/null @@ -1,2015 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPackage.cxx - * @author drose - * @date 2009-06-12 - */ - -#include "p3dPackage.h" -#include "p3dInstanceManager.h" -#include "p3dInstance.h" -#include "p3dMultifileReader.h" -#include "p3dTemporaryFile.h" -#include "p3dPatchFinder.h" -#include "mkdir_complete.h" -#include "wstring_encode.h" - -#include - -#include -#include - -#ifdef _WIN32 -#include // chmod() -#endif - -using std::ios; -using std::ostream; -using std::ostringstream; -using std::string; -using std::vector; - -// Weight factors for computing download progress. This attempts to reflect -// the relative time-per-byte of each of these operations. -const double P3DPackage::_download_factor = 1.0; -const double P3DPackage::_uncompress_factor = 0.01; -const double P3DPackage::_unpack_factor = 0.01; -const double P3DPackage::_patch_factor = 0.01; - -/** - * - */ -P3DPackage:: -P3DPackage(P3DHost *host, const string &package_name, - const string &package_version, const string &package_platform, - const string &alt_host) : - _host(host), - _package_name(package_name), - _package_version(package_version), - _package_platform(package_platform), - _alt_host(alt_host) -{ - set_fullname(); - _per_platform = false; - _patch_version = 0; - - // This is set true if the package is a "solo", i.e. a single file, instead - // of an xml file and a multifile to unpack. - _package_solo = false; - - _host_contents_iseq = 0; - - _xconfig = nullptr; - _temp_contents_file = nullptr; - - _computed_plan_size = false; - _info_ready = false; - _allow_data_download = false; - _ready = false; - _failed = false; - _active_download = nullptr; - _saved_download = nullptr; - _updated = false; -} - -/** - * - */ -P3DPackage:: -~P3DPackage() { - // Tell any pending callbacks that we're no good any more. - if (!_ready && !_failed) { - report_done(false); - } - - // Ditto the outstanding instances. - Instances::iterator ii; - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - (*ii)->remove_package(this); - } - _instances.clear(); - - if (_xconfig != nullptr) { - delete _xconfig; - _xconfig = nullptr; - } - - // Cancel any pending download. - if (_active_download != nullptr) { - _active_download->cancel(); - set_active_download(nullptr); - } - if (_saved_download != nullptr) { - _saved_download->cancel(); - set_saved_download(nullptr); - } - - if (_temp_contents_file != nullptr) { - delete _temp_contents_file; - _temp_contents_file = nullptr; - } -} - -/** - * Authorizes the package to begin downloading and unpacking the meat of its - * data. Until this is called, the package will download its file information - * only, and then wait. - */ -void P3DPackage:: -activate_download() { - _allow_data_download = true; - - if (_ready) { - // If we've already been downloaded, we can report that now. - Instances::iterator ii; - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - (*ii)->report_package_done(this, true); - } - - } else { - // Otherwise, if we've already got the desc file, then start the download. - if (_info_ready) { - follow_install_plans(true, false); - } - } -} - -/** - * Returns the name of this package, for output to the user. This will be the - * "public" name of the package, as formatted for user consumption; it will - * include capital letters and spaces where appropriate. - */ -string P3DPackage:: -get_formatted_name() const { - ostringstream strm; - - if (!_package_display_name.empty()) { - strm << _package_display_name; - } else { - strm << _package_name; - if (!_package_version.empty()) { - strm << " " << _package_version; - } - } - - if (_patch_version != 0) { - strm << " rev " << _patch_version; - } - - return strm.str(); -} - -/** - * Specifies an instance that that will be using this package, and may be - * responsible for downloading it. - */ -void P3DPackage:: -add_instance(P3DInstance *inst) { - _instances.push_back(inst); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (!_host->has_current_contents_file(inst_mgr)) { - // If the host needs to update its contents file, we're no longer sure - // that we're current. - _info_ready = false; - _ready = false; - _failed = false; - _allow_data_download = false; - nout << "No longer current: " << get_package_name() << "\n"; - } - - begin_info_download(); -} - -/** - * Indicates that the given instance is no longer interested in this package - * and will not be responsible for downloading it. - */ -void P3DPackage:: -remove_instance(P3DInstance *inst) { - assert(!_instances.empty()); - - if (inst == _instances[0]) { - // This was the primary instance. Cancel any pending download and move to - // the next instance. - if (_active_download != nullptr) { - _active_download->cancel(); - set_active_download(nullptr); - } - } - - Instances::iterator ii = find(_instances.begin(), _instances.end(), inst); - assert(ii != _instances.end()); - _instances.erase(ii); - - begin_info_download(); -} - -/** - * Marks this package as having been "used", for accounting purposes. - */ -void P3DPackage:: -mark_used() { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (inst_mgr->get_verify_contents() == P3D_VC_never) { - // We're not allowed to create any files in the package directory. - return; - } - - // Unlike the Python variant of this function, we don't mess around with - // updating the disk space or anything. - string filename = get_package_dir() + "/usage.xml"; - TiXmlDocument doc(filename); - if (!doc.LoadFile()) { - TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", ""); - doc.LinkEndChild(decl); - } - - TiXmlElement *xusage = doc.FirstChildElement("usage"); - if (xusage == nullptr) { - xusage = new TiXmlElement("usage"); - doc.LinkEndChild(xusage); - } - - time_t now = time(nullptr); - int count = 0; - xusage->Attribute("count_runtime", &count); - if (count == 0) { - xusage->SetAttribute("first_use", (int)now); - } - - ++count; - xusage->SetAttribute("count_runtime", count); - xusage->SetAttribute("last_use", (int)now); - - if (_updated) { - // If we've updated the package, we're no longer sure what its disk space - // is. Remove that from the XML file, so that the Python code can - // recompute it later. - xusage->RemoveAttribute("disk_space"); - xusage->SetAttribute("last_update", (int)now); - } - - // Write the file to a temporary filename, then atomically move it to its - // actual filename, to avoid race conditions. - ostringstream strm; - strm << get_package_dir() << "/usage_"; -#ifdef _WIN32 - strm << GetCurrentProcessId(); -#else - strm << getpid(); -#endif - strm << ".xml"; - string tfile = strm.str(); - - unlink(tfile.c_str()); - if (doc.SaveFile(tfile)) { - if (rename(tfile.c_str(), filename.c_str()) != 0) { - // If rename failed, remove the original file first. - unlink(filename.c_str()); - rename(tfile.c_str(), filename.c_str()); - } - } -} - -/** - * Removes the package directory and all its contents from the user's hard - * disk. - */ -void P3DPackage:: -uninstall() { - if (_package_dir.empty()) { - nout << "Cannot uninstall " << _package_name << ": package directory not yet known.\n"; - return; - } - - nout << "Uninstalling package " << _package_name << " from " << _package_dir << "\n"; - - // First, make sure that all instances that are sharing this package are - // stopped, so there will be no access conflicts preventing us from removing - // the files. This is particularly important on Windows. - Instances::iterator ii; - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - P3DInstance *inst = (*ii); - P3DSession *session = inst->get_session(); - if (session != nullptr) { - nout << "Stopping session " << session << "\n"; - session->shutdown(); - } - inst->set_failed(); - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - inst_mgr->delete_directory_recursively(_package_dir); - - _info_ready = false; - _ready = false; - _failed = false; - _allow_data_download = false; - - // Make sure the host forgets us too. - _host->forget_package(this); -} - -/** - * Returns a newly-allocated XML structure that corresponds to the package - * data within this instance. - */ -TiXmlElement *P3DPackage:: -make_xml() { - TiXmlElement *xpackage = new TiXmlElement("package"); - - xpackage->SetAttribute("name", _package_name); - if (!_package_platform.empty()) { - xpackage->SetAttribute("platform", _package_platform); - } - if (!_package_version.empty()) { - xpackage->SetAttribute("version", _package_version); - } - xpackage->SetAttribute("host", _host->get_host_url()); - xpackage->SetAttribute("host_dir", _host->get_host_dir()); - - return xpackage; -} - -/** - * Begins downloading and installing the information about the package, - * including its file size and download source and such, if needed. This is - * generally a very small download. - */ -void P3DPackage:: -begin_info_download() { - if (_instances.empty()) { - // Can't download without any instances. - return; - } - - if (_info_ready) { - // Already downloaded. - report_info_ready(); - return; - } - - if (_active_download != nullptr) { - // In the middle of downloading. - return; - } - - download_contents_file(); -} - -/** - * Starts downloading the root-level contents.xml file. This is only done for - * the first package downloaded from a particular host, and only if the host - * doesn't have the file already. - */ -void P3DPackage:: -download_contents_file() { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (!_host->has_contents_file() && inst_mgr->get_verify_contents() != P3D_VC_force) { - // First, read whatever contents file is already on disk. Maybe it's - // current enough. - _host->read_contents_file(); - } - - if (_host->has_current_contents_file(inst_mgr)) { - // We've already got a contents.xml file; go straight to the package desc - // file. - host_got_contents_file(); - return; - } - - // Don't download it if we're not allowed to. - if (inst_mgr->get_verify_contents() == P3D_VC_never) { - contents_file_download_finished(false); - return; - } - - // Download contents.xml to a temporary filename first, in case multiple - // packages are downloading it simultaneously. - if (_temp_contents_file != nullptr) { - delete _temp_contents_file; - _temp_contents_file = nullptr; - } - _temp_contents_file = new P3DTemporaryFile(".xml"); - - start_download(DT_contents_file, "contents.xml", - _temp_contents_file->get_filename(), FileSpec()); -} - -/** - * Called when the contents.xml file has been fully downloaded. - */ -void P3DPackage:: -contents_file_download_finished(bool success) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (!_host->has_current_contents_file(inst_mgr)) { - if (!success || _temp_contents_file == nullptr || - !_host->read_contents_file(_temp_contents_file->get_filename(), true)) { - - if (_temp_contents_file) { - nout << "Couldn't read " << *_temp_contents_file << "\n"; - } - - // Maybe we can read an already-downloaded contents.xml file. - bool success = false; - if (_host->has_host_dir()) { - string standard_filename = _host->get_host_dir() + "/contents.xml"; - if (_host->read_contents_file(standard_filename, false)) { - success = true; - } else { - nout << "Couldn't read " << standard_filename << "\n"; - } - } else { - nout << "No host_dir available for " << _host->get_host_url() - << "\n"; - } - if (!success) { - // Couldn't read an already-downloaded file either. Fail. - report_done(false); - if (_temp_contents_file) { - delete _temp_contents_file; - _temp_contents_file = nullptr; - } - return; - } - } - } - - // The file is correctly installed by now; we can remove the temporary file. - if (_temp_contents_file) { - delete _temp_contents_file; - _temp_contents_file = nullptr; - } - - host_got_contents_file(); -} - -/** - * Starts a new download attempt of contents.xml, to check to see whether our - * local copy is stale. This is called only from download_desc_file(), or - * from Download::download_finished(). If the former, the download pointer - * will be NULL. - * - * If it turns out a new version can be downloaded, the indicated Download - * object (and the current install plan) is discarded, and the package - * download is restarted from the beginning. - * - * If there is no new version available, calls resume_download_finished() on - * the indicated Download object, to carry on as if nothing had happened. - */ -void P3DPackage:: -redownload_contents_file(P3DPackage::Download *download) { - assert(_active_download == nullptr); - assert(_saved_download == nullptr); - - if (_host->get_contents_iseq() != _host_contents_iseq) { - // If the contents_iseq number has changed, we don't even need to download - // anything--just go restart the download. - host_got_contents_file(); - return; - } - - // Don't download it if we're not allowed to. - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (inst_mgr->get_verify_contents() == P3D_VC_never) { - return; - } - - set_saved_download(download); - - // Download contents.xml to a temporary filename first. - if (_temp_contents_file != nullptr) { - delete _temp_contents_file; - _temp_contents_file = nullptr; - } - _temp_contents_file = new P3DTemporaryFile(".xml"); - - start_download(DT_redownload_contents_file, "contents.xml", - _temp_contents_file->get_filename(), FileSpec()); -} - -/** - * Called when the redownload attempt on contents.xml has finished. - */ -void P3DPackage:: -contents_file_redownload_finished(bool success) { - bool contents_changed = false; - - if (_host->get_contents_iseq() != _host_contents_iseq) { - // If the contents_iseq number has changed, we don't even need to bother - // reading what we just downloaded. - contents_changed = true; - } - - if (!contents_changed && success) { - // If we successfully downloaded something, see if it's different from - // what we had before. - if (!_host->check_contents_hash(_temp_contents_file->get_filename())) { - // It changed! Now see if we can read the new contents. - if (!_host->read_contents_file(_temp_contents_file->get_filename(), true)) { - // Huh, appears to have changed to something bad. Never mind. - nout << "Couldn't read " << *_temp_contents_file << "\n"; - - } else { - // The new contents file is read and in place. - contents_changed = true; - } - } - } - - // We no longer need the temporary file. - if (_temp_contents_file) { - delete _temp_contents_file; - _temp_contents_file = nullptr; - } - - if (contents_changed) { - // OK, the contents.xml has changed; this means we have to restart the - // whole download process from the beginning. - nout << "Redownloading contents.xml made a difference.\n"; - set_saved_download(nullptr); - host_got_contents_file(); - - } else { - // Nothing's changed. This was just a useless diversion. We now return - // you to our regularly scheduled download. - nout << "Redownloading contents.xml didn't help.\n"; - Download *download = _saved_download; - _saved_download = nullptr; - if (download == nullptr) { - // But, if _saved_download was NULL (meaning NULL was passed to - // redownload_contents_file(), above), it means that we were called from - // download_desc_file(), and there's nothing more to do. We're just - // hosed. - report_done(false); - - } else { - download->resume_download_finished(false); - p3d_unref_delete(download); - } - } -} - -/** - * We come here when we've successfully downloaded and read the host's - * contents.xml file. This begins the rest of the download process. - */ -void P3DPackage:: -host_got_contents_file() { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - if (!_alt_host.empty()) { - // If we have an alt host specification, maybe we need to change the host - // now. - P3DHost *new_host = _host->get_alt_host(_alt_host); - nout << "Migrating " << get_package_name() << " to alt_host " - << _alt_host << ": " << new_host->get_host_url() << "\n"; - if (new_host != _host) { - _host->migrate_package_host(this, _alt_host, new_host); - _host = new_host; - } - - // Clear the alt_host string now that we're migrated to our final host. - _alt_host.clear(); - - if (!_host->has_current_contents_file(inst_mgr)) { - // Now go back and get the contents.xml file for the new host. - download_contents_file(); - return; - } - } - - // Record this now, so we'll know later whether the host has been reloaded - // (e.g. due to some other package, from some other instance, reloading - // it). - _host_contents_iseq = _host->get_contents_iseq(); - - // Now adjust the platform based on the available platforms provided. - assert(_alt_host.empty()); - string new_platform; - if (_host->choose_suitable_platform(new_platform, _per_platform, - _package_name, _package_version, _package_platform)) { - if (new_platform != _package_platform) { - nout << "Migrating " << get_package_name() << " from platform \"" - << _package_platform << "\" to platform \"" - << new_platform << "\"\n"; - _package_platform = new_platform; - set_fullname(); - } - } else { - nout << "Couldn't find a platform for " << get_package_name() - << " matching \"" << inst_mgr->get_platform() << "\".\n"; - } - - nout << "_per_platform for " << get_package_name() << " = " << _per_platform << "\n"; - - // Now that we have a valid host and platform, we can define the - // _package_dir. - _package_dir = _host->get_host_dir() + string("/") + _package_name; - if (!_package_version.empty()) { - _package_dir += string("/") + _package_version; - } - if (_per_platform && !_package_platform.empty()) { - _package_dir += string("/") + _package_platform; - } - - // Ensure the package directory exists; create it if it does not. - if (inst_mgr->get_verify_contents() != P3D_VC_never) { - mkdir_complete(_package_dir, nout); - } - download_desc_file(); -} - -/** - * Starts downloading the desc file for the package, if it's needed; or read - * the local version if it's fresh enough. - */ -void P3DPackage:: -download_desc_file() { - assert(!_package_dir.empty()); - - // Attempt to check the desc file for freshness. If it already exists, and - // is consistent with the server contents file, we don't need to re-download - // it. - string package_seq; - if (!_host->get_package_desc_file(_desc_file, package_seq, _package_solo, - _package_name, _package_version, - _package_platform)) { - nout << "Couldn't find package " << _package_fullname - << ", platform \"" << _package_platform - << "\" in contents file.\n"; - redownload_contents_file(nullptr); - return; - } - - string url_filename = _desc_file.get_filename(); - - _desc_file_dirname = ""; - _desc_file_basename = url_filename; - size_t slash = _desc_file_basename.rfind('/'); - if (slash != string::npos) { - _desc_file_dirname = _desc_file_basename.substr(0, slash); - _desc_file_basename = _desc_file_basename.substr(slash + 1); - } - - // The desc file might have a different path on the host server than it has - // locally, because we might strip out the platform directory locally - // (according to _per_platform). - FileSpec local_desc_file = _desc_file; - local_desc_file.set_filename(_desc_file_basename); - _desc_file_pathname = local_desc_file.get_pathname(_package_dir); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (!local_desc_file.full_verify(_package_dir) && inst_mgr->get_verify_contents() != P3D_VC_never) { - nout << _desc_file_pathname << " is stale.\n"; - - } else { - // The desc file is current. Attempt to read it. - if (_package_solo) { - // No need to load it: the desc file *is* the package. - report_done(true); - return; - } else { - TiXmlDocument doc(_desc_file_pathname.c_str()); - if (doc.LoadFile()) { - got_desc_file(&doc, false); - return; - } - } - } - - // Don't download it if we're not allowed to. - if (inst_mgr->get_verify_contents() == P3D_VC_never) { - nout << "Couldn't read " << _desc_file_pathname << "\n"; - report_done(false); - return; - } - - // The desc file is not current. Go download it. - start_download(DT_desc_file, _desc_file.get_filename(), - _desc_file_pathname, local_desc_file); -} - -/** - * Called when the desc file has been fully downloaded. - */ -void P3DPackage:: -desc_file_download_finished(bool success) { - if (!success) { - report_done(false); - return; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (inst_mgr->get_verify_contents() != P3D_VC_never) { - // Now that we've downloaded the desc file, make it read-only. - chmod(_desc_file_pathname.c_str(), 0444); - } - - if (_package_solo) { - // No need to load it: the desc file *is* the package. - report_done(true); - return; - - } else { - TiXmlDocument doc(_desc_file_pathname.c_str()); - if (!doc.LoadFile()) { - nout << "Couldn't read " << _desc_file_pathname << "\n"; - report_done(false); - return; - } - - got_desc_file(&doc, true); - } -} - -/** - * Reads the desc file and begins verifying the files. - */ -void P3DPackage:: -got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) { - TiXmlElement *xpackage = doc->FirstChildElement("package"); - if (xpackage == nullptr) { - nout << _package_name << " desc file contains no \n"; - if (!freshly_downloaded) { - download_desc_file(); - return; - } - report_done(false); - return; - } - - bool per_platform = parse_bool_attrib(xpackage, "per_platform", false); - if (per_platform != _per_platform) { - nout << "Warning! per_platform disagreement for " << get_package_name() - << "!\n"; - // We don't do anything with this warning--the original value for - // _per_platform we got from the contents.xml file has to apply, because - // we're already committed to the _package_dir we're using. - } - - xpackage->Attribute("patch_version", &_patch_version); - - TiXmlElement *xconfig = xpackage->FirstChildElement("config"); - if (xconfig != nullptr) { - const char *display_name_cstr = xconfig->Attribute("display_name"); - if (display_name_cstr != nullptr) { - _package_display_name = display_name_cstr; - } - - // Save the config entry within this class for others to query. - _xconfig = (TiXmlElement *)xconfig->Clone(); - } - - TiXmlElement *xuncompressed_archive = - xpackage->FirstChildElement("uncompressed_archive"); - TiXmlElement *xcompressed_archive = - xpackage->FirstChildElement("compressed_archive"); - - if (xuncompressed_archive == nullptr || xcompressed_archive == nullptr) { - // The desc file didn't include the archive file itself, weird. - if (!freshly_downloaded) { - download_desc_file(); - return; - } - report_done(false); - return; - } - - _uncompressed_archive.load_xml(xuncompressed_archive); - _compressed_archive.load_xml(xcompressed_archive); - - // Now get all the extractable components. - _unpack_size = 0; - _extracts.clear(); - TiXmlElement *xextract = xpackage->FirstChildElement("extract"); - while (xextract != nullptr) { - FileSpec file; - file.load_xml(xextract); - _extracts.push_back(file); - _unpack_size += file.get_size(); - xextract = xextract->NextSiblingElement("extract"); - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - // Get the required packages. - _requires.clear(); - TiXmlElement *xrequires = xpackage->FirstChildElement("requires"); - while (xrequires != nullptr) { - const char *package_name = xrequires->Attribute("name"); - const char *host_url = xrequires->Attribute("host"); - if (package_name != nullptr && host_url != nullptr) { - const char *version = xrequires->Attribute("version"); - if (version == nullptr) { - version = ""; - } - const char *seq = xrequires->Attribute("seq"); - if (seq == nullptr) { - seq = ""; - } - P3DHost *host = inst_mgr->get_host(host_url); - _requires.push_back(RequiredPackage(package_name, version, seq, host)); - } - - xrequires = xrequires->NextSiblingElement("requires"); - } - - if (inst_mgr->get_verify_contents() == P3D_VC_never) { - // This means we'll just leave it at this and assume that we're finished. - report_done(true); - return; - } - - // Get a list of all of the files in the directory, so we can remove files - // that don't belong. - vector contents, dirname_contents; - inst_mgr->scan_directory_recursively(_package_dir, contents, dirname_contents); - - inst_mgr->remove_file_from_list(contents, _desc_file_basename); - inst_mgr->remove_file_from_list(contents, _uncompressed_archive.get_filename()); - inst_mgr->remove_file_from_list(contents, "usage.xml"); - Extracts::iterator ei; - for (ei = _extracts.begin(); ei != _extracts.end(); ++ei) { - inst_mgr->remove_file_from_list(contents, (*ei).get_filename()); - } - - // Now, any files that are still in the contents list don't belong. It's - // important to remove these files before we start verifying the files that - // we expect to find here, in case there is a problem with ambiguous - // filenames or something (e.g. case insensitivity). - vector::iterator ci; - for (ci = contents.begin(); ci != contents.end(); ++ci) { - string filename = (*ci); - nout << "Removing " << filename << "\n"; - string pathname = _package_dir + "/" + filename; - -#ifdef _WIN32 - // Windows can't delete a file if it's read-only. - chmod(pathname.c_str(), 0644); -#endif - unlink(pathname.c_str()); - _updated = true; - } - - // Verify the uncompressed archive. - bool all_extracts_ok = true; - if (!_uncompressed_archive.quick_verify(_package_dir)) { - nout << "File is incorrect: " << _uncompressed_archive.get_filename() << "\n"; - all_extracts_ok = false; - } - - // Verify all of the extracts. - for (ei = _extracts.begin(); ei != _extracts.end() && all_extracts_ok; ++ei) { - if (!(*ei).quick_verify(_package_dir)) { - nout << "File is incorrect: " << (*ei).get_filename() << "\n"; - all_extracts_ok = false; - } - - // Make sure all extracts are still marked executable. - chmod((*ei).get_pathname(_package_dir).c_str(), 0555); - } - - if (all_extracts_ok) { - // Great, we're ready to begin. - nout << "All " << _extracts.size() << " extracts of " << _package_name - << " seem good.\n"; - - report_done(true); - - } else { - // We need to get the file data still, but at least we know all about it - // by this point. - build_install_plans(doc); - - if (!_allow_data_download) { - // Not authorized to start downloading yet; just report that we're - // ready. - report_info_ready(); - } else { - // We've already been authorized to start downloading, so do it. - follow_install_plans(true, false); - } - } -} - -/** - * Empties _install_plans cleanly. - */ -void P3DPackage:: -clear_install_plans() { - InstallPlans::iterator pi; - for (pi = _install_plans.begin(); pi != _install_plans.end(); ++pi) { - InstallPlan &plan = (*pi); - InstallPlan::iterator si; - for (si = plan.begin(); si != plan.end(); ++si) { - InstallStep *step = (*si); - delete step; - } - } - - _install_plans.clear(); - _computed_plan_size = false; -} - -/** - * Sets up _install_plans, a list of one or more "plans" to download and - * install the package. - */ -void P3DPackage:: -build_install_plans(TiXmlDocument *doc) { - clear_install_plans(); - - if (_instances.empty()) { - // Can't download without any instances. - return; - } - - if (_ready) { - // Already downloaded. - return; - } - - _install_plans.push_front(InstallPlan()); - InstallPlan &plan = _install_plans.front(); - _computed_plan_size = false; - - bool needs_redownload = false; - - InstallStep *step; - if (!_uncompressed_archive.quick_verify(_package_dir)) { - // The uncompressed archive is no good. - - if (!_compressed_archive.quick_verify(_package_dir)) { - // The compressed archive is no good either. Download a new compressed - // archive. - needs_redownload = true; - step = new InstallStepDownloadFile(this, _compressed_archive); - plan.push_back(step); - } - - // Uncompress the compressed archive to generate the uncompressed archive. - step = new InstallStepUncompressFile - (this, _compressed_archive, _uncompressed_archive, true); - plan.push_back(step); - } - - // Unpack the uncompressed archive. - step = new InstallStepUnpackArchive(this, _unpack_size); - plan.push_back(step); - - if (needs_redownload) { - // Since we need to do some downloading, try to build a plan that involves - // downloading patches instead of downloading the whole file. This will - // be our first choice, plan A, if we can do it. - - // We'll need the md5 hash of the uncompressed archive currently on disk. - - // Maybe we've already read the md5 hash and we have it stored here. - const FileSpec *on_disk_ptr = _uncompressed_archive.get_actual_file(); - FileSpec on_disk; - if (on_disk_ptr == nullptr) { - // If not, we have to go read it now. - if (on_disk.read_hash(_uncompressed_archive.get_pathname(_package_dir))) { - on_disk_ptr = &on_disk; - } - } - - if (on_disk_ptr != nullptr) { - P3DPatchFinder patch_finder; - P3DPatchFinder::Patchfiles chain; - if (patch_finder.get_patch_chain_to_current(chain, doc, *on_disk_ptr)) { - nout << "Got patch chain of length " << chain.size() << "\n"; - - // OK, we can create a plan to download and apply the patches. - _install_plans.push_front(InstallPlan()); - InstallPlan &plan = _install_plans.front(); - - P3DPatchFinder::Patchfiles::iterator pi; - for (pi = chain.begin(); pi != chain.end(); ++pi) { - P3DPatchFinder::Patchfile *patchfile = (*pi); - - // Download the patchfile - step = new InstallStepDownloadFile(this, patchfile->_file); - plan.push_back(step); - - // Uncompress it - FileSpec new_file = patchfile->_file; - string new_filename = new_file.get_filename(); - size_t dot = new_filename.rfind('.'); - string extension = new_filename.substr(dot); - assert(extension == ".pz" || extension == ".gz"); - new_filename = new_filename.substr(0, dot); - new_file.set_filename(new_filename); - step = new InstallStepUncompressFile - (this, patchfile->_file, new_file, false); - plan.push_back(step); - - // And apply it - FileSpec source_file = patchfile->_source_file; - FileSpec target_file = patchfile->_target_file; - source_file.set_filename(_uncompressed_archive.get_filename()); - target_file.set_filename(_uncompressed_archive.get_filename()); - step = new InstallStepApplyPatch - (this, new_file, source_file, target_file); - plan.push_back(step); - } - - // Unpack the uncompressed archive. - step = new InstallStepUnpackArchive(this, _unpack_size); - plan.push_back(step); - } - } - } -} - -/** - * Performs the next step in the current install plan. - * - * If download_finished is false, there is a pending download that has not - * fully completed yet; otherwise, download_finished should be set true. - * - * If plan_failed is false, it means that the top-of-stack plan is still good; - * if true, the top-of-stack plan has failed and should be removed. - */ -void P3DPackage:: -follow_install_plans(bool download_finished, bool plan_failed) { - if (!_allow_data_download || _failed) { - // Not authorized yet, or something went wrong. - return; - } - - while (!_install_plans.empty()) { - // Pull the next step off the current plan. - - InstallPlan &plan = _install_plans.front(); - - if (!_computed_plan_size) { - _total_plan_size = 0.0; - _total_plan_completed = 0.0; - InstallPlan::iterator si; - for (si = plan.begin(); si != plan.end(); ++si) { - double step_effort = (*si)->get_effort(); - _total_plan_size += step_effort; - _total_plan_completed += (*si)->get_progress() * step_effort; - } - - _download_progress = 0.0; - if (_total_plan_size > 0.0) { - _download_progress = _total_plan_completed / _total_plan_size; - } - _computed_plan_size = true; - nout << "Selected install plan for " << get_package_name() - << ": " << _total_plan_completed << " of " - << _total_plan_size << "\n"; - } - - while (!plan.empty() && !plan_failed) { - InstallStep *step = plan.front(); - _current_step_effort = step->get_effort(); - - InstallToken token = step->do_step(download_finished); - switch (token) { - case IT_step_failed: - // This plan has failed. - plan_failed = true; - break; - - case IT_terminate: - // All plans have failed. - _install_plans.clear(); - report_done(false); - return; - - case IT_continue: - // A callback hook has been attached; we'll come back later. - return; - - case IT_needs_callback: - // We need to install a callback hook and come back later. - request_callback(); - return; - - case IT_step_complete: - // So far, so good. Go on to the next step. - _total_plan_completed += _current_step_effort; - delete step; - plan.pop_front(); - break; - } - } - - if (!plan_failed) { - // We've finished the plan successfully. - clear_install_plans(); - report_done(true); - return; - } - - // That plan failed. Go on to the next plan. - nout << "Plan failed.\n"; - _install_plans.pop_front(); - _computed_plan_size = false; - - // The next plan is (so far as we know) still good. - plan_failed = false; - } - - // All plans failed. Too bad for us. - report_done(false); -} - -/** - * This function is registered as the callback hook when a package is in the - * middle of processing in a sub-thread. - */ -void P3DPackage:: -st_callback(void *self) { - ((P3DPackage *)self)->follow_install_plans(false, false); -} - -/** - * Requests that follow_install_plans() will be called again in the future. - */ -void P3DPackage:: -request_callback() { - Instances::iterator ii; - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - (*ii)->request_callback(&st_callback, this); - } -} - -/** - * Reports the current install progress to all interested instances. - */ -void P3DPackage:: -report_progress(P3DPackage::InstallStep *step) { - if (_computed_plan_size) { - double size = _total_plan_completed + _current_step_effort * step->get_progress(); - _download_progress = std::min(size / _total_plan_size, 1.0); - - Instances::iterator ii; - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - (*ii)->report_package_progress(this, _download_progress); - } - } -} - -/** - * Called when the package information has been successfully downloaded but - * activate_download() has not yet been called, and the package is now idle, - * waiting for activate_download() to be called. - */ -void P3DPackage:: -report_info_ready() { - _info_ready = true; - - Instances::iterator ii; - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - (*ii)->report_package_info_ready(this); - } -} - -/** - * Transitions the package to "ready" or "failure" state, and reports this - * change to all the interested instances. - */ -void P3DPackage:: -report_done(bool success) { - // Don't call report_done() twice. - if (_ready || _failed) { - nout << get_package_name() << ": report_done() called twice\n"; - _failed = true; - return; - } - - if (success) { - _info_ready = true; - _ready = true; - _failed = false; - } else { - _ready = false; - _failed = true; - } - - if (!_allow_data_download && success) { - // If we haven't been authorized to start downloading yet, just report - // that we're ready to start. - Instances::iterator ii; - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - (*ii)->report_package_info_ready(this); - } - - } else { - // Otherwise, we can report that we're fully downloaded. - Instances::iterator ii; - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - (*ii)->report_package_done(this, success); - } - } -} - -/** - * Initiates a download of the indicated file. Returns the new Download - * object. - */ -P3DPackage::Download *P3DPackage:: -start_download(P3DPackage::DownloadType dtype, const string &urlbase, - const string &pathname, const FileSpec &file_spec) { - // Only one download should be active at a time - assert(_active_download == nullptr); - // This can't happen! If verify_contents is set to P3D_VC_never, we're not - // allowed to download anything, so we shouldn't get here - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - assert(inst_mgr->get_verify_contents() != P3D_VC_never); - - // We can't explicitly support partial downloads here, because Mozilla - // provides no interface to ask for one. We have to trust that Mozilla's - // use of the browser cache handles partial downloads for us automatically. - - // Delete the target file before we begin. -#ifdef _WIN32 - // Windows can't delete a file if it's read-only. - chmod(pathname.c_str(), 0644); -#endif - unlink(pathname.c_str()); - - Download *download = new Download(this, dtype, file_spec); - - // Fill up the _try_urls vector for URL's to try getting this file from, in - // reverse order. - bool is_contents_file = (dtype == DT_contents_file || dtype == DT_redownload_contents_file); - - // The last thing we try is the actual authoritative host, with a cache- - // busting query string. - ostringstream strm; - if (is_contents_file) { - strm << _host->get_host_url_prefix(); - } else { - strm << _host->get_download_url_prefix(); - } - strm << urlbase << "?" << time(nullptr); - string url = strm.str(); - download->_try_urls.push_back(url); - - if (!is_contents_file) { - // Before we try the cache-buster out of desperation, we try the - // authoritative host, allowing caches. - url = _host->get_download_url_prefix() + urlbase; - download->_try_urls.push_back(url); - - // Before *that*, we try a couple of mirrors, chosen at random. - vector mirrors; - _host->choose_random_mirrors(mirrors, 2); - for (vector::iterator si = mirrors.begin(); - si != mirrors.end(); - ++si) { - url = (*si) + urlbase; - download->_try_urls.push_back(url); - } - } - - if (dtype == DT_redownload_contents_file) { - // When we're redownloading the contents file after a download error, we - // always go straight to the authoritative host, not even to the super- - // mirror. - - } else { - // In other cases, if the "super mirror" is enabled, we try that first. - if (!inst_mgr->get_super_mirror().empty()) { - string url = inst_mgr->get_super_mirror() + urlbase; - download->_try_urls.push_back(url); - } - } - - if (download->_try_urls.size() == 1) { - // If we only ended up with only one URL on the try list, then try it - // twice, for a bit of redundancy in case there's a random network hiccup - // or something. - - // Save a copy into its own string object first to avoid self- - // dereferencing errors in the push_back() method. - string url = download->_try_urls[0]; - download->_try_urls.push_back(url); - } - - // OK, start the download. - assert(!download->_try_urls.empty()); - url = download->_try_urls.back(); - download->_try_urls.pop_back(); - download->set_url(url); - download->set_filename(pathname); - - set_active_download(download); - assert(!_instances.empty()); - - _instances[0]->start_download(download); - return download; -} - -/** - * Changes _active_download to point to the indicated object, respecting - * reference counts. - */ -void P3DPackage:: -set_active_download(Download *download) { - if (_active_download != download) { - if (_active_download != nullptr) { - p3d_unref_delete(_active_download); - } - _active_download = download; - if (_active_download != nullptr) { - _active_download->ref(); - } - } -} - -/** - * Changes _saved_download to point to the indicated object, respecting - * reference counts. - */ -void P3DPackage:: -set_saved_download(Download *download) { - if (_saved_download != download) { - if (_saved_download != nullptr) { - p3d_unref_delete(_saved_download); - } - _saved_download = download; - if (_saved_download != nullptr) { - _saved_download->ref(); - } - } -} - -/** - * Returns true if the name file is on the extract list, false otherwise. If - * true, fills in the FileSpec with the file's information. - */ -bool P3DPackage:: -is_extractable(FileSpec &file, const string &filename) const { - Extracts::const_iterator ei; - for (ei = _extracts.begin(); ei != _extracts.end(); ++ei) { - if ((*ei).get_filename() == filename) { - file = (*ei); - return true; - } - } - - return false; -} - - -/** - * Called when P3D_RC_shutdown is received by any Download object, which - * indicates that the instance owning this download object is terminating and - * we should either find a new instance or abort the download. - * - * The return value is true if a new instance is available, or false if not. - */ -bool P3DPackage:: -instance_terminating(P3DInstance *instance) { - if (_instances.empty() || - (_instances.size() == 1 && instance == _instances[0])) { - // No other instances. - return false; - } - - // There are more instances available to continue this download; pick one of - // them. Move this one to the end of the list. - Instances::iterator ii = find(_instances.begin(), _instances.end(), instance); - if (ii != _instances.end()) { - _instances.erase(ii); - _instances.push_back(instance); - } - return true; -} - -/** - * Assigns _package_fullname to the appropriate combination of name, version, - * and platform. - */ -void P3DPackage:: -set_fullname() { - _package_fullname = _package_name; - if (!_package_version.empty()) { - _package_fullname += string(".") + _package_version; - } - if (!_package_platform.empty()) { - _package_fullname += string(".") + _package_platform; - } -} - -/** - * - */ -P3DPackage::Download:: -Download(P3DPackage *package, DownloadType dtype, const FileSpec &file_spec) : - _package(package), - _dtype(dtype), - _file_spec(file_spec) -{ -} - -/** - * - */ -P3DPackage::Download:: -Download(const P3DPackage::Download ©) : - P3DFileDownload(copy), - _try_urls(copy._try_urls), - _package(copy._package), - _dtype(copy._dtype), - _file_spec(copy._file_spec) -{ -} - -/** - * - */ -void P3DPackage::Download:: -download_progress() { - P3DFileDownload::download_progress(); - assert(_package->_active_download == this); - - switch (_dtype) { - case DT_contents_file: - case DT_redownload_contents_file: - break; - - case DT_desc_file: - break; - - case DT_install_step: - _package->follow_install_plans(false, false); - break; - } -} - -/** - * - */ -void P3DPackage::Download:: -download_finished(bool success) { - P3DFileDownload::download_finished(success); - assert(_package->_active_download == this); - if (get_ref_count() == 1) { - // No one cares anymore. - nout << "No one cares about " << get_url() << "\n"; - _package->set_active_download(nullptr); - return; - } - - _package->set_active_download(nullptr); - assert(get_ref_count() > 0); - - if (success && !_file_spec.get_filename().empty()) { - // We think we downloaded it correctly. Check the hash to be sure. - if (!_file_spec.full_verify(_package->_package_dir)) { - nout << "After downloading " << get_url() - << ", failed hash check\n"; - nout << "expected: "; - _file_spec.output_hash(nout); - nout << "\n"; - if (_file_spec.get_actual_file() != nullptr) { - nout << " got: "; - _file_spec.get_actual_file()->output_hash(nout); - nout << "\n"; - } - - success = false; - } - } - - close_file(); - - if (!success) { - if (get_download_terminated()) { - // Short-circuit the exit. - _try_urls.clear(); - resume_download_finished(false); - return; - } - - // Maybe it failed because our contents.xml file is out-of-date. Go try - // to freshen it. - bool is_contents_file = (_dtype == DT_contents_file || _dtype == DT_redownload_contents_file); - if (!is_contents_file) { - _package->redownload_contents_file(this); - return; - } - } - - // Carry on. - resume_download_finished(success); -} - -/** - * Continuing the work begun in download_finished(). This is a separate entry - * point so that it can be called again after determining that the host's - * contents.xml file is *not* stale. - */ -void P3DPackage::Download:: -resume_download_finished(bool success) { - if (!success && !_try_urls.empty()) { - // Try the next mirror. - string url = _try_urls.back(); - _try_urls.pop_back(); - - clear(); - set_url(url); - set_filename(get_filename()); - _package->set_active_download(this); - - assert(!_package->_instances.empty()); - _package->_instances[0]->start_download(this); - return; - } - - switch (_dtype) { - case DT_contents_file: - _package->contents_file_download_finished(success); - break; - - case DT_redownload_contents_file: - _package->contents_file_redownload_finished(success); - break; - - case DT_desc_file: - _package->desc_file_download_finished(success); - break; - - case DT_install_step: - _package->follow_install_plans(true, !success); - break; - } -} - -/** - * - */ -P3DPackage::InstallStep:: -InstallStep(P3DPackage *package, size_t bytes, double factor) : - _package(package), - _bytes_needed(bytes), - _bytes_done(0), - _bytes_factor(factor) -{ -} - -/** - * - */ -P3DPackage::InstallStep:: -~InstallStep() { -} - -/** - * - */ -P3DPackage::InstallStepDownloadFile:: -InstallStepDownloadFile(P3DPackage *package, const FileSpec &file) : - InstallStep(package, file.get_size(), _download_factor), - _file(file) -{ - _urlbase = _package->get_desc_file_dirname(); - _urlbase += "/"; - _urlbase += _file.get_filename(); - - _pathname = _package->get_package_dir() + "/" + _file.get_filename(); - - _download = nullptr; -} - -/** - * - */ -P3DPackage::InstallStepDownloadFile:: -~InstallStepDownloadFile() { - if (_download != nullptr) { - p3d_unref_delete(_download); - } -} - -/** - * - */ -P3DPackage::InstallToken P3DPackage::InstallStepDownloadFile:: -do_step(bool download_finished) { - if (_download == nullptr) { - // First, we have to start the download going. - assert(_package->_active_download == nullptr); - - _download = _package->start_download(DT_install_step, _urlbase, - _pathname, _file); - assert(_download != nullptr); - _download->ref(); - } - - _bytes_done = _download->get_total_data(); - report_step_progress(); - - if (!_download->get_download_finished() || !download_finished) { - // Wait for it. - return IT_continue; - } - - if (_download->get_download_success()) { - // The Download object has already validated the hash. - _package->_updated = true; - return IT_step_complete; - - } else if (_download->get_download_terminated()) { - // The download was interrupted because its instance is shutting down. - // Don't try any other plans, unless we have some more instances. - P3DInstance *instance = _download->get_instance(); - if (!_package->instance_terminating(instance)) { - // That was the only instance referencing this package, so stop the - // download. - nout << "Terminating download of " << _urlbase << "\n"; - return IT_terminate; - } - nout << "Restarting download of " << _urlbase << " on new instance\n"; - - p3d_unref_delete(_download); - _download = nullptr; - return IT_continue; - - } else { - // The Download object has already tried all of the mirrors, and they all - // failed. - return IT_step_failed; - } -} - -/** - * - */ -void P3DPackage::InstallStepDownloadFile:: -output(ostream &out) { - out << "InstallStepDownloadFile(" << _package->get_package_name() - << ", " << _file.get_filename() << ")"; -} - - -/** - * - */ -P3DPackage::InstallStepThreaded:: -InstallStepThreaded(P3DPackage *package, size_t bytes, double factor) : - InstallStep(package, bytes, factor) -{ - INIT_THREAD(_thread); - INIT_LOCK(_thread_lock); - _thread_started = false; - _thread_token = IT_needs_callback; - _thread_bytes_done = 0; -} - -/** - * - */ -P3DPackage::InstallStepThreaded:: -~InstallStepThreaded() { - if (_thread_started) { - JOIN_THREAD(_thread); - _thread_started = false; - } - DESTROY_LOCK(_thread_lock); -} - -/** - * - */ -P3DPackage::InstallToken P3DPackage::InstallStepThreaded:: -do_step(bool download_finished) { - // This method is called within the main thread. It simply checks the - // thread status, and returns. - - // Spawn a thread and wait for it to finish. - if (!_thread_started) { - nout << "Spawning thread to handle " << _package->get_package_name() << "\n"; - _thread_started = true; - SPAWN_THREAD(_thread, thread_main, this); - } - - InstallToken token; - bool made_progress = false; - - ACQUIRE_LOCK(_thread_lock); - token = _thread_token; - if (_bytes_done != _thread_bytes_done) { - _bytes_done = _thread_bytes_done; - made_progress = true; - } - RELEASE_LOCK(_thread_lock); - - if (made_progress) { - report_step_progress(); - } - - return token; -} - -/** - * - */ -void P3DPackage::InstallStepThreaded:: -thread_main() { - // This method is called within the sub-thread. It calls thread_step() to - // do its work. - - InstallToken token = IT_needs_callback; - do { - // Perform the nested step, then update the token. - token = thread_step(); - - ACQUIRE_LOCK(_thread_lock); - _thread_token = token; - RELEASE_LOCK(_thread_lock); - - // Do it again if needed. - } while (token == IT_needs_callback); - - // All done. -} - -/** - * Should be called from time to time within the sub-thread to update the - * number of bytes processed. - */ -void P3DPackage::InstallStepThreaded:: -thread_set_bytes_done(size_t bytes_done) { - ACQUIRE_LOCK(_thread_lock); - _thread_bytes_done = bytes_done; - RELEASE_LOCK(_thread_lock); -} - -/** - * Should be called from time to time within the sub-thread to update the - * number of bytes processed. - */ -void P3DPackage::InstallStepThreaded:: -thread_add_bytes_done(size_t bytes_done) { - ACQUIRE_LOCK(_thread_lock); - _thread_bytes_done += bytes_done; - RELEASE_LOCK(_thread_lock); -} - -/** - * - */ -P3DPackage::InstallStepUncompressFile:: -InstallStepUncompressFile(P3DPackage *package, const FileSpec &source, - const FileSpec &target, bool verify_target) : - InstallStepThreaded(package, target.get_size(), _uncompress_factor), - _source(source), - _target(target), - _verify_target(verify_target) -{ -} - - -/** - * - */ -P3DPackage::InstallToken P3DPackage::InstallStepUncompressFile:: -thread_step() { - string source_pathname = _package->get_package_dir() + "/" + _source.get_filename(); - string target_pathname = _package->get_package_dir() + "/" + _target.get_filename(); - - ifstream source; -#ifdef _WIN32 - std::wstring source_pathname_w; - if (string_to_wstring(source_pathname_w, source_pathname)) { - source.open(source_pathname_w.c_str(), ios::in | ios::binary); - } -#else // _WIN32 - source.open(source_pathname.c_str(), ios::in | ios::binary); -#endif // _WIN32 - if (!source) { - nout << "Couldn't open " << source_pathname << "\n"; - return IT_step_failed; - } - - if (!mkfile_complete(target_pathname, nout)) { - return IT_step_failed; - } - - ofstream target; -#ifdef _WIN32 - std::wstring target_pathname_w; - if (string_to_wstring(target_pathname_w, target_pathname)) { - target.open(target_pathname_w.c_str(), ios::out | ios::binary); - } -#else // _WIN32 - target.open(target_pathname.c_str(), ios::out | ios::binary); -#endif // _WIN32 - if (!target) { - nout << "Couldn't write to " << target_pathname << "\n"; - return IT_step_failed; - } - - static const int decompress_buffer_size = 81920; - char decompress_buffer[decompress_buffer_size]; - static const int write_buffer_size = 81920; - char write_buffer[write_buffer_size]; - - z_stream z; - z.next_in = Z_NULL; - z.avail_in = 0; - z.next_out = Z_NULL; - z.avail_out = 0; - z.zalloc = Z_NULL; - z.zfree = Z_NULL; - z.opaque = Z_NULL; - z.msg = (char *)"no error message"; - - bool eof = false; - int flush = 0; - - source.read(decompress_buffer, decompress_buffer_size); - std::streamsize read_count = source.gcount(); - eof = (read_count == 0 || source.eof() || source.fail()); - - z.next_in = (Bytef *)decompress_buffer; - z.avail_in = (size_t)read_count; - - int result = inflateInit2(&z, 32 + 15); - if (result < 0) { - nout << z.msg << "\n"; - return IT_step_failed; - } - - while (true) { - if (z.avail_in == 0 && !eof) { - source.read(decompress_buffer, decompress_buffer_size); - std::streamsize read_count = source.gcount(); - eof = (read_count == 0 || source.eof() || source.fail()); - - z.next_in = (Bytef *)decompress_buffer; - z.avail_in = (size_t)read_count; - } - - z.next_out = (Bytef *)write_buffer; - z.avail_out = write_buffer_size; - int result = inflate(&z, flush); - if (z.avail_out < write_buffer_size) { - target.write(write_buffer, write_buffer_size - z.avail_out); - if (!target) { - nout << "Couldn't write entire file to " << target_pathname << "\n"; - return IT_step_failed; - } - - thread_add_bytes_done(write_buffer_size - z.avail_out); - } - - if (result == Z_STREAM_END) { - // Here's the end of the file. - break; - - } else if (result == Z_BUF_ERROR && flush == 0) { - // We might get this if no progress is possible, for instance if the - // input stream is truncated. In this case, tell zlib to dump - // everything it's got. - flush = Z_FINISH; - - } else if (result < 0) { - nout << z.msg << "\n"; - inflateEnd(&z); - return IT_step_failed; - } - } - - result = inflateEnd(&z); - if (result < 0) { - nout << z.msg << "\n"; - return IT_step_failed; - } - - source.close(); - target.close(); - - if (_verify_target && !_target.full_verify(_package->get_package_dir())) { - nout << "after uncompressing " << target_pathname - << ", failed hash check\n"; - return IT_step_failed; - } - - // Now that we've verified the target, make it read-only. - chmod(target_pathname.c_str(), 0444); - - // Now we can safely remove the source. -#ifdef _WIN32 - chmod(source_pathname.c_str(), 0644); -#endif - unlink(source_pathname.c_str()); - - // All done uncompressing. - _package->_updated = true; - return IT_step_complete; -} - -/** - * - */ -void P3DPackage::InstallStepUncompressFile:: -output(ostream &out) { - out << "InstallStepUncompressFile(" << _package->get_package_name() - << ", " << _source.get_filename() << ", " << _target.get_filename() - << ", " << _verify_target << ")"; -} - -/** - * - */ -P3DPackage::InstallStepUnpackArchive:: -InstallStepUnpackArchive(P3DPackage *package, size_t unpack_size) : - InstallStepThreaded(package, unpack_size, _unpack_factor) -{ -} - -/** - * - */ -P3DPackage::InstallToken P3DPackage::InstallStepUnpackArchive:: -thread_step() { - string source_pathname = _package->get_archive_file_pathname(); - P3DMultifileReader reader; - - if (!reader.open_read(source_pathname)) { - nout << "Couldn't read " << source_pathname << "\n"; - return IT_step_failed; - } - - if (!reader.extract_all(_package->get_package_dir(), _package, this)) { - nout << "Failure extracting " << source_pathname << "\n"; - return IT_step_failed; - } - - _package->_updated = true; - return IT_step_complete; -} - -/** - * - */ -void P3DPackage::InstallStepUnpackArchive:: -output(ostream &out) { - out << "InstallStepUnpackArchive(" << _package->get_package_name() << ")"; -} - - -/** - * - */ -P3DPackage::InstallStepApplyPatch:: -InstallStepApplyPatch(P3DPackage *package, const FileSpec &patchfile, - const FileSpec &source, const FileSpec &target) : - InstallStepThreaded(package, target.get_size(), _patch_factor), - _reader(package->get_package_dir(), patchfile, source, target) -{ -} - -/** - * - */ -P3DPackage::InstallToken P3DPackage::InstallStepApplyPatch:: -thread_step() { - // Open the patchfile - if (!_reader.open_read()) { - _reader.close(); - return IT_step_failed; - } - - // Apply the patch. - while (_reader.step()) { - size_t bytes_written = _reader.get_bytes_written(); - thread_set_bytes_done(bytes_written); - } - - // Close and verify. - _reader.close(); - - if (!_reader.get_success()) { - nout << "Patching failed\n"; - return IT_step_failed; - } - - _package->_updated = true; - return IT_step_complete; -} - -/** - * - */ -void P3DPackage::InstallStepApplyPatch:: -output(ostream &out) { - out << "InstallStepApplyPatch(" << _package->get_package_name() << ")"; -} diff --git a/direct/src/plugin/p3dPackage.h b/direct/src/plugin/p3dPackage.h deleted file mode 100644 index 4d44282c67..0000000000 --- a/direct/src/plugin/p3dPackage.h +++ /dev/null @@ -1,310 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPackage.h - * @author drose - * @date 2009-06-12 - */ - -#ifndef P3DPACKAGE_H -#define P3DPACKAGE_H - -#include "p3d_plugin_common.h" -#include "p3dFileDownload.h" -#include "p3dPatchfileReader.h" -#include "fileSpec.h" -#include "get_tinyxml.h" -#include - -class P3DHost; -class P3DInstance; -class P3DTemporaryFile; - -/** - * This corresponds to a downloadable, patchable package, and all its - * constituent files. For instance, a particular version of the Panda3D - * runtime, which consists of a bunch of dll's downloaded in a single tar - * file, is a package. - * - * The core API is responsible for managing these packages on disk, - * downloading new versions when needed, and removing stale versions to limit - * disk space waste. - */ -class P3DPackage { -private: - P3DPackage(P3DHost *host, - const std::string &package_name, - const std::string &package_version, - const std::string &package_platform, - const std::string &alt_host); - ~P3DPackage(); - -public: - inline bool get_info_ready() const; - inline size_t get_download_size() const; - - void activate_download(); - inline bool get_ready() const; - inline bool get_failed() const; - inline P3DHost *get_host() const; - inline const std::string &get_package_dir() const; - inline const std::string &get_package_name() const; - inline const std::string &get_package_version() const; - inline const std::string &get_package_platform() const; - inline const std::string &get_package_display_name() const; - std::string get_formatted_name() const; - inline const TiXmlElement *get_xconfig() const; - - inline const std::string &get_desc_file_pathname() const; - inline const std::string &get_desc_file_dirname() const; - inline std::string get_archive_file_pathname() const; - - void add_instance(P3DInstance *inst); - void remove_instance(P3DInstance *inst); - - void mark_used(); - void uninstall(); - - TiXmlElement *make_xml(); - -private: - typedef std::vector Extracts; - - enum DownloadType { - DT_contents_file, - DT_redownload_contents_file, - DT_desc_file, - DT_install_step, - }; - - typedef std::vector TryUrls; - - class Download : public P3DFileDownload { - public: - Download(P3DPackage *package, DownloadType dtype, - const FileSpec &file_spec); - Download(const Download ©); - - protected: - virtual void download_progress(); - virtual void download_finished(bool success); - - public: - void resume_download_finished(bool success); - - public: - // URL's to try downloading from, in reverse order. - TryUrls _try_urls; - - private: - P3DPackage *_package; - DownloadType _dtype; - - // FileSpec to validate the download against. - FileSpec _file_spec; - }; - - enum InstallToken { - IT_step_complete, - IT_step_failed, - IT_continue, - IT_needs_callback, - IT_terminate, - }; - - class InstallStep { - public: - InstallStep(P3DPackage *package, size_t bytes, double factor); - virtual ~InstallStep(); - - virtual InstallToken do_step(bool download_finished) = 0; - virtual void output(std::ostream &out) = 0; - - inline double get_effort() const; - inline double get_progress() const; - inline void report_step_progress(); - - P3DPackage *_package; - size_t _bytes_needed; - size_t _bytes_done; - double _bytes_factor; - }; - - class InstallStepDownloadFile : public InstallStep { - public: - InstallStepDownloadFile(P3DPackage *package, const FileSpec &file); - virtual ~InstallStepDownloadFile(); - - virtual InstallToken do_step(bool download_finished); - virtual void output(std::ostream &out); - - std::string _urlbase; - std::string _pathname; - FileSpec _file; - Download *_download; - }; - - class InstallStepThreaded : public InstallStep { - public: - InstallStepThreaded(P3DPackage *package, size_t bytes, double factor); - virtual ~InstallStepThreaded(); - - virtual InstallToken do_step(bool download_finished); - - THREAD_CALLBACK_DECLARATION(InstallStepThreaded, thread_main); - void thread_main(); - virtual InstallToken thread_step()=0; - void thread_set_bytes_done(size_t bytes_done); - void thread_add_bytes_done(size_t bytes_done); - - THREAD _thread; - LOCK _thread_lock; - bool _thread_started; - InstallToken _thread_token; - size_t _thread_bytes_done; - }; - - class InstallStepUncompressFile : public InstallStepThreaded { - public: - InstallStepUncompressFile(P3DPackage *package, const FileSpec &source, - const FileSpec &target, bool verify_target); - virtual InstallToken thread_step(); - virtual void output(std::ostream &out); - - FileSpec _source; - FileSpec _target; - bool _verify_target; - }; - - class InstallStepUnpackArchive : public InstallStepThreaded { - public: - InstallStepUnpackArchive(P3DPackage *package, size_t unpack_size); - virtual InstallToken thread_step(); - virtual void output(std::ostream &out); - }; - - class InstallStepApplyPatch : public InstallStepThreaded { - public: - InstallStepApplyPatch(P3DPackage *package, - const FileSpec &patchfile, - const FileSpec &source, - const FileSpec &target); - virtual InstallToken thread_step(); - virtual void output(std::ostream &out); - - P3DPatchfileReader _reader; - }; - - typedef std::deque InstallPlan; - typedef std::deque InstallPlans; - InstallPlans _install_plans; - - bool _computed_plan_size; - double _total_plan_size; - double _total_plan_completed; - double _download_progress; - double _current_step_effort; - - void begin_info_download(); - void download_contents_file(); - void contents_file_download_finished(bool success); - void redownload_contents_file(Download *download); - void contents_file_redownload_finished(bool success); - void host_got_contents_file(); - - void download_desc_file(); - void desc_file_download_finished(bool success); - void got_desc_file(TiXmlDocument *doc, bool freshly_downloaded); - - void clear_install_plans(); - void build_install_plans(TiXmlDocument *doc); - void follow_install_plans(bool download_finished, bool plan_failed); - static void st_callback(void *self); - void request_callback(); - - void report_progress(InstallStep *step); - void report_info_ready(); - void report_done(bool success); - Download *start_download(DownloadType dtype, const std::string &urlbase, - const std::string &pathname, const FileSpec &file_spec); - void set_active_download(Download *download); - void set_saved_download(Download *download); - - bool is_extractable(FileSpec &file, const std::string &filename) const; - bool instance_terminating(P3DInstance *instance); - void set_fullname(); - -public: - class RequiredPackage { - public: - inline RequiredPackage(const std::string &package_name, - const std::string &package_version, - const std::string &package_seq, - P3DHost *host); - std::string _package_name; - std::string _package_version; - std::string _package_seq; - P3DHost *_host; - }; - typedef std::vector Requires; - Requires _requires; - -private: - P3DHost *_host; - int _host_contents_iseq; - - std::string _package_name; - std::string _package_version; - std::string _package_platform; - bool _per_platform; - int _patch_version; - std::string _alt_host; - bool _package_solo; - std::string _package_display_name; - std::string _package_fullname; - std::string _package_dir; - TiXmlElement *_xconfig; - - P3DTemporaryFile *_temp_contents_file; - - FileSpec _desc_file; - std::string _desc_file_dirname; - std::string _desc_file_basename; - std::string _desc_file_pathname; - - bool _info_ready; - bool _allow_data_download; - bool _ready; - bool _failed; - Download *_active_download; - Download *_saved_download; - - typedef std::vector Instances; - Instances _instances; - - FileSpec _compressed_archive; - FileSpec _uncompressed_archive; - - size_t _unpack_size; - Extracts _extracts; - bool _updated; - - static const double _download_factor; - static const double _uncompress_factor; - static const double _unpack_factor; - static const double _patch_factor; - - friend class Download; - friend class InstallStep; - friend class P3DMultifileReader; - friend class P3DHost; -}; - -#include "p3dPackage.I" - -#endif diff --git a/direct/src/plugin/p3dPatchFinder.I b/direct/src/plugin/p3dPatchFinder.I deleted file mode 100644 index af066807ca..0000000000 --- a/direct/src/plugin/p3dPatchFinder.I +++ /dev/null @@ -1,12 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPatchFinder.I - * @author drose - * @date 2009-09-27 - */ diff --git a/direct/src/plugin/p3dPatchFinder.cxx b/direct/src/plugin/p3dPatchFinder.cxx deleted file mode 100644 index fbc109fe8c..0000000000 --- a/direct/src/plugin/p3dPatchFinder.cxx +++ /dev/null @@ -1,399 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPatchFinder.cxx - * @author drose - * @date 2009-09-27 - */ - -#include "p3dPatchFinder.h" - -using std::string; - -/** - * - */ -P3DPatchFinder::PackageVersion:: -PackageVersion(const PackageVersionKey &key) : - _package_name(key._package_name), - _platform(key._platform), - _version(key._version), - _host_url(key._host_url), - _file(key._file) -{ - _package_current = nullptr; - _package_base = nullptr; -} - -/** - * Fills chain with the list of patches that, when applied in sequence to the - * indicated PackageVersion object, produces this PackageVersion object. - * Returns false if no chain can be found. - */ -bool P3DPatchFinder::PackageVersion:: -get_patch_chain(Patchfiles &chain, PackageVersion *start_pv, - const PackageVersionsList &already_visited_in) { - chain.clear(); - if (this == start_pv) { - // We're already here. A zero-length patch chain is therefore the answer. - return true; - } - if (::find(already_visited_in.begin(), already_visited_in.end(), this) != already_visited_in.end()) { - // We've already been here; this is a loop. Avoid infinite recursion. - return false; - } - - // Yeah, we make a new copy of this vector at each stage of the recursion. - // This could be made much faster with a linked list instead, but I'm - // working on the assumption that there will be no more than a few dozen - // patchfiles, in which case this naive approach should be fast enough. - PackageVersionsList already_visited = already_visited_in; - already_visited.push_back(this); - - bool found_any = false; - Patchfiles::iterator pi; - for (pi = _from_patches.begin(); pi != _from_patches.end(); ++pi) { - Patchfile *patchfile = (*pi); - PackageVersion *from_pv = patchfile->_from_pv; - assert(from_pv != nullptr); - Patchfiles this_chain; - if (from_pv->get_patch_chain(this_chain, start_pv, already_visited)) { - // There's a path through this patchfile. - this_chain.push_back(patchfile); - if (!found_any || this_chain.size() < chain.size()) { - found_any = true; - chain.swap(this_chain); - } - } - } - - // If found_any is true, we've already filled chain with the shortest path - // found. - return found_any; -} - -/** - * - */ -P3DPatchFinder::PackageVersionKey:: -PackageVersionKey(const string &package_name, - const string &platform, - const string &version, - const string &host_url, - const FileSpec &file) : - _package_name(package_name), - _platform(platform), - _version(version), - _host_url(host_url), - _file(file) -{ -} - -/** - * - */ -bool P3DPatchFinder::PackageVersionKey:: -operator < (const PackageVersionKey &other) const { - if (_package_name != other._package_name) { - return _package_name < other._package_name; - } - if (_platform != other._platform) { - return _platform < other._platform; - } - if (_version != other._version) { - return _version < other._version; - } - if (_host_url != other._host_url) { - return _host_url < other._host_url; - } - return _file.compare_hash(other._file) < 0; -} - -/** - * - */ -void P3DPatchFinder::PackageVersionKey:: -output(std::ostream &out) const { - out << "(" << _package_name << ", " << _platform << ", " << _version - << ", " << _host_url << ", "; - _file.output_hash(out); - out << ")"; -} - -/** - * - */ -P3DPatchFinder::Patchfile:: -Patchfile(Package *package) : - _package(package), - _from_pv(nullptr), - _to_pv(nullptr) -{ - _package_name = package->_package_name; - _platform = package->_platform; - _version = package->_version; - _host_url = package->_host_url; -} - -/** - * Returns the key for locating the package that this patchfile can be applied - * to. - */ -P3DPatchFinder::PackageVersionKey P3DPatchFinder::Patchfile:: -get_source_key() const { - return PackageVersionKey(_package_name, _platform, _version, _host_url, _source_file); -} - -/** - * Returns the key for locating the package that this patchfile will generate. - */ -P3DPatchFinder::PackageVersionKey P3DPatchFinder::Patchfile:: -get_target_key() const { - return PackageVersionKey(_package_name, _platform, _version, _host_url, _target_file); -} - -/** - * Reads the data structures from an xml file. - */ -void P3DPatchFinder::Patchfile:: -load_xml(TiXmlElement *xpatch) { - const char *package_name_cstr = xpatch->Attribute("name"); - if (package_name_cstr != nullptr && *package_name_cstr) { - _package_name = package_name_cstr; - } - const char *platform_cstr = xpatch->Attribute("platform"); - if (platform_cstr != nullptr && *platform_cstr) { - _platform = platform_cstr; - } - const char *version_cstr = xpatch->Attribute("version"); - if (version_cstr != nullptr && *version_cstr) { - _version = version_cstr; - } - const char *host_url_cstr = xpatch->Attribute("host"); - if (host_url_cstr != nullptr && *host_url_cstr) { - _host_url = host_url_cstr; - } - - _file.load_xml(xpatch); - - TiXmlElement *xsource = xpatch->FirstChildElement("source"); - if (xsource != nullptr) { - _source_file.load_xml(xsource); - } - TiXmlElement *xtarget = xpatch->FirstChildElement("target"); - if (xtarget != nullptr) { - _target_file.load_xml(xtarget); - } -} - -/** - * - */ -P3DPatchFinder::Package:: -Package() { - _current_pv = nullptr; - _base_pv = nullptr; - _got_base_file = false; -} - -/** - * Returns the key to locate the current version of this package. - */ -P3DPatchFinder::PackageVersionKey P3DPatchFinder::Package:: -get_current_key() const { - return PackageVersionKey(_package_name, _platform, _version, _host_url, _current_file); -} - -/** - * Returns the key to locate the "base" or oldest version of this package. - */ -P3DPatchFinder::PackageVersionKey P3DPatchFinder::Package:: -get_base_key() const { - return PackageVersionKey(_package_name, _platform, _version, _host_url, _base_file); -} - -/** - * Returns the key that has the indicated hash. - */ -P3DPatchFinder::PackageVersionKey P3DPatchFinder::Package:: -get_generic_key(const FileSpec &file) const { - return PackageVersionKey(_package_name, _platform, _version, _host_url, file); -} - -/** - * Reads the package's desc file for the package information. Returns true on - * success, false on failure. - */ -bool P3DPatchFinder::Package:: -read_desc_file(TiXmlDocument *doc) { - TiXmlElement *xpackage = doc->FirstChildElement("package"); - if (xpackage == nullptr) { - return false; - } - - const char *package_name_cstr = xpackage->Attribute("name"); - if (package_name_cstr != nullptr && *package_name_cstr) { - _package_name = package_name_cstr; - } - const char *platform_cstr = xpackage->Attribute("platform"); - if (platform_cstr != nullptr && *platform_cstr) { - _platform = platform_cstr; - } - const char *version_cstr = xpackage->Attribute("version"); - if (version_cstr != nullptr && *version_cstr) { - _version = version_cstr; - } - const char *host_url_cstr = xpackage->Attribute("host"); - if (host_url_cstr != nullptr && *host_url_cstr) { - _host_url = host_url_cstr; - } - - // Get the current version. - TiXmlElement *xarchive = xpackage->FirstChildElement("uncompressed_archive"); - if (xarchive != nullptr) { - _current_file.load_xml(xarchive); - } - - // Get the base_version--the bottom (oldest) of the patch chain. - xarchive = xpackage->FirstChildElement("base_version"); - if (xarchive != nullptr) { - _base_file.load_xml(xarchive); - _got_base_file = true; - } - - _patches.clear(); - TiXmlElement *xpatch = xpackage->FirstChildElement("patch"); - while (xpatch != nullptr) { - Patchfile *patchfile = new Patchfile(this); - patchfile->load_xml(xpatch); - _patches.push_back(patchfile); - xpatch = xpatch->NextSiblingElement("patch"); - } - - return true; -} - -/** - * - */ -P3DPatchFinder:: -P3DPatchFinder() { -} - -/** - * - */ -P3DPatchFinder:: -~P3DPatchFinder() { - // TODO. Cleanup nicely. -} - -/** - * Loads the package defined in the indicated desc file, and constructs a - * patch chain from the version represented by file to the current version of - * this package, if possible. Returns true if successful, false otherwise. - */ -bool P3DPatchFinder:: -get_patch_chain_to_current(Patchfiles &chain, TiXmlDocument *doc, - const FileSpec &file) { - chain.clear(); - Package *package = read_package_desc_file(doc); - if (package == nullptr) { - return false; - } - - build_patch_chains(); - PackageVersion *from_pv = get_package_version(package->get_generic_key(file)); - PackageVersion *to_pv = package->_current_pv; - - if (to_pv != nullptr && from_pv != nullptr) { - return to_pv->get_patch_chain(chain, from_pv, PackageVersionsList()); - } - - return false; -} - - -/** - * Reads a desc file associated with a particular package, and adds the - * package to _packages. Returns the Package object, or NULL on failure. - */ -P3DPatchFinder::Package *P3DPatchFinder:: -read_package_desc_file(TiXmlDocument *doc) { - Package *package = new Package; - if (!package->read_desc_file(doc)) { - delete package; - return nullptr; - } - - _packages.push_back(package); - return package; -} - -/** - * Builds up the chains of PackageVersions and the patchfiles that connect - * them. - */ -void P3DPatchFinder:: -build_patch_chains() { - Packages::iterator pi; - for (pi = _packages.begin(); pi != _packages.end(); ++pi) { - Package *package = (*pi); - if (!package->_got_base_file) { - // This package doesn't have any versions yet. - continue; - } - - PackageVersion *current_pv = get_package_version(package->get_current_key()); - package->_current_pv = current_pv; - current_pv->_package_current = package; - current_pv->_print_name = package->_current_file.get_filename(); - - PackageVersion *base_pv = get_package_version(package->get_base_key()); - package->_base_pv = base_pv; - base_pv->_package_base = package; - base_pv->_print_name = package->_base_file.get_filename(); - - Patchfiles::iterator fi; - for (fi = package->_patches.begin(); fi != package->_patches.end(); ++fi) { - record_patchfile(*fi); - } - } -} - -/** - * Returns a shared PackageVersion object for the indicated key. - */ -P3DPatchFinder::PackageVersion *P3DPatchFinder:: -get_package_version(const PackageVersionKey &key) { - assert(!key._package_name.empty()); - PackageVersions::const_iterator vi = _package_versions.find(key); - if (vi != _package_versions.end()) { - return (*vi).second; - } - - PackageVersion *pv = new PackageVersion(key); - bool inserted = _package_versions.insert(PackageVersions::value_type(key, pv)).second; - assert(inserted); - return pv; -} - -/** - * Adds the indicated patchfile to the patch chains. - */ -void P3DPatchFinder:: -record_patchfile(Patchfile *patchfile) { - PackageVersion *from_pv = get_package_version(patchfile->get_source_key()); - patchfile->_from_pv = from_pv; - from_pv->_to_patches.push_back(patchfile); - - PackageVersion *to_pv = get_package_version(patchfile->get_target_key()); - patchfile->_to_pv = to_pv; - to_pv->_from_patches.push_back(patchfile); - to_pv->_print_name = patchfile->_file.get_filename(); -} diff --git a/direct/src/plugin/p3dPatchFinder.h b/direct/src/plugin/p3dPatchFinder.h deleted file mode 100644 index f25145a8e3..0000000000 --- a/direct/src/plugin/p3dPatchFinder.h +++ /dev/null @@ -1,179 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPatchFinder.h - * @author drose - * @date 2009-09-27 - */ - -#ifndef P3DPATCHFINDER_H -#define P3DPATCHFINDER_H - -#include "p3d_plugin_common.h" -#include "fileSpec.h" -#include "get_tinyxml.h" -#include -#include - -/** - * This class is used to reconstruct the patch chain--the chain of patch files - * needed to generate a file--for downloading a package via patches, rather - * than downloading the entire file. - * - * It is similar to PatchMaker.py, except it only reads patches, it does not - * generate them. - */ -class P3DPatchFinder { -public: - class Package; - class Patchfile; - class PackageVersion; - - typedef std::vector Patchfiles; - typedef std::vector PackageVersionsList; - - // This class is used to index into a map to locate PackageVersion objects, - // below. - class PackageVersionKey { - public: - PackageVersionKey(const std::string &package_name, - const std::string &platform, - const std::string &version, - const std::string &host_url, - const FileSpec &file); - bool operator < (const PackageVersionKey &other) const; - void output(std::ostream &out) const; - - public: - std::string _package_name; - std::string _platform; - std::string _version; - std::string _host_url; - FileSpec _file; - }; - - // A specific version of a package. This is not just a package's "version" - // string; it also corresponds to the particular patch version, which - // increments independently of the "version". - class PackageVersion { - public: - PackageVersion(const PackageVersionKey &key); - - bool get_patch_chain(Patchfiles &chain, PackageVersion *start_pv, - const PackageVersionsList &already_visited_in); - - public: - std::string _package_name; - std::string _platform; - std::string _version; - std::string _host_url; - FileSpec _file; - std::string _print_name; - - // The Package object that produces this version if this is the current - // form or the base form, respectively. - Package *_package_current; - Package *_package_base; - - // A list of patchfiles that can produce this version. - Patchfiles _from_patches; - - // A list of patchfiles that can start from this version. - Patchfiles _to_patches; - }; - - // A single patchfile for a package. - class Patchfile { - public: - Patchfile(Package *package); - - PackageVersionKey get_source_key() const; - PackageVersionKey get_target_key() const; - void load_xml(TiXmlElement *xpatch); - - public: - Package *_package; - std::string _package_name; - std::string _platform; - std::string _version; - std::string _host_url; - - // The patchfile itself - FileSpec _file; - - // The package file that the patch is applied to - FileSpec _source_file; - - // The package file that the patch generates - FileSpec _target_file; - - // The PackageVersion corresponding to our source_file - PackageVersion *_from_pv; - - // The PackageVersion corresponding to our target_file - PackageVersion *_to_pv; - }; - - // This is a particular package. This contains all of the information - // extracted from the package's desc file. - class Package { - public: - Package(); - - PackageVersionKey get_current_key() const; - PackageVersionKey get_base_key() const; - PackageVersionKey get_generic_key(const FileSpec &file) const; - - bool read_desc_file(TiXmlDocument *doc); - - public: - std::string _package_name; - std::string _platform; - std::string _version; - std::string _host_url; - - PackageVersion *_current_pv; - PackageVersion *_base_pv; - - FileSpec _current_file; - FileSpec _base_file; - bool _got_base_file; - - Patchfiles _patches; - }; - -public: - P3DPatchFinder(); - ~P3DPatchFinder(); - - bool get_patch_chain_to_current(Patchfiles &chain, TiXmlDocument *doc, - const FileSpec &file); - - Package *read_package_desc_file(TiXmlDocument *doc); - void build_patch_chains(); - PackageVersion *get_package_version(const PackageVersionKey &key); - -private: - void record_patchfile(Patchfile *patchfile); - -private: - typedef std::map PackageVersions; - PackageVersions _package_versions; - - typedef std::vector Packages; - Packages _packages; -}; - -#include "p3dPatchFinder.I" - -inline std::ostream &operator << (std::ostream &out, const P3DPatchFinder::PackageVersionKey &key) { - key.output(out); - return out; -} - -#endif diff --git a/direct/src/plugin/p3dPatchfileReader.I b/direct/src/plugin/p3dPatchfileReader.I deleted file mode 100644 index 9e290b43c8..0000000000 --- a/direct/src/plugin/p3dPatchfileReader.I +++ /dev/null @@ -1,72 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPatchfileReader.I - * @author drose - * @date 2009-09-28 - */ - -/** - * Returns true if the patchfile is currently open, false otherwise. - */ -inline bool P3DPatchfileReader:: -is_open() const { - return _is_open; -} - -/** - * Returns the number of bytes written to the output file so far during the - * patching process. - */ -inline size_t P3DPatchfileReader:: -get_bytes_written() const { - return _bytes_written; -} - -/** - * Returns true if the patching process has completed successfully, false if - * it has failed or has not yet completed. - */ -inline bool P3DPatchfileReader:: -get_success() const { - return _success; -} - -/** - * Extracts an unsigned short from the patchfile. - */ -inline unsigned int P3DPatchfileReader:: -read_uint16() { - unsigned int a = _patch_in.get(); - unsigned int b = _patch_in.get(); - return (b << 8) | a; -} - -/** - * Extracts an unsigned long from the patchfile. - */ -inline unsigned int P3DPatchfileReader:: -read_uint32() { - unsigned int a = _patch_in.get(); - unsigned int b = _patch_in.get(); - unsigned int c = _patch_in.get(); - unsigned int d = _patch_in.get(); - return (d << 24) | (c << 16) | (b << 8) | a; -} - -/** - * Extracts a signed long from the patchfile. - */ -inline int P3DPatchfileReader:: -read_int32() { - unsigned int a = _patch_in.get(); - unsigned int b = _patch_in.get(); - unsigned int c = _patch_in.get(); - int d = _patch_in.get(); - return (d << 24) | (c << 16) | (b << 8) | a; -} diff --git a/direct/src/plugin/p3dPatchfileReader.cxx b/direct/src/plugin/p3dPatchfileReader.cxx deleted file mode 100644 index 14ede5e9f9..0000000000 --- a/direct/src/plugin/p3dPatchfileReader.cxx +++ /dev/null @@ -1,280 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPatchfileReader.cxx - * @author drose - * @date 2009-09-28 - */ - -#include "p3dPatchfileReader.h" -#include "wstring_encode.h" - -using std::ios; -using std::string; - -/** - * - */ -P3DPatchfileReader:: -P3DPatchfileReader(const string &package_dir, const FileSpec &patchfile, - const FileSpec &source, const FileSpec &target) : - _package_dir(package_dir), - _patchfile(patchfile), - _source(source), - _target(target) -{ - _is_open = false; - _bytes_written = 0; - _success = false; -} - -/** - * - */ -P3DPatchfileReader:: -~P3DPatchfileReader() { - close(); -} - -/** - * Opens the named patchfile for reading, reads the header, and validates the - * inputs. Returns true on success, false otherwise. If this returns false, - * you should immediately call close(), or let this object destruct. - */ -bool P3DPatchfileReader:: -open_read() { - close(); - - // Synthesize an output filename, in case the source and the target refer to - // the same filename. - _output_pathname = _target.get_pathname(_package_dir); - _output_pathname += ".tmp"; - - string patch_pathname = _patchfile.get_pathname(_package_dir); - _patch_in.clear(); -#ifdef _WIN32 - std::wstring patch_pathname_w; - if (string_to_wstring(patch_pathname_w, patch_pathname)) { - _patch_in.open(patch_pathname_w.c_str(), ios::in | ios::binary); - } -#else // _WIN32 - _patch_in.open(patch_pathname.c_str(), ios::in | ios::binary); -#endif // _WIN32 - - string source_pathname = _source.get_pathname(_package_dir); - _source_in.clear(); -#ifdef _WIN32 - std::wstring source_pathname_w; - if (string_to_wstring(source_pathname_w, source_pathname)) { - _source_in.open(source_pathname_w.c_str(), ios::in | ios::binary); - } -#else // _WIN32 - _source_in.open(source_pathname.c_str(), ios::in | ios::binary); -#endif // _WIN32 - - mkfile_complete(_output_pathname, nout); - _target_out.clear(); -#ifdef _WIN32 - std::wstring output_pathname_w; - if (string_to_wstring(output_pathname_w, _output_pathname)) { - _target_out.open(output_pathname_w.c_str(), ios::in | ios::binary); - } -#else // _WIN32 - _target_out.open(_output_pathname.c_str(), ios::in | ios::binary); -#endif // _WIN32 - - _is_open = true; - - // If any of those failed to open, we fail. - if (_patch_in.fail() || _source_in.fail() || _target_out.fail()) { - nout << "Couldn't open patchfile source, input, and/or target.\n"; - return false; - } - - // Read the patchfile header and validate it against the hashes we were - // given. - unsigned int magic_number = read_uint32(); - if (magic_number != 0xfeebfaac) { - nout << "Not a valid patchfile: " << patch_pathname << "\n"; - return false; - } - - unsigned int version = read_uint16(); - if (version != 2) { - // This code only knows about patchfile version 2. If the patchfile code - // is updated, we have to update this code accordingly. - nout << "Unsupported patchfile version: " << version << "\n"; - return false; - } - - size_t source_length = read_uint32(); - if (source_length != _source.get_size()) { - nout << "Patchfile " << patch_pathname - << " doesn't match source size.\n"; - return false; - } - FileSpec validate; - validate.read_hash_stream(_patch_in); - if (_source.compare_hash(validate) != 0) { - nout << "Patchfile " << patch_pathname - << " doesn't match source hash.\n"; - return false; - } - - _target_length = read_uint32(); - if (_target_length != _target.get_size()) { - nout << "Patchfile " << patch_pathname - << " doesn't match target size.\n"; - return false; - } - validate.read_hash_stream(_patch_in); - if (_target.compare_hash(validate) != 0) { - nout << "Patchfile " << patch_pathname - << " doesn't match target hash.\n"; - return false; - } - - return true; -} - -/** - * Performs one incremental step of the patching operation. Returns true if - * the operation should continue and step() should be called again, false if - * the patching is done (either successfully, or due to failure). - */ -bool P3DPatchfileReader:: -step() { - assert(_is_open); - - size_t add_length = read_uint16(); - if (add_length != 0) { - // Add a number of bytes from the patchfile. - if (!copy_bytes(_patch_in, add_length)) { - nout << "Truncated patchfile.\n"; - return false; - } - } - - size_t copy_length = read_uint16(); - if (copy_length != 0) { - // Copy a number of bytes from the original source. - int offset = read_int32(); - _source_in.seekg(offset, ios::cur); - if (!copy_bytes(_source_in, copy_length)) { - nout << "Garbage in patchfile.\n"; - return false; - } - } - - assert(_bytes_written <= _target_length); - - // When both counts reach 0, the patchfile is done. - if (add_length != 0 || copy_length != 0) { - // So, we've still got more to do. - return true; - } - - if (_bytes_written != _target_length) { - nout << "Patchfile wrote truncated file.\n"; - return false; - } - - // Set the _success flag true, so close() will move the finished file into - // place. - _success = true; - close(); - - // Now validate the hash. - if (!_target.full_verify(_package_dir)) { - nout << "After patching, " << _target.get_filename() - << " is still incorrect.\n"; - _success = false; - return false; - } - - // Successfully patched! Return false to indicate completion. - return false; -} - -/** - * Closes the previously-opened files, and moves the output file into place. - * This also deletes the patchfile, assuming it will not be needed after it - * has been used. - */ -void P3DPatchfileReader:: -close() { - if (!_is_open) { - return; - } - - _is_open = false; - - _patch_in.close(); - _source_in.close(); - _target_out.close(); - - // Delete the patchfile. - string patch_pathname = _patchfile.get_pathname(_package_dir); -#ifdef _WIN32 - // Windows can't delete a file if it's read-only. - chmod(patch_pathname.c_str(), 0644); -#endif - unlink(patch_pathname.c_str()); - - if (_success) { - // Move the output file onto the target file. - string target_pathname = _target.get_pathname(_package_dir); -#ifdef _WIN32 - chmod(target_pathname.c_str(), 0644); -#endif - unlink(target_pathname.c_str()); - rename(_output_pathname.c_str(), target_pathname.c_str()); - - } else { - // Failure; remove the output file. -#ifdef _WIN32 - chmod(_output_pathname.c_str(), 0644); -#endif - unlink(_output_pathname.c_str()); - } -} - -/** - * Copies the indicated number of bytes from the indicated stream onto the - * output stream. Returns true on success, false if the input stream didn't - * have enough bytes. - */ -bool P3DPatchfileReader:: -copy_bytes(std::istream &in, size_t copy_byte_count) { - static const size_t buffer_size = 8192; - char buffer[buffer_size]; - - std::streamsize read_size = std::min(copy_byte_count, buffer_size); - in.read(buffer, read_size); - std::streamsize count = in.gcount(); - while (count != 0) { - _target_out.write(buffer, count); - _bytes_written += (size_t)count; - if (_bytes_written > _target_length) { - nout << "Runaway patchfile.\n"; - return false; - } - if (count != read_size) { - return false; - } - copy_byte_count -= (size_t)count; - count = 0; - if (copy_byte_count != 0) { - read_size = std::min(copy_byte_count, buffer_size); - in.read(buffer, read_size); - count = in.gcount(); - } - } - - return (copy_byte_count == 0); -} diff --git a/direct/src/plugin/p3dPatchfileReader.h b/direct/src/plugin/p3dPatchfileReader.h deleted file mode 100644 index 1c9501f5d1..0000000000 --- a/direct/src/plugin/p3dPatchfileReader.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPatchfileReader.h - * @author drose - * @date 2009-09-27 - */ - -#ifndef P3DPATCHFILEREADER_H -#define P3DPATCHFILEREADER_H - -#include "p3d_plugin_common.h" -#include "p3dInstanceManager.h" // for openssl -#include "fileSpec.h" - -/** - * A read-only implementation of Panda's patchfile format, for applying - * patches. - * - * This object assumes that the sourcefile has been already validated against - * its md5 hash, and does not validate it again. It *does* verify that the - * md5 hash in source and target match those read in the patchfile header; and - * it verifies the md5 hash on the target after completion. - */ -class P3DPatchfileReader { -public: - P3DPatchfileReader(const std::string &package_dir, - const FileSpec &patchfile, - const FileSpec &source, - const FileSpec &target); - ~P3DPatchfileReader(); - - bool open_read(); - inline bool is_open() const; - - bool step(); - inline size_t get_bytes_written() const; - inline bool get_success() const; - - void close(); - -private: - bool copy_bytes(std::istream &in, size_t copy_byte_count); - inline unsigned int read_uint16(); - inline unsigned int read_uint32(); - inline int read_int32(); - -private: - std::string _package_dir; - FileSpec _patchfile; - FileSpec _source; - FileSpec _target; - - std::string _output_pathname; - ifstream _patch_in; - ifstream _source_in; - ofstream _target_out; - - bool _is_open; - size_t _target_length; - size_t _bytes_written; - bool _success; -}; - -#include "p3dPatchfileReader.I" - -#endif diff --git a/direct/src/plugin/p3dPythonMain.cxx b/direct/src/plugin/p3dPythonMain.cxx deleted file mode 100644 index b5d11e6052..0000000000 --- a/direct/src/plugin/p3dPythonMain.cxx +++ /dev/null @@ -1,153 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPythonMain.cxx - * @author drose - * @date 2009-08-29 - */ - -#include "run_p3dpython.h" - -#include -#include -#include -#include -#include // strrchr - -#if defined(_WIN32) && defined(NON_CONSOLE) -// On Windows, we may need to build p3dpythonw.exe, a non-console version of -// this program. - -// We'll wrap the main() function with our own startup WinMain(). -#define main local_main -int main(int argc, char *argv[]); - -// Returns a newly-allocated string representing the quoted argument beginning -// at p. Advances p to the first character following the close quote. -static char * -parse_quoted_arg(char *&p) { - char quote = *p; - ++p; - std::string result; - - while (*p != '\0' && *p != quote) { - // TODO: handle escape characters? Not sure if we need to. - result += *p; - ++p; - } - if (*p == quote) { - ++p; - } - return strdup(result.c_str()); -} - -// Returns a newly-allocated string representing the unquoted argument -// beginning at p. Advances p to the first whitespace following the argument. -static char * -parse_unquoted_arg(char *&p) { - std::string result; - while (*p != '\0' && !isspace(*p)) { - result += *p; - ++p; - } - return strdup(result.c_str()); -} - -int WINAPI -WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { - char *command_line = GetCommandLine(); - - std::vector argv; - - char *p = command_line; - while (*p != '\0') { - if (*p == '"') { - char *arg = parse_quoted_arg(p); - argv.push_back(arg); - } else { - char *arg = parse_unquoted_arg(p); - argv.push_back(arg); - } - - // Skip whitespace. - while (*p != '\0' && isspace(*p)) { - ++p; - } - } - - assert(!argv.empty()); - return main(argv.size(), &argv[0]); -} -#endif // NON_CONSOLE - -/** - * This is a trivial main() function that invokes P3DPythonRun. It's used to - * build p3dpython.exe, which is the preferred way to run Python in a child - * process, as a separate executable. - */ -int -main(int argc, char *argv[]) { - const char *program_name = argv[0]; - const char *archive_file = nullptr; - const char *input_handle_str = nullptr; - const char *output_handle_str = nullptr; - const char *interactive_console_str = nullptr; - - if (argc > 1) { - archive_file = argv[1]; - } - if (argc > 2) { - input_handle_str = argv[2]; - } - if (argc > 3) { - output_handle_str = argv[3]; - } - if (argc > 4) { - interactive_console_str = argv[4]; - } - - if (archive_file == nullptr || *archive_file == '\0') { - std::cerr << "No archive filename specified on command line.\n"; - return 1; - } - - FHandle input_handle = invalid_fhandle; - if (input_handle_str != nullptr && *input_handle_str) { - std::stringstream stream(input_handle_str); - stream >> input_handle; - if (!stream) { - input_handle = invalid_fhandle; - } - } - - FHandle output_handle = invalid_fhandle; - if (output_handle_str != nullptr && *output_handle_str) { - std::stringstream stream(output_handle_str); - stream >> output_handle; - if (!stream) { - output_handle = invalid_fhandle; - } - } - - bool interactive_console = false; - if (interactive_console_str != nullptr && *interactive_console_str) { - std::stringstream stream(interactive_console_str); - int flag; - stream >> flag; - if (!stream.fail()) { - interactive_console = (flag != 0); - } - } - - int status = run_p3dpython(program_name, archive_file, input_handle, - output_handle, nullptr, interactive_console); - if (status != 0) { - std::cerr << "Failure on startup.\n"; - } - return status; -} diff --git a/direct/src/plugin/p3dPythonObject.cxx b/direct/src/plugin/p3dPythonObject.cxx deleted file mode 100644 index 58a2d0348f..0000000000 --- a/direct/src/plugin/p3dPythonObject.cxx +++ /dev/null @@ -1,341 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPythonObject.cxx - * @author drose - * @date 2009-07-03 - */ - -#include "p3dPythonObject.h" - -using std::string; - -/** - * - */ -P3DPythonObject:: -P3DPythonObject(P3DSession *session, int object_id) : - _session(session), - _object_id(object_id) -{ - _session->ref(); -} - -/** - * - */ -P3DPythonObject:: -~P3DPythonObject() { - // When the P3DPythonObject wrapper goes away, we have to inform the child - // process that we no longer need the corresponding PyObject to be kept - // around. - _session->drop_pyobj(_object_id); - p3d_unref_delete(_session); -} - -/** - * Returns the fundamental type of this kind of object. - */ -P3D_object_type P3DPythonObject:: -get_type() { - return P3D_OT_object; -} - -/** - * Returns the object value coerced to a boolean, if possible. - */ -bool P3DPythonObject:: -get_bool() { - bool bresult = 0; - - P3D_object *result = call("__bool__", true, nullptr, 0); - if (result != nullptr) { - bresult = P3D_OBJECT_GET_BOOL(result); - P3D_OBJECT_DECREF(result); - } - - return bresult; -} - -/** - * Returns the object value coerced to an integer, if possible. - */ -int P3DPythonObject:: -get_int() { - int iresult = 0; - - P3D_object *result = call("__int__", true, nullptr, 0); - if (result != nullptr) { - iresult = P3D_OBJECT_GET_INT(result); - P3D_OBJECT_DECREF(result); - } - - return iresult; -} - -/** - * Returns the object value coerced to a floating-point value, if possible. - */ -double P3DPythonObject:: -get_float() { - double fresult = 0.0; - - P3D_object *result = call("__float__", true, nullptr, 0); - if (result != nullptr) { - fresult = P3D_OBJECT_GET_FLOAT(result); - P3D_OBJECT_DECREF(result); - } - - return fresult; -} - -/** - * Fills the indicated C++ string object with the value of this object coerced - * to a string. - */ -void P3DPythonObject:: -make_string(string &value) { - P3D_object *result = call("__str__", true, nullptr, 0); - if (result != nullptr) { - int size = P3D_OBJECT_GET_STRING(result, nullptr, 0); - char *buffer = new char[size]; - P3D_OBJECT_GET_STRING(result, buffer, size); - value = string(buffer, size); - delete[] buffer; - - P3D_OBJECT_DECREF(result); - } -} - -/** - * Returns the named property element in the object. The return value is a - * new-reference P3D_object, or NULL on error. - */ -P3D_object *P3DPythonObject:: -get_property(const string &property) { - P3D_object *params[1]; - params[0] = new P3DStringObject(property); - - P3D_object *result = call("__get_property__", true, params, 1); - P3D_OBJECT_DECREF(params[0]); - return result; -} - -/** - * Modifies (or deletes, if value is NULL) the named property element in the - * object. Returns true on success, false on failure. - */ -bool P3DPythonObject:: -set_property(const string &property, bool needs_response, P3D_object *value) { - if (!_session->get_matches_script_origin()) { - // If you can't be scripting us, you can't be setting properties either. - return false; - } - - return set_property_insecure(property, needs_response, value); -} - -/** - * Works as set_property(), but does not check the matches_script_origin flag. - * Intended to be called internally only, never to be called from Javascript. - */ -bool P3DPythonObject:: -set_property_insecure(const string &property, bool needs_response, - P3D_object *value) { - bool bresult = !needs_response; - - P3D_object *params[2]; - params[0] = new P3DStringObject(property); - - P3D_object *result = nullptr; - - if (value == nullptr) { - // Delete an attribute. - result = call_insecure("__del_property__", needs_response, params, 1); - - } else { - // Set a new attribute. - params[1] = value; - result = call_insecure("__set_property__", needs_response, params, 2); - } - - P3D_OBJECT_DECREF(params[0]); - - if (result != nullptr) { - bresult = P3D_OBJECT_GET_BOOL(result); - P3D_OBJECT_DECREF(result); - } - - return bresult; -} - -/** - * Returns true if the named method exists on this object, false otherwise. - */ -bool P3DPythonObject:: -has_method(const string &method_name) { - // First, check the cache. - std::pair cresult = _has_method.insert(HasMethod::value_type(method_name, false)); - HasMethod::iterator hi = cresult.first; - if (!cresult.second) { - // Already cached. - return (*hi).second; - } - - bool bresult = false; - - P3D_object *params[1]; - params[0] = new P3DStringObject(method_name); - - P3D_object *result = call("__has_method__", true, params, 1); - P3D_OBJECT_DECREF(params[0]); - - if (result != nullptr) { - bresult = P3D_OBJECT_GET_BOOL(result); - P3D_OBJECT_DECREF(result); - } - - // Save the cached result, so we don't have to keep asking this question. - // We assume that the set of methods on an object don't change - // substantially, so we can get away with keeping this cache. - (*hi).second = bresult; - - return bresult; -} - -/** - * Invokes the named method on the object, passing the indicated parameters. - * If the method name is empty, invokes the object itself. - * - * If needs_response is true, the return value is a new-reference P3D_object - * on success, or NULL on failure. If needs_response is false, the return - * value is always NULL, and there is no way to determine success or failure. - */ -P3D_object *P3DPythonObject:: -call(const string &method_name, bool needs_response, - P3D_object *params[], int num_params) { - if (!_session->get_matches_script_origin()) { - // If you can't be scripting us, you can't be calling methods. - return nullptr; - } - - return call_insecure(method_name, needs_response, params, num_params); -} - -/** - * Works as call(), but does not check the matches_script_origin flag. - * Intended to be called internally only, never to be called from Javascript. - */ -P3D_object *P3DPythonObject:: -call_insecure(const string &method_name, bool needs_response, - P3D_object *params[], int num_params) { - TiXmlDocument *doc = new TiXmlDocument; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "pyobj"); - xcommand->SetAttribute("op", "call"); - if (!method_name.empty()) { - xcommand->SetAttribute("method_name", method_name); - } - - TiXmlElement *xobject = _session->p3dobj_to_xml(this); - xobject->SetValue("object"); - xcommand->LinkEndChild(xobject); - - for (int i = 0; i < num_params; ++i) { - TiXmlElement *xparams = _session->p3dobj_to_xml(params[i]); - xcommand->LinkEndChild(xparams); - } - - doc->LinkEndChild(xcommand); - - // If no response is requested, send the command out in a vacuum, and return - // NULL. - if (!needs_response) { - _session->send_command(doc); - return nullptr; - } - - // If a response is requested, we have to send the command and wait for it. - TiXmlDocument *response = _session->command_and_response(doc); - - P3D_object *result = nullptr; - if (response != nullptr) { - TiXmlElement *xresponse = response->FirstChildElement("response"); - if (xresponse != nullptr) { - TiXmlElement *xvalue = xresponse->FirstChildElement("value"); - if (xvalue != nullptr) { - result = _session->xml_to_p3dobj(xvalue); - } - } - delete response; - } - - return result; -} - -/** - * Writes a formatted representation of the value to the indicated string. - * This is intended for developer assistance. - */ -void P3DPythonObject:: -output(std::ostream &out) { - P3D_object *result = call("__repr__", true, nullptr, 0); - out << "Python " << _object_id; - if (result != nullptr) { - out << ": " << *result; - P3D_OBJECT_DECREF(result); - } -} - -/** - * If this object has a valid XML representation for the indicated session - * (that hasn't already been implemented by the generic code in P3DSession), - * this method will apply it to the indicated "value" element and return true. - * Otherwise, this method will leave the element unchanged and return false. - */ -bool P3DPythonObject:: -fill_xml(TiXmlElement *xvalue, P3DSession *session) { - if (session == _session) { - // If it's a P3DPythonObject from the same session, just send the - // object_id down, since the actual implementation of this object exists - // (as a Python object) in the sub-process space. - xvalue->SetAttribute("type", "python"); - xvalue->SetAttribute("object_id", _object_id); - return true; - } - - // Otherwise, we have to send it as a browser object. - return false; -} - -/** - * Returns this object, downcast to a P3DPythonObject, if it is in fact an - * object of that type; or NULL if it is not. - */ -P3DPythonObject *P3DPythonObject:: -as_python_object() { - return this; -} - -/** - * Returns the session that this object is identified with. - */ -P3DSession *P3DPythonObject:: -get_session() { - return _session; -} - - -/** - * Returns the object_id number that is used to uniquely identify this object - * in the XML stream. - */ -int P3DPythonObject:: -get_object_id() { - return _object_id; -} diff --git a/direct/src/plugin/p3dPythonObject.h b/direct/src/plugin/p3dPythonObject.h deleted file mode 100644 index a4f9c5d7d0..0000000000 --- a/direct/src/plugin/p3dPythonObject.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPythonObject.h - * @author drose - * @date 2009-07-02 - */ - -#ifndef P3DPYTHONOBJECT_H -#define P3DPYTHONOBJECT_H - -#include "p3d_plugin_common.h" -#include "p3dObject.h" - -class P3DSession; - -/** - * An object type that references a PyObject in the subordinate process. It - * allows querying and/or modifying the state of the referenced PyObject, via - * clever XML communication in P3DSession::command_and_response(). - */ -class P3DPythonObject : public P3DObject { -public: - P3DPythonObject(P3DSession *session, int object_id); - virtual ~P3DPythonObject(); - -public: - virtual P3D_object_type get_type(); - virtual bool get_bool(); - virtual int get_int(); - virtual double get_float(); - - virtual void make_string(std::string &value); - - virtual P3D_object *get_property(const std::string &property); - virtual bool set_property(const std::string &property, bool needs_response, P3D_object *value); - bool set_property_insecure(const std::string &property, bool needs_response, - P3D_object *value); - - virtual bool has_method(const std::string &method_name); - virtual P3D_object *call(const std::string &method_name, bool needs_response, - P3D_object *params[], int num_params); - P3D_object *call_insecure(const std::string &method_name, bool needs_response, - P3D_object *params[], int num_params); - - virtual void output(std::ostream &out); - virtual bool fill_xml(TiXmlElement *xvalue, P3DSession *session); - - virtual P3DPythonObject *as_python_object(); - - P3DSession *get_session(); - int get_object_id(); - -private: - P3DSession *_session; - int _object_id; - - typedef std::map HasMethod; - HasMethod _has_method; -}; - -#endif diff --git a/direct/src/plugin/p3dPythonRun.I b/direct/src/plugin/p3dPythonRun.I deleted file mode 100644 index dabbe7ef8f..0000000000 --- a/direct/src/plugin/p3dPythonRun.I +++ /dev/null @@ -1,12 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPythonRun.I - * @author drose - * @date 2009-06-05 - */ diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx deleted file mode 100644 index b9e4c5655e..0000000000 --- a/direct/src/plugin/p3dPythonRun.cxx +++ /dev/null @@ -1,1930 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPythonRun.cxx - * @author drose - * @date 2009-06-05 - */ - -#include "p3dPythonRun.h" -#include "asyncTaskManager.h" -#include "binaryXml.h" -#include "multifile.h" -#include "virtualFileSystem.h" -#include "nativeWindowHandle.h" - -#include "py_panda.h" - -using std::string; - -extern "C" { - // This has been compiled-in by the build system, if all is well. - extern struct _frozen _PyImport_FrozenModules[]; -}; - -// There is only one P3DPythonRun object in any given process space. Makes -// the statics easier to deal with, and we don't need multiple instances of -// this thing. -P3DPythonRun *P3DPythonRun::_global_ptr = nullptr; - -TypeHandle P3DPythonRun::P3DWindowHandle::_type_handle; - -/** - * - */ -P3DPythonRun:: -P3DPythonRun(const char *program_name, const char *archive_file, - FHandle input_handle, FHandle output_handle, - const char *log_pathname, bool interactive_console) { - P3DWindowHandle::init_type(); - init_xml(); - - _read_thread_continue = false; - _program_continue = true; - _session_terminated = false; - _taskMgr = nullptr; - - INIT_LOCK(_commands_lock); - INIT_THREAD(_read_thread); - - _session_id = 0; - _next_sent_id = 0; - - _interactive_console = interactive_console; - - if (program_name != nullptr) { -#if PY_MAJOR_VERSION >= 3 - // Python 3 case: we have to convert it to a wstring. - TextEncoder enc; - enc.set_text(program_name); - _program_name = enc.get_wtext(); -#else - // Python 2 is happy with a regular string. - _program_name = program_name; -#endif - } - if (archive_file != nullptr) { - _archive_file = Filename::from_os_specific(archive_file); - } - - _py_argc = 1; -#if PY_MAJOR_VERSION >= 3 - _py_argv[0] = (wchar_t *)_program_name.c_str(); -#else - _py_argv[0] = (char *)_program_name.c_str(); -#endif - _py_argv[1] = nullptr; - -#ifdef NDEBUG - // In OPTIMIZE 4 compilation mode, run Python in optimized mode too. - extern int Py_OptimizeFlag; - Py_OptimizeFlag = 2; -#endif - - // Turn off the automatic load of site.py at startup. - extern int Py_NoSiteFlag; - Py_NoSiteFlag = 1; - Py_NoUserSiteDirectory = 1; - - // Tell Python not to write bytecode files for loaded modules. - Py_DontWriteBytecodeFlag = 1; - - // Prevent Python from complaining about finding the standard modules. - Py_FrozenFlag = 1; - - // This contains the modules we need in order to call Py_Initialize, as well - // as the VFSImporter. - PyImport_FrozenModules = _PyImport_FrozenModules; - - // Initialize Python. It appears to be important to do this before we open - // the pipe streams and spawn the thread, below. -#if PY_MAJOR_VERSION >= 3 - Py_SetProgramName((wchar_t *)_program_name.c_str()); - Py_SetPythonHome((wchar_t *)L""); -#else - Py_SetProgramName((char *)_program_name.c_str()); - Py_SetPythonHome((char *)""); -#endif - Py_Initialize(); - PyEval_InitThreads(); - PySys_SetArgvEx(_py_argc, _py_argv, 0); - - // Open the error output before we do too much more. - if (log_pathname != nullptr && *log_pathname != '\0') { - Filename f = Filename::from_os_specific(log_pathname); - f.set_text(); - if (f.open_write(_error_log)) { - // Set up the indicated error log as the Notify output. - _error_log.setf(std::ios::unitbuf); - Notify::ptr()->set_ostream_ptr(&_error_log, false); - } - } - - // Open the pipe streams with the input and output handles from the parent. - _pipe_read.open_read(input_handle); - _pipe_write.open_write(output_handle); - - if (!_pipe_read) { - nout << "unable to open read pipe\n"; - } - if (!_pipe_write) { - nout << "unable to open write pipe\n"; - } - - spawn_read_thread(); -} - -/** - * - */ -P3DPythonRun:: -~P3DPythonRun() { - terminate_session(); - - // Close the write pipe, so the parent process will terminate us. - _pipe_write.close(); - - // Shut down Python and Panda. - Py_Finalize(); - - join_read_thread(); - DESTROY_LOCK(_commands_lock); - - // Restore the notify stream in case it tries to write to anything else - // after our shutdown. - Notify::ptr()->set_ostream_ptr(&std::cerr, false); -} - -/** - * Runs the embedded Python process. This method does not return until the - * plugin is ready to exit. - * - * Returns the exit status, which will be 0 on success. - */ -int P3DPythonRun:: -run_python() { -#if defined(_WIN32) && defined(USE_DEBUG_PYTHON) - // On Windows, in a debug build, we have to preload sys.dll_suffix = "_d", - // so that the Panda DLL preloader can import the correct filenames. - PyRun_SimpleString("import sys; sys.dll_suffix = '_d'"); -#endif - - Filename dir = _archive_file.get_dirname(); - - // We'll need to synthesize a 'panda3d' module before loading VFSImporter. - // We could simply freeze it, but Python has a bug setting __path__ of - // frozen modules properly. - PyObject *panda3d_module = PyImport_AddModule("panda3d"); - if (panda3d_module == nullptr) { - nout << "Failed to add panda3d module:\n"; - PyErr_Print(); - return 1; - } - - // Set the __path__ such that it can find panda3dcore.pyd, etc. - Filename panda3d_dir(dir, "panda3d"); - string dir_str = panda3d_dir.to_os_specific(); - PyModule_AddObject(panda3d_module, "__path__", Py_BuildValue("[s#]", dir_str.data(), dir_str.length())); - PyModule_AddStringConstant(panda3d_module, "__package__", "panda3d"); - - // Import the VFSImporter module that was frozen in. - PyObject *vfsimporter_module = PyImport_ImportModule("direct.showbase.VFSImporter"); - if (vfsimporter_module == nullptr) { - nout << "Failed to import VFSImporter:\n"; - PyErr_Print(); - return 1; - } - - // Now repair the "direct" and "direct.showbase" trees, which were - // presumably frozen along with the VFSImporter, by setting their __path__ - // such that we can still find the other direct modules. - Filename direct_dir(dir, "direct"); - PyObject *direct_module = PyImport_AddModule("direct"); - if (direct_module != nullptr) { - dir_str = direct_dir.to_os_specific(); - PyModule_AddObject(direct_module, "__path__", Py_BuildValue("[s#]", dir_str.data(), dir_str.length())); - PyModule_AddStringConstant(direct_module, "__package__", "direct"); - } - - PyObject *showbase_module = PyImport_AddModule("direct.showbase"); - if (showbase_module != nullptr) { - Filename showbase_dir(direct_dir, "showbase"); - dir_str = showbase_dir.to_os_specific(); - PyModule_AddObject(showbase_module, "__path__", Py_BuildValue("[s#]", dir_str.data(), dir_str.length())); - PyModule_AddStringConstant(showbase_module, "__package__", "direct.showbase"); - } - - PyObject *stdpy_module = PyImport_AddModule("direct.stdpy"); - if (stdpy_module != nullptr) { - Filename stdpy_dir(direct_dir, "stdpy"); - dir_str = stdpy_dir.to_os_specific(); - PyModule_AddObject(stdpy_module, "__path__", Py_BuildValue("[s#]", dir_str.data(), dir_str.length())); - PyModule_AddStringConstant(stdpy_module, "__package__", "direct.stdpy"); - } - - // And the encodings package as well, since we've presumably picked up a - // bunch of encodings modules as part of the frozen bundle. - Filename encodings_dir(dir, "encodings"); - PyObject *encodings_module = PyImport_AddModule("encodings"); - if (encodings_module != nullptr) { - dir_str = encodings_dir.to_os_specific(); - PyModule_AddObject(encodings_module, "__path__", Py_BuildValue("[s#]", dir_str.data(), dir_str.length())); - PyModule_AddStringConstant(encodings_module, "__package__", "encodings"); - } - - // And register the VFSImporter. - PyObject *result = PyObject_CallMethod(vfsimporter_module, (char *)"register", (char *)""); - if (result == nullptr) { - nout << "Failed to call VFSImporter.register():\n"; - PyErr_Print(); - return 1; - } - Py_DECREF(result); - Py_DECREF(vfsimporter_module); - - // Now, the VFSImporter has been registered, which means we can start - // importing the rest of the Python modules, which are all defined in the - // multifile. First, we need to mount the multifile into the VFS. - PT(Multifile) mf = new Multifile; - if (!mf->open_read(_archive_file)) { - nout << "Could not read " << _archive_file << "\n"; - return 1; - } - VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); - if (!vfs->mount(mf, dir, VirtualFileSystem::MF_read_only)) { - nout << "Could not mount " << _archive_file << "\n"; - return 1; - } - - // And finally, we can import the startup module. - PyObject *app_runner_module = PyImport_ImportModule("direct.p3d.AppRunner"); - if (app_runner_module == nullptr) { - nout << "Failed to import direct.p3d.AppRunner\n"; - PyErr_Print(); - return 1; - } - - // Get the pointers to the objects needed within the module. - PyObject *app_runner_class = PyObject_GetAttrString(app_runner_module, "AppRunner"); - if (app_runner_class == nullptr) { - nout << "Failed to get AppRunner class\n"; - PyErr_Print(); - return 1; - } - - // Construct an instance of AppRunner. - _runner = PyObject_CallFunction(app_runner_class, (char *)""); - if (_runner == nullptr) { - nout << "Failed to construct AppRunner instance\n"; - PyErr_Print(); - return 1; - } - Py_DECREF(app_runner_class); - - // Import the JavaScript module. - PyObject *javascript_module = PyImport_ImportModule("direct.p3d.JavaScript"); - if (javascript_module == nullptr) { - nout << "Failed to import direct.p3d.JavaScript\n"; - PyErr_Print(); - return false; - } - - // Get the UndefinedObject class. - _undefined_object_class = PyObject_GetAttrString(javascript_module, "UndefinedObject"); - if (_undefined_object_class == nullptr) { - PyErr_Print(); - return 1; - } - - // And the "Undefined" instance. - _undefined = PyObject_GetAttrString(javascript_module, "Undefined"); - if (_undefined == nullptr) { - PyErr_Print(); - return 1; - } - - // Get the ConcreteStruct class. - _concrete_struct_class = PyObject_GetAttrString(javascript_module, "ConcreteStruct"); - if (_concrete_struct_class == nullptr) { - PyErr_Print(); - return 1; - } - - // Get the BrowserObject class. - _browser_object_class = PyObject_GetAttrString(javascript_module, "BrowserObject"); - if (_browser_object_class == nullptr) { - PyErr_Print(); - return 1; - } - - // Get the global TaskManager. - _taskMgr = PyObject_GetAttrString(app_runner_module, "taskMgr"); - if (_taskMgr == nullptr) { - PyErr_Print(); - return 1; - } - - Py_DECREF(app_runner_module); - Py_DECREF(javascript_module); - - // Construct a Python wrapper around our methods we need to expose to - // Python. - static PyMethodDef p3dpython_methods[] = { - { "check_comm", P3DPythonRun::st_check_comm, METH_VARARGS, - "Poll for communications from the parent process" }, - { "request_func", P3DPythonRun::st_request_func, METH_VARARGS, - "Send an asynchronous request to the plugin host" }, - { nullptr, nullptr, 0, nullptr } /* Sentinel */ - }; - -#if PY_MAJOR_VERSION >= 3 - static PyModuleDef p3dpython_module = { - PyModuleDef_HEAD_INIT, - "p3dpython", - nullptr, - -1, - p3dpython_methods, - nullptr, nullptr, nullptr, nullptr - }; - PyObject *p3dpython = PyModule_Create(&p3dpython_module); -#else - PyObject *p3dpython = Py_InitModule("p3dpython", p3dpython_methods); -#endif - if (p3dpython == nullptr) { - PyErr_Print(); - return 1; - } - PyObject *request_func = PyObject_GetAttrString(p3dpython, "request_func"); - if (request_func == nullptr) { - PyErr_Print(); - return 1; - } - - // Now pass that func pointer back to our AppRunner instance, so it can call - // up to us. - result = PyObject_CallMethod(_runner, (char *)"setRequestFunc", (char *)"N", request_func); - if (result == nullptr) { - PyErr_Print(); - return 1; - } - Py_DECREF(result); - - // Now add check_comm() as a task. It can be a threaded task, but this does - // mean that application programmers will have to be alert to asynchronous - // calls coming in from JavaScript. We'll put it on its own task chain so - // the application programmer can decide how it should be. - AsyncTaskManager *task_mgr = AsyncTaskManager::get_global_ptr(); - PT(AsyncTaskChain) chain = task_mgr->make_task_chain("JavaScript"); - - // The default is not threaded (num_threads == 0), but if the app programmer - // decides to enable threads, the default is TP_low priority. - chain->set_thread_priority(TP_low); - - PyObject *check_comm = PyObject_GetAttrString(p3dpython, "check_comm"); - if (check_comm == nullptr) { - PyErr_Print(); - return 1; - } - - // Add it to the task manager. We do this instead of constructing a - // PythonTask because linking p3dpython with core.pyd is problematic. - result = PyObject_CallMethod(_taskMgr, (char *)"add", (char *)"Ns", check_comm, "check_comm"); - if (result == nullptr) { - PyErr_Print(); - return 1; - } - Py_DECREF(result); - - // Finally, get lost in AppRunner.run() (which is really a call to - // taskMgr.run()). - PyObject *done = PyObject_CallMethod(_runner, (char *)"run", (char *)""); - if (done == nullptr) { - int status = 1; - - // An uncaught application exception, and not handled by - // appRunner.exceptionHandler. If it is a SystemExit, extract the exit - // status that we should return. - if (PyErr_ExceptionMatches(PyExc_SystemExit)) { - PyObject *ptype, *ptraceback; - PyObject *value = nullptr; - PyErr_Fetch(&ptype, &value, &ptraceback); - - if (value != nullptr && PyExceptionInstance_Check(value)) { - PyObject *code = PyObject_GetAttrString(value, "code"); - if (code) { - Py_DECREF(value); - value = code; - } - } - - if (value == nullptr || value == Py_None) { - status = 0; -#if PY_MAJOR_VERSION >= 3 - } else if (PyLong_Check(value)) { - status = (int)PyLong_AsLong(value); -#else - } else if (PyInt_Check(value)) { - status = (int)PyInt_AsLong(value); -#endif - } else { - status = 1; - } - } else { - PyErr_Print(); - } - - if (_interactive_console) { - // Give an interactive user a chance to explore the exception. - run_interactive_console(); - return 0; - } - - // We're done. - return status; - } - - // A normal exit from the taskManager. We're presumably done. - Py_DECREF(done); - - if (_interactive_console) { - run_interactive_console(); - } - - return 0; -} - -/** - * Called from low-level Panda (via the P3DWindowHandle object) when a child - * window has been attached or detached from the browser window. This - * triggers the "onwindowattach" and "onwindowdetach" JavaScript - * notifications. - */ -void P3DPythonRun:: -set_window_open(P3DCInstance *inst, bool is_open) { - TiXmlDocument doc; - TiXmlElement *xrequest = new TiXmlElement("request"); - xrequest->SetAttribute("instance_id", inst->get_instance_id()); - xrequest->SetAttribute("rtype", "notify"); - if (is_open) { - xrequest->SetAttribute("message", "onwindowattach"); - } else { - xrequest->SetAttribute("message", "onwindowdetach"); - } - doc.LinkEndChild(xrequest); - - write_xml(_pipe_write, &doc, nout); -} - -/** - * Called from low-level Panda (via the P3DWindowHandle object) when its main - * window requires keyboard focus, but is unable to assign it directly. This - * is particularly necessary under Windows Vista, where a child window of the - * browser is specifically disallowed from being given keyboard focus. - * - * This sends a notify request up to the parent process, to ask the parent to - * manage keyboard events by proxy, and send them back down to Panda, again - * via the P3DWindowHandle. - */ -void P3DPythonRun:: -request_keyboard_focus(P3DCInstance *inst) { - TiXmlDocument doc; - TiXmlElement *xrequest = new TiXmlElement("request"); - xrequest->SetAttribute("instance_id", inst->get_instance_id()); - xrequest->SetAttribute("rtype", "notify"); - xrequest->SetAttribute("message", "keyboardfocus"); - doc.LinkEndChild(xrequest); - - write_xml(_pipe_write, &doc, nout); -} - -/** - * Gives the user a chance to type interactive Python commands, for easy - * development of a p3d application. This method is only called if - * "interactive_console=1" is set as a web token, and "allow_python_dev" is - * set within the application itself. - */ -void P3DPythonRun:: -run_interactive_console() { -#ifdef _WIN32 - // Make sure that control-C support is enabled for the interpreter. - SetConsoleCtrlHandler(nullptr, false); -#endif - - // The "readline" module makes the Python prompt friendlier, with command - // history and everything. Simply importing it is sufficient. - PyObject *readline_module = PyImport_ImportModule("readline"); - if (readline_module == nullptr) { - // But, the module might not exist on certain platforms. If not, no - // sweat. - PyErr_Clear(); - } else { - Py_DECREF(readline_module); - } - - PyRun_InteractiveLoop(stdin, ""); -} - -/** - * Handles a command received from the plugin host, via an XML syntax on the - * wire. Ownership of the XML document object is passed into this method. - * - * It's important *not* to be holding _commands_lock when calling this method. - */ -void P3DPythonRun:: -handle_command(TiXmlDocument *doc) { - TiXmlElement *xcommand = doc->FirstChildElement("command"); - if (xcommand != nullptr) { - bool needs_response = false; - int want_response_id; - if (xcommand->QueryIntAttribute("want_response_id", &want_response_id) == TIXML_SUCCESS) { - // This command will be waiting for a response. - needs_response = true; - } - - const char *cmd = xcommand->Attribute("cmd"); - if (cmd != nullptr) { - if (strcmp(cmd, "init") == 0) { - assert(!needs_response); - - // The only purpose of the "init" command is to send us a unique - // session ID, which in fact we don't do much with. - xcommand->Attribute("session_id", &_session_id); - - // We do use it to initiate our object id sequence with a number at - // least a little bit distinct from other sessions, though. No - // technical requirement that we do this, but it does make debugging - // the logs a bit easier. - _next_sent_id = _session_id * 1000; - - PyObject *obj = PyObject_CallMethod(_runner, (char*)"setSessionId", (char *)"i", _session_id); - Py_XDECREF(obj); - - } else if (strcmp(cmd, "start_instance") == 0) { - assert(!needs_response); - TiXmlElement *xinstance = xcommand->FirstChildElement("instance"); - if (xinstance != nullptr) { - P3DCInstance *inst = new P3DCInstance(xinstance); - start_instance(inst, xinstance); - } - - } else if (strcmp(cmd, "terminate_instance") == 0) { - assert(!needs_response); - int instance_id; - if (xcommand->QueryIntAttribute("instance_id", &instance_id) == TIXML_SUCCESS) { - terminate_instance(instance_id); - } - - } else if (strcmp(cmd, "setup_window") == 0) { - assert(!needs_response); - int instance_id; - TiXmlElement *xwparams = xcommand->FirstChildElement("wparams"); - if (xwparams != nullptr && - xcommand->QueryIntAttribute("instance_id", &instance_id) == TIXML_SUCCESS) { - setup_window(instance_id, xwparams); - } - - } else if (strcmp(cmd, "windows_message") == 0) { - assert(!needs_response); - // This is a special message that we use to proxy keyboard events from - // the parent process down into Panda, a necessary hack on Vista. - int instance_id = 0, msg = 0, wparam = 0, lparam = 0; - xcommand->Attribute("instance_id", &instance_id); - xcommand->Attribute("msg", &msg); - xcommand->Attribute("wparam", &wparam); - xcommand->Attribute("lparam", &lparam); - send_windows_message(instance_id, msg, wparam, lparam); - - } else if (strcmp(cmd, "exit") == 0) { - assert(!needs_response); - terminate_session(); - - } else if (strcmp(cmd, "pyobj") == 0) { - // Manipulate or query a python object. - handle_pyobj_command(xcommand, needs_response, want_response_id); - - } else if (strcmp(cmd, "script_response") == 0) { - // Response from a script request. In this case, we just store it - // away instead of processing it immediately. - - MutexHolder holder(_responses_lock); - _responses.push_back(doc); - - // And now we must return out, instead of deleting the document at the - // bottom of this method. - return; - - } else if (strcmp(cmd, "drop_pyobj") == 0) { - int object_id; - if (xcommand->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) { - SentObjects::iterator si = _sent_objects.find(object_id); - if (si != _sent_objects.end()) { - PyObject *obj = (*si).second; - Py_DECREF(obj); - _sent_objects.erase(si); - } - } - - } else { - nout << "Unhandled command " << cmd << "\n"; - if (needs_response) { - // Better send a response. - TiXmlDocument doc; - TiXmlElement *xresponse = new TiXmlElement("response"); - xresponse->SetAttribute("response_id", want_response_id); - doc.LinkEndChild(xresponse); - write_xml(_pipe_write, &doc, nout); - } - } - } - } - - delete doc; -} - -/** - * Handles the pyobj command, which queries or modifies a Python object from - * the browser scripts. - */ -void P3DPythonRun:: -handle_pyobj_command(TiXmlElement *xcommand, bool needs_response, - int want_response_id) { - TiXmlDocument doc; - TiXmlElement *xresponse = new TiXmlElement("response"); - xresponse->SetAttribute("response_id", want_response_id); - doc.LinkEndChild(xresponse); - - const char *op = xcommand->Attribute("op"); - if (op != nullptr && !PyErr_Occurred()) { - if (strcmp(op, "get_panda_script_object") == 0) { - // Get Panda's toplevel Python object. - PyObject *obj = PyObject_CallMethod(_runner, (char*)"getPandaScriptObject", (char *)""); - if (obj != nullptr) { - xresponse->LinkEndChild(pyobj_to_xml(obj)); - Py_DECREF(obj); - } - - } else if (strcmp(op, "set_browser_script_object") == 0) { - // Set the Browser's toplevel window object. - PyObject *obj; - TiXmlElement *xvalue = xcommand->FirstChildElement("value"); - if (xvalue != nullptr) { - obj = xml_to_pyobj(xvalue); - } else { - obj = Py_None; - Py_INCREF(obj); - } - - Py_XDECREF(PyObject_CallMethod - (_runner, (char *)"setBrowserScriptObject", (char *)"N", obj)); - - } else if (strcmp(op, "call") == 0) { - // Call the named method on the indicated object, or the object itself - // if method_name isn't given. - TiXmlElement *xobject = xcommand->FirstChildElement("object"); - if (xobject != nullptr) { - PyObject *obj = xml_to_pyobj(xobject); - - const char *method_name = xcommand->Attribute("method_name"); - - // Build up a list of params. - PyObject *list = PyList_New(0); - - TiXmlElement *xchild = xcommand->FirstChildElement("value"); - while (xchild != nullptr) { - PyObject *child = xml_to_pyobj(xchild); - PyList_Append(list, child); - Py_DECREF(child); - xchild = xchild->NextSiblingElement("value"); - } - - // Convert the list to a tuple for the call. - PyObject *params = PyList_AsTuple(list); - Py_DECREF(list); - - // Now call the method. - PyObject *result = nullptr; - if (method_name == nullptr) { - // No method name; call the object directly. - result = PyObject_CallObject(obj, params); - - // Several special-case "method" names. - } else if (strcmp(method_name, "__bool__") == 0) { - result = PyBool_FromLong(PyObject_IsTrue(obj)); - - } else if (strcmp(method_name, "__int__") == 0) { -#if PY_MAJOR_VERSION >= 3 - result = PyNumber_Long(obj); -#else - result = PyNumber_Int(obj); -#endif - } else if (strcmp(method_name, "__float__") == 0) { - result = PyNumber_Float(obj); - - } else if (strcmp(method_name, "__repr__") == 0) { - result = PyObject_Repr(obj); - - } else if (strcmp(method_name, "__str__") == 0 || - strcmp(method_name, "toString") == 0) { - result = PyObject_Str(obj); - - } else if (strcmp(method_name, "__set_property__") == 0) { - // We call these methods __set_property__ et al instead of - // __setattr__ et al, because they do not precisely duplicate the - // Python semantics. - char *property_name; - PyObject *value; - if (PyArg_ParseTuple(params, "sO", &property_name, &value)) { - bool success = false; - - // If it already exists as an attribute, update it there. - if (PyObject_HasAttrString(obj, property_name)) { - if (PyObject_SetAttrString(obj, property_name, value) != -1) { - success = true; - } else { - PyErr_Clear(); - } - } - - // If the object supports the mapping protocol, store it in the - // object's dictionary. - if (!success && PyMapping_Check(obj)) { - if (PyMapping_SetItemString(obj, property_name, value) != -1) { - success = true; - } else { - PyErr_Clear(); - } - } - - // Finally, try to store it on the object. - if (!success) { - if (PyObject_SetAttrString(obj, property_name, value) != -1) { - success = true; - } else { - PyErr_Clear(); - } - } - - if (success) { - result = Py_True; - } else { - result = Py_False; - } - Py_INCREF(result); - } - - } else if (strcmp(method_name, "__del_property__") == 0) { - char *property_name; - if (PyArg_ParseTuple(params, "s", &property_name)) { - bool success = false; - - if (PyObject_HasAttrString(obj, property_name)) { - if (PyObject_DelAttrString(obj, property_name) != -1) { - success = true; - } else { - PyErr_Clear(); - } - } - - if (!success) { - if (PyObject_DelItemString(obj, property_name) != -1) { - success = true; - } else { - PyErr_Clear(); - } - } - - if (success) { - result = Py_True; - } else { - result = Py_False; - } - Py_INCREF(result); - } - - } else if (strcmp(method_name, "__get_property__") == 0) { - char *property_name; - if (PyArg_ParseTuple(params, "s", &property_name)) { - bool success = false; - - if (PyObject_HasAttrString(obj, property_name)) { - result = PyObject_GetAttrString(obj, property_name); - if (result != nullptr) { - success = true; - } else { - PyErr_Clear(); - } - } - - if (!success) { - if (PyMapping_HasKeyString(obj, property_name)) { - result = PyMapping_GetItemString(obj, property_name); - if (result != nullptr) { - success = true; - } else { - PyErr_Clear(); - } - } - } - - if (!success) { - result = nullptr; - } - } - - } else if (strcmp(method_name, "__has_method__") == 0) { - char *property_name; - result = Py_False; - if (PyArg_ParseTuple(params, "s", &property_name)) { - if (*property_name) { - // Check for a callable method - if (PyObject_HasAttrString(obj, property_name)) { - PyObject *prop = PyObject_GetAttrString(obj, property_name); - if (PyCallable_Check(prop)) { - result = Py_True; - } - Py_DECREF(prop); - } - } else { - // Check for the default method - if (PyCallable_Check(obj)) { - result = Py_True; - } - } - } - Py_INCREF(result); - - } else { - // Not a special-case name. Call the named method. - PyObject *method = PyObject_GetAttrString(obj, (char *)method_name); - if (method != nullptr) { - result = PyObject_CallObject(method, params); - Py_DECREF(method); - } - } - Py_DECREF(params); - - // Feed the return value back through the XML pipe to the caller. - if (result != nullptr) { - xresponse->LinkEndChild(pyobj_to_xml(result)); - Py_DECREF(result); - } else { - // Print the Python error message if there was one. - PyErr_Print(); - } - - Py_DECREF(obj); - } - } - } - - if (needs_response) { - write_xml(_pipe_write, &doc, nout); - } -} - -/** - * This method is added to the task manager (via st_check_comm, below) so that - * it gets a call every frame. Its job is to check for commands received from - * the plugin host in the parent process. - */ -void P3DPythonRun:: -check_comm() { - // nout << ":"; - ACQUIRE_LOCK(_commands_lock); - while (!_commands.empty()) { - TiXmlDocument *doc = _commands.front(); - _commands.pop_front(); - RELEASE_LOCK(_commands_lock); - handle_command(doc); - if (_session_terminated) { - return; - } - ACQUIRE_LOCK(_commands_lock); - } - RELEASE_LOCK(_commands_lock); - - if (!_program_continue) { - // The low-level thread detected an error, for instance pipe closed. We - // should exit gracefully. - terminate_session(); - return; - } - - // Sleep to yield the timeslice, but only if we're not running in the main - // thread. - if (Thread::get_current_thread() != Thread::get_main_thread()) { - Thread::sleep(0.001); - } -} - -/** - * This is a static Python wrapper around py_check_comm, needed to add the - * function to a PythonTask. - */ -PyObject *P3DPythonRun:: -st_check_comm(PyObject *, PyObject *args) { - P3DPythonRun::_global_ptr->check_comm(); - return Py_BuildValue("i", AsyncTask::DS_cont); -} - -/** - * This method is similar to check_comm(), above, but instead of handling all - * events, it waits for a specific script_response ID to come back from the - * browser, and leaves all other events in the queue. - */ -TiXmlDocument *P3DPythonRun:: -wait_script_response(int response_id) { - // nout << "waiting script_response " << response_id << "\n"; - while (true) { - Commands::iterator ci; - - // First, walk through the _commands queue to see if there's anything that - // needs immediate processing. - ACQUIRE_LOCK(_commands_lock); - for (ci = _commands.begin(); ci != _commands.end(); ++ci) { - TiXmlDocument *doc = (*ci); - - TiXmlElement *xcommand = doc->FirstChildElement("command"); - if (xcommand != nullptr) { - const char *cmd = xcommand->Attribute("cmd"); - if ((cmd != nullptr && strcmp(cmd, "script_response") == 0) || - xcommand->Attribute("want_response_id") != nullptr) { - - // This is either a response, or it's a command that will want a - // response itself. In either case we should handle it right away. - // ("handling" a response means moving it to the _responses queue.) - _commands.erase(ci); - RELEASE_LOCK(_commands_lock); - handle_command(doc); - if (_session_terminated) { - return nullptr; - } - ACQUIRE_LOCK(_commands_lock); - break; - } - } - } - RELEASE_LOCK(_commands_lock); - - // Now, walk through the _responses queue to look for the particular - // response we're waiting for. - _responses_lock.acquire(); - for (ci = _responses.begin(); ci != _responses.end(); ++ci) { - TiXmlDocument *doc = (*ci); - - TiXmlElement *xcommand = doc->FirstChildElement("command"); - assert(xcommand != nullptr); - const char *cmd = xcommand->Attribute("cmd"); - assert(cmd != nullptr && strcmp(cmd, "script_response") == 0); - - int unique_id; - if (xcommand->QueryIntAttribute("unique_id", &unique_id) == TIXML_SUCCESS) { - if (unique_id == response_id) { - // This is the response we were waiting for. - _responses.erase(ci); - _responses_lock.release(); - // nout << "got script_response " << unique_id << "\n"; - return doc; - } - } - } - _responses_lock.release(); - - if (!_program_continue) { - terminate_session(); - return nullptr; - } - -#ifdef _WIN32 - // Make sure we process the Windows event loop while we're waiting, or - // everything that depends on Windows messages will starve. - - // We appear to be best off with just a single PeekMessage() call here; - // the full message pump seems to cause problems. - MSG msg; - PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE | PM_NOYIELD); -#endif // _WIN32 - - // nout << "."; - - // It hasn't shown up yet. Give the sub-thread a chance to process the - // input and append it to the queue. - Thread::force_yield(); - } - assert(false); -} - -/** - * This method is a special Python function that is added as a callback to the - * AppRunner class, to allow Python to upcall into this object. - */ -PyObject *P3DPythonRun:: -py_request_func(PyObject *args) { - int instance_id; - const char *request_type; - PyObject *extra_args; - if (!PyArg_ParseTuple(args, "isO", &instance_id, &request_type, &extra_args)) { - return nullptr; - } - - if (strcmp(request_type, "wait_script_response") == 0) { - // This is a special case. Instead of generating a new request, this - // means to wait for a particular script_response to come in on the wire. - int response_id; - if (!PyArg_ParseTuple(extra_args, "i", &response_id)) { - return nullptr; - } - - TiXmlDocument *doc = wait_script_response(response_id); - if (_session_terminated) { - return Py_BuildValue(""); - } - assert(doc != nullptr); - TiXmlElement *xcommand = doc->FirstChildElement("command"); - assert(xcommand != nullptr); - TiXmlElement *xvalue = xcommand->FirstChildElement("value"); - - PyObject *value = nullptr; - if (xvalue != nullptr) { - value = xml_to_pyobj(xvalue); - } else { - // An absence of a element is an exception. We will return NULL - // from this function, but first set the error condition. - PyErr_SetString(PyExc_EnvironmentError, "Error on script call"); - } - - delete doc; - return value; - } - - TiXmlDocument doc; - TiXmlElement *xrequest = new TiXmlElement("request"); - xrequest->SetAttribute("instance_id", instance_id); - xrequest->SetAttribute("rtype", request_type); - doc.LinkEndChild(xrequest); - - if (strcmp(request_type, "notify") == 0) { - // A general notification to be sent directly to the instance. - const char *message; - if (!PyArg_ParseTuple(extra_args, "s", &message)) { - return nullptr; - } - - xrequest->SetAttribute("message", message); - write_xml(_pipe_write, &doc, nout); - - } else if (strcmp(request_type, "script") == 0) { - // Meddling with a scripting variable on the browser side. - const char *operation; - PyObject *object; - const char *property_name; - PyObject *value; - int needs_response; - int unique_id; - if (!PyArg_ParseTuple(extra_args, "sOsOii", - &operation, &object, &property_name, &value, - &needs_response, &unique_id)) { - return nullptr; - } - - xrequest->SetAttribute("operation", operation); - xrequest->SetAttribute("property_name", property_name); - xrequest->SetAttribute("needs_response", (int)(needs_response != 0)); - xrequest->SetAttribute("unique_id", unique_id); - TiXmlElement *xobject = pyobj_to_xml(object); - xobject->SetValue("object"); - xrequest->LinkEndChild(xobject); - TiXmlElement *xvalue = pyobj_to_xml(value); - xrequest->LinkEndChild(xvalue); - - write_xml(_pipe_write, &doc, nout); - - } else if (strcmp(request_type, "drop_p3dobj") == 0) { - // Release a particular P3D_object that we were holding a reference to. - int object_id; - if (!PyArg_ParseTuple(extra_args, "i", &object_id)) { - return nullptr; - } - - xrequest->SetAttribute("object_id", object_id); - write_xml(_pipe_write, &doc, nout); - - } else if (strcmp(request_type, "forget_package") == 0) { - // A request to the instance to drop a particular package (or host) from - // the cache. - const char *host_url; - const char *package_name; - const char *package_version; - if (!PyArg_ParseTuple(extra_args, "sss", &host_url, &package_name, &package_version)) { - return nullptr; - } - - xrequest->SetAttribute("host_url", host_url); - if (*package_name) { - xrequest->SetAttribute("package_name", package_name); - if (*package_version) { - xrequest->SetAttribute("package_version", package_version); - } - } - write_xml(_pipe_write, &doc, nout); - - } else { - string message = string("Unsupported request type: ") + string(request_type); - PyErr_SetString(PyExc_ValueError, message.c_str()); - return nullptr; - } - - return Py_BuildValue(""); -} - -/** - * This is the static wrapper around py_request_func. - */ -PyObject *P3DPythonRun:: -st_request_func(PyObject *, PyObject *args) { - return P3DPythonRun::_global_ptr->py_request_func(args); -} - -/** - * Starts the read thread. This thread is responsible for reading the - * standard input socket for XML commands and storing them in the _commands - * queue. - */ -void P3DPythonRun:: -spawn_read_thread() { - assert(!_read_thread_continue); - - // We have to use direct OS calls to create the thread instead of Panda - // constructs, because it has to be an actual thread, not necessarily a - // Panda thread (we can't use Panda's simple threads implementation, because - // we can't get overlapped IO on an anonymous pipe in Windows). - - _read_thread_continue = true; - SPAWN_THREAD(_read_thread, rt_thread_run, this); -} - -/** - * Waits for the read thread to stop. - */ -void P3DPythonRun:: -join_read_thread() { - _read_thread_continue = false; - JOIN_THREAD(_read_thread); -} - -/** - * Starts the indicated instance running within the Python process. - */ -void P3DPythonRun:: -start_instance(P3DCInstance *inst, TiXmlElement *xinstance) { - _instances[inst->get_instance_id()] = inst; - - set_instance_info(inst, xinstance); - - TiXmlElement *xpackage = xinstance->FirstChildElement("package"); - while (xpackage != nullptr) { - add_package_info(inst, xpackage); - xpackage = xpackage->NextSiblingElement("package"); - } - - TiXmlElement *xfparams = xinstance->FirstChildElement("fparams"); - if (xfparams != nullptr) { - set_p3d_filename(inst, xfparams); - } - - TiXmlElement *xwparams = xinstance->FirstChildElement("wparams"); - if (xwparams != nullptr) { - setup_window(inst, xwparams); - } -} - -/** - * Stops the instance with the indicated id. - */ -void P3DPythonRun:: -terminate_instance(int id) { - Instances::iterator ii = _instances.find(id); - if (ii == _instances.end()) { - nout << "Can't stop instance " << id << ": not started.\n"; - return; - } - - P3DCInstance *inst = (*ii).second; - _instances.erase(ii); - delete inst; - - // TODO: we don't currently have any way to stop just one instance of a - // multi-instance session. This will require a different Python interface - // than ShowBase. - terminate_session(); -} - -/** - * Sets some global information about the instance. - */ -void P3DPythonRun:: -set_instance_info(P3DCInstance *inst, TiXmlElement *xinstance) { - const char *root_dir = xinstance->Attribute("root_dir"); - if (root_dir == nullptr) { - root_dir = ""; - } - - const char *log_directory = xinstance->Attribute("log_directory"); - if (log_directory == nullptr) { - log_directory = ""; - } - - int verify_contents = 0; - xinstance->Attribute("verify_contents", &verify_contents); - - const char *super_mirror = xinstance->Attribute("super_mirror"); - if (super_mirror == nullptr) { - super_mirror = ""; - } - - // Get the initial "main" object, if specified. - PyObject *main; - TiXmlElement *xmain = xinstance->FirstChildElement("main"); - if (xmain != nullptr) { - main = xml_to_pyobj(xmain); - } else { - main = Py_None; - Py_INCREF(main); - } - - int respect_per_platform = 0; - xinstance->Attribute("respect_per_platform", &respect_per_platform); - - PyObject *result = PyObject_CallMethod - (_runner, (char *)"setInstanceInfo", (char *)"sssiNi", root_dir, - log_directory, super_mirror, verify_contents, main, respect_per_platform); - - if (result == nullptr) { - PyErr_Print(); - if (_interactive_console) { - run_interactive_console(); - } - exit(1); - } - Py_XDECREF(result); -} - -/** - * Adds some information about a pre-loaded package. - */ -void P3DPythonRun:: -add_package_info(P3DCInstance *inst, TiXmlElement *xpackage) { - const char *name = xpackage->Attribute("name"); - const char *platform = xpackage->Attribute("platform"); - const char *version = xpackage->Attribute("version"); - const char *host = xpackage->Attribute("host"); - const char *host_dir = xpackage->Attribute("host_dir"); - if (name == nullptr || host == nullptr) { - return; - } - if (version == nullptr) { - version = ""; - } - if (platform == nullptr) { - platform = ""; - } - if (host_dir == nullptr) { - host_dir = ""; - } - - PyObject *result = PyObject_CallMethod - (_runner, (char *)"addPackageInfo", (char *)"sssss", - name, platform, version, host, host_dir); - - if (result == nullptr) { - PyErr_Print(); - if (_interactive_console) { - run_interactive_console(); - } - exit(1); - } - - Py_XDECREF(result); -} - -/** - * Sets the startup filename and tokens for the indicated instance. - */ -void P3DPythonRun:: -set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams) { - string p3d_filename; - const char *p3d_filename_c = xfparams->Attribute("p3d_filename"); - if (p3d_filename_c != nullptr) { - p3d_filename = p3d_filename_c; - } - - int p3d_offset = 0; - xfparams->Attribute("p3d_offset", &p3d_offset); - - string p3d_url; - const char *p3d_url_c = xfparams->Attribute("p3d_url"); - if (p3d_url_c != nullptr) { - p3d_url = p3d_url_c; - } - - PyObject *token_list = PyList_New(0); - TiXmlElement *xtoken = xfparams->FirstChildElement("token"); - while (xtoken != nullptr) { - string keyword, value; - const char *keyword_c = xtoken->Attribute("keyword"); - if (keyword_c != nullptr) { - keyword = keyword_c; - } - - const char *value_c = xtoken->Attribute("value"); - if (value_c != nullptr) { - value = value_c; - } - - PyObject *tuple = Py_BuildValue("(ss)", keyword.c_str(), - value.c_str()); - PyList_Append(token_list, tuple); - Py_DECREF(tuple); - - xtoken = xtoken->NextSiblingElement("token"); - } - - PyObject *arg_list = PyList_New(0); - TiXmlElement *xarg = xfparams->FirstChildElement("arg"); - while (xarg != nullptr) { - string value; - const char *value_c = xarg->Attribute("value"); - if (value_c != nullptr) { - value = value_c; - } - - PyObject *str = Py_BuildValue("s", value.c_str()); - PyList_Append(arg_list, str); - Py_DECREF(str); - - xarg = xarg->NextSiblingElement("arg"); - } - - PyObject *result = PyObject_CallMethod - (_runner, (char *)"setP3DFilename", (char *)"sNNiiis", p3d_filename.c_str(), - token_list, arg_list, inst->get_instance_id(), _interactive_console, p3d_offset, - p3d_url.c_str()); - - if (result == nullptr) { - PyErr_Print(); - if (_interactive_console) { - run_interactive_console(); - } - exit(1); - } - Py_XDECREF(result); -} - -/** - * Sets the window parameters for the indicated instance. - */ -void P3DPythonRun:: -setup_window(int id, TiXmlElement *xwparams) { - Instances::iterator ii = _instances.find(id); - if (ii == _instances.end()) { - nout << "Can't setup window for " << id << ": not started.\n"; - return; - } - - P3DCInstance *inst = (*ii).second; - setup_window(inst, xwparams); -} - -/** - * Sets the window parameters for the indicated instance. - */ -void P3DPythonRun:: -setup_window(P3DCInstance *inst, TiXmlElement *xwparams) { - string window_type; - const char *window_type_c = xwparams->Attribute("window_type"); - if (window_type_c != nullptr) { - window_type = window_type_c; - } - - int win_x, win_y, win_width, win_height; - - xwparams->Attribute("win_x", &win_x); - xwparams->Attribute("win_y", &win_y); - xwparams->Attribute("win_width", &win_width); - xwparams->Attribute("win_height", &win_height); - - PT(WindowHandle) parent_window_handle; - -#ifdef _WIN32 - int hwnd; - if (xwparams->Attribute("parent_hwnd", &hwnd)) { - parent_window_handle = NativeWindowHandle::make_win((HWND)hwnd); - } - -#elif __APPLE__ - // On Mac, we don't parent windows directly to the browser; instead, we have - // to go through this subprocess-window nonsense. - - const char *subprocess_window = xwparams->Attribute("subprocess_window"); - if (subprocess_window != nullptr) { - Filename filename = Filename::from_os_specific(subprocess_window); - parent_window_handle = NativeWindowHandle::make_subprocess(filename); - } - -#elif defined(HAVE_X11) - // Use stringstream to decode the "long" attribute. - const char *parent_cstr = xwparams->Attribute("parent_xwindow"); - if (parent_cstr != nullptr) { - long window; - std::istringstream strm(parent_cstr); - strm >> window; - parent_window_handle = NativeWindowHandle::make_x11((X11_Window)window); - } -#endif - - PyObject *py_handle = Py_None; - if (parent_window_handle != nullptr) { - - // We have a valid parent WindowHandle, but replace it with a - // P3DWindowHandle so we can get the callbacks. - parent_window_handle = new P3DWindowHandle(this, inst, *parent_window_handle); - inst->_parent_window_handle = parent_window_handle; - - // Also pass this P3DWindowHandle object down into Panda, via the - // setupWindow() call. For this, we need to create a Python wrapper - // objcet. - parent_window_handle->ref(); - py_handle = DTool_CreatePyInstanceTyped(parent_window_handle.p(), true); - } - Py_INCREF(py_handle); - - // TODO: direct this into the particular instance. This will require a - // specialized ShowBase replacement. - PyObject *result = PyObject_CallMethod - (_runner, (char *)"setupWindow", (char *)"siiiiN", window_type.c_str(), - win_x, win_y, win_width, win_height, py_handle); - - if (result == nullptr) { - PyErr_Print(); - if (_interactive_console) { - run_interactive_console(); - } - exit(1); - } - Py_XDECREF(result); -} - -/** - * This is used to deliver a windows keyboard message to the Panda process - * from the parent process, a necessary hack on Vista. - */ -void P3DPythonRun:: -send_windows_message(int id, unsigned int msg, int wparam, int lparam) { - Instances::iterator ii = _instances.find(id); - if (ii == _instances.end()) { - return; - } - - P3DCInstance *inst = (*ii).second; - if (inst->_parent_window_handle != nullptr) { - inst->_parent_window_handle->send_windows_message(msg, wparam, lparam); - } -} - -/** - * Stops all currently-running instances. - */ -void P3DPythonRun:: -terminate_session() { - Instances::iterator ii; - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - P3DCInstance *inst = (*ii).second; - delete inst; - } - _instances.clear(); - - if (!_session_terminated) { - if (_taskMgr != nullptr) { - PyObject *result = PyObject_CallMethod(_taskMgr, (char *)"stop", (char *)""); - if (result == nullptr) { - PyErr_Print(); - } else { - Py_DECREF(result); - } - } - - _session_terminated = true; - } -} - -/** - * Converts the indicated PyObject to the appropriate XML representation of a - * P3D_value type, and returns a freshly-allocated TiXmlElement. - */ -TiXmlElement *P3DPythonRun:: -pyobj_to_xml(PyObject *value) { - TiXmlElement *xvalue = new TiXmlElement("value"); - if (value == Py_None) { - // None. - xvalue->SetAttribute("type", "none"); - - } else if (PyBool_Check(value)) { - // A bool value. - xvalue->SetAttribute("type", "bool"); - xvalue->SetAttribute("value", PyObject_IsTrue(value)); - -#if PY_MAJOR_VERSION < 3 - } else if (PyInt_Check(value)) { - // A plain integer value. - xvalue->SetAttribute("type", "int"); - xvalue->SetAttribute("value", PyInt_AsLong(value)); -#endif - - } else if (PyLong_Check(value)) { - // A long integer value. This gets converted either as an integer or as a - // floating-point type, whichever fits. - long lvalue = PyLong_AsLong(value); - if (PyErr_Occurred()) { - // It won't fit as an integer; make it a double. - PyErr_Clear(); - xvalue->SetAttribute("type", "float"); - xvalue->SetDoubleAttribute("value", PyLong_AsDouble(value)); - } else { - // It fits as an integer. - xvalue->SetAttribute("type", "int"); - xvalue->SetAttribute("value", lvalue); - } - - } else if (PyFloat_Check(value)) { - // A floating-point value. - xvalue->SetAttribute("type", "float"); - xvalue->SetDoubleAttribute("value", PyFloat_AsDouble(value)); - - - } else if (PyUnicode_Check(value)) { - // A unicode value. Convert to utf-8 for the XML encoding. - xvalue->SetAttribute("type", "string"); - -#if PY_MAJOR_VERSION >= 3 - // In Python 3, there are only unicode strings, and there is a handy - // function for getting the UTF-8 encoded version. - Py_ssize_t length = 0; - char *buffer = PyUnicode_AsUTF8AndSize(value, &length); - if (buffer != nullptr) { - string str(buffer, length); - xvalue->SetAttribute("value", str); - } -#else - PyObject *as_str = PyUnicode_AsUTF8String(value); - if (as_str != nullptr) { - char *buffer; - Py_ssize_t length; - if (PyString_AsStringAndSize(as_str, &buffer, &length) != -1) { - string str(buffer, length); - xvalue->SetAttribute("value", str); - } - Py_DECREF(as_str); - } - - } else if (PyString_Check(value)) { - // A string value. Insist that it is utf-8 encoded, by decoding it first - // using the standard encoding, then re-encoding it. - xvalue->SetAttribute("type", "string"); - - PyObject *ustr = PyUnicode_FromEncodedObject(value, nullptr, nullptr); - if (ustr == nullptr) { - PyErr_Print(); - return xvalue; - } else { - PyObject *as_str = PyUnicode_AsUTF8String(ustr); - if (as_str != nullptr) { - char *buffer; - Py_ssize_t length; - if (PyString_AsStringAndSize(as_str, &buffer, &length) != -1) { - string str(buffer, length); - xvalue->SetAttribute("value", str); - } - Py_DECREF(as_str); - } - Py_DECREF(ustr); - } -#endif // PY_MAJOR_VERSION - - } else if (PyTuple_Check(value)) { - // An immutable sequence. Pass it as a concrete. - xvalue->SetAttribute("type", "concrete_sequence"); - - Py_ssize_t length = PySequence_Length(value); - for (Py_ssize_t i = 0; i < length; ++i) { - PyObject *item = PySequence_GetItem(value, i); - if (item != nullptr) { - xvalue->LinkEndChild(pyobj_to_xml(item)); - Py_DECREF(item); - } - } - - } else if (PyObject_IsInstance(value, _concrete_struct_class)) { - // This is a ConcreteStruct. - xvalue->SetAttribute("type", "concrete_struct"); - - PyObject *items = PyObject_CallMethod(value, (char *)"getConcreteProperties", (char *)""); - if (items == nullptr) { - PyErr_Print(); - return xvalue; - } - - Py_ssize_t length = PySequence_Length(items); - for (Py_ssize_t i = 0; i < length; ++i) { - PyObject *item = PySequence_GetItem(items, i); - if (item != nullptr) { - PyObject *a = PySequence_GetItem(item, 0); - if (a != nullptr) { - PyObject *b = PySequence_GetItem(item, 1); - if (b != nullptr) { - TiXmlElement *xitem = pyobj_to_xml(b); - Py_DECREF(b); - - PyObject *as_str; - if (PyUnicode_Check(a)) { - // The key is a unicode value. -#if PY_MAJOR_VERSION >= 3 - as_str = a; -#else - as_str = PyUnicode_AsUTF8String(a); -#endif - } else { - // The key is a string value or something else. Make it a - // string. - as_str = PyObject_Str(a); - } - char *buffer; - Py_ssize_t length; -#if PY_MAJOR_VERSION >= 3 - buffer = PyUnicode_AsUTF8AndSize(as_str, &length); - if (buffer != nullptr) { -#else - if (PyString_AsStringAndSize(as_str, &buffer, &length) != -1) { -#endif - string str(buffer, length); - xitem->SetAttribute("key", str); - } - Py_DECREF(as_str); - - xvalue->LinkEndChild(xitem); - } - Py_DECREF(a); - } - Py_DECREF(item); - } - } - - // We've already avoided errors in the above code; clear the error flag. - PyErr_Clear(); - - Py_DECREF(items); - - } else if (PyObject_IsInstance(value, _undefined_object_class)) { - // This is an UndefinedObject. - xvalue->SetAttribute("type", "undefined"); - - } else if (PyObject_IsInstance(value, _browser_object_class)) { - // This is a BrowserObject, a reference to an object that actually exists - // in the host namespace. So, pass up the appropriate object ID. - PyObject *objectId = PyObject_GetAttrString(value, (char *)"_BrowserObject__objectId"); - if (objectId != nullptr) { - int object_id = PyInt_AsLong(objectId); - xvalue->SetAttribute("type", "browser"); - xvalue->SetAttribute("object_id", object_id); - Py_DECREF(objectId); - } - - } else { - // Some other kind of object. Make it a generic Python object. This is - // more expensive for the caller to deal with--it requires a back-and- - // forth across the XML pipe--but it's much more general. - - int object_id = _next_sent_id; - ++_next_sent_id; - bool inserted = _sent_objects.insert(SentObjects::value_type(object_id, value)).second; - while (!inserted) { - // Hmm, we must have cycled around the entire int space? Either that, - // or there's a logic bug somewhere. Assume the former, and keep - // looking for an empty slot. - object_id = _next_sent_id; - ++_next_sent_id; - inserted = _sent_objects.insert(SentObjects::value_type(object_id, value)).second; - } - - // Now that it's stored in the map, increment its reference count. - Py_INCREF(value); - - xvalue->SetAttribute("type", "python"); - xvalue->SetAttribute("object_id", object_id); - } - - return xvalue; -} - -/** - * Converts the XML representation of a P3D_value type into the equivalent - * Python object and returns it. - */ -PyObject *P3DPythonRun:: -xml_to_pyobj(TiXmlElement *xvalue) { - const char *type = xvalue->Attribute("type"); - if (strcmp(type, "none") == 0) { - return Py_BuildValue(""); - - } else if (strcmp(type, "bool") == 0) { - int value; - if (xvalue->QueryIntAttribute("value", &value) == TIXML_SUCCESS) { - return PyBool_FromLong(value); - } - - } else if (strcmp(type, "int") == 0) { - int value; - if (xvalue->QueryIntAttribute("value", &value) == TIXML_SUCCESS) { -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(value); -#else - return PyInt_FromLong(value); -#endif - } - - } else if (strcmp(type, "float") == 0) { - double value; - if (xvalue->QueryDoubleAttribute("value", &value) == TIXML_SUCCESS) { - return PyFloat_FromDouble(value); - } - - } else if (strcmp(type, "string") == 0) { - // Using the string form here instead of the char * form, so we don't get - // tripped up on embedded null characters. - const string *value = xvalue->Attribute(string("value")); - if (value != nullptr) { - return PyUnicode_DecodeUTF8(value->data(), value->length(), nullptr); - } - - } else if (strcmp(type, "undefined") == 0) { - Py_INCREF(_undefined); - return _undefined; - - } else if (strcmp(type, "browser") == 0) { - int object_id; - if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) { - // Construct a new BrowserObject wrapper around this object. - return PyObject_CallFunction(_browser_object_class, (char *)"Oi", - _runner, object_id); - } - - } else if (strcmp(type, "concrete_sequence") == 0) { - // Receive a concrete sequence as a tuple. - PyObject *list = PyList_New(0); - - TiXmlElement *xitem = xvalue->FirstChildElement("value"); - while (xitem != nullptr) { - PyObject *item = xml_to_pyobj(xitem); - if (item != nullptr) { - PyList_Append(list, item); - Py_DECREF(item); - } - xitem = xitem->NextSiblingElement("value"); - } - - PyObject *result = PyList_AsTuple(list); - Py_DECREF(list); - return result; - - } else if (strcmp(type, "concrete_struct") == 0) { - // Receive a concrete struct as a new ConcreteStruct instance. - PyObject *obj = PyObject_CallFunction(_concrete_struct_class, (char *)""); - - if (obj != nullptr) { - TiXmlElement *xitem = xvalue->FirstChildElement("value"); - while (xitem != nullptr) { - const char *key = xitem->Attribute("key"); - if (key != nullptr) { - PyObject *item = xml_to_pyobj(xitem); - if (item != nullptr) { - PyObject_SetAttrString(obj, (char *)key, item); - Py_DECREF(item); - } - } - xitem = xitem->NextSiblingElement("value"); - } - return obj; - } - - } else if (strcmp(type, "python") == 0) { - int object_id; - if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) { - SentObjects::iterator si = _sent_objects.find(object_id); - PyObject *result; - if (si == _sent_objects.end()) { - // Hmm, the parent process gave us a bogus object ID. - result = _undefined; - } else { - result = (*si).second; - } - Py_INCREF(result); - return result; - } - } - - // Something went wrong in decoding. - PyObject *result = _undefined; - Py_INCREF(result); - return result; -} - -/** - * The main function for the read thread. - */ -void P3DPythonRun:: -rt_thread_run() { - while (_read_thread_continue) { - TiXmlDocument *doc = read_xml(_pipe_read, nout); - if (doc == nullptr) { - // Some error on reading. Abort. - _program_continue = false; - return; - } - - // Successfully read an XML document. - - // Check for one special case: the "exit" command means we shut down the - // read thread along with everything else. - TiXmlElement *xcommand = doc->FirstChildElement("command"); - if (xcommand != nullptr) { - const char *cmd = xcommand->Attribute("cmd"); - if (cmd != nullptr) { - if (strcmp(cmd, "exit") == 0) { - _read_thread_continue = false; - } - } - } - - // Feed the command up to the parent. - ACQUIRE_LOCK(_commands_lock); - _commands.push_back(doc); - RELEASE_LOCK(_commands_lock); - } -} - -/** - * - */ -P3DPythonRun::P3DWindowHandle:: -P3DWindowHandle(P3DPythonRun *p3dpython, P3DCInstance *inst, - const WindowHandle ©) : - WindowHandle(copy), - _p3dpython(p3dpython), - _inst(inst), - _child_count(0) -{ -} - -/** - * Called on a parent handle to indicate a child window's intention to attach - * itself. - */ -void P3DPythonRun::P3DWindowHandle:: -attach_child(WindowHandle *child) { - WindowHandle::attach_child(child); - ++_child_count; - - if (_child_count == 1) { - // When the first child window is attached, we tell the plugin. - _p3dpython->set_window_open(_inst, true); - } -} - -/** - * Called on a parent handle to indicate a child window's intention to detach - * itself. - */ -void P3DPythonRun::P3DWindowHandle:: -detach_child(WindowHandle *child) { - WindowHandle::detach_child(child); - --_child_count; - - if (_child_count == 0) { - // When the last child window is detached, we tell the plugin. - _p3dpython->set_window_open(_inst, false); - } -} - -/** - * Called on a parent handle to indicate a child window's wish to receive - * keyboard button events. - */ -void P3DPythonRun::P3DWindowHandle:: -request_keyboard_focus(WindowHandle *child) { - WindowHandle::request_keyboard_focus(child); - _p3dpython->request_keyboard_focus(_inst); -} diff --git a/direct/src/plugin/p3dPythonRun.h b/direct/src/plugin/p3dPythonRun.h deleted file mode 100644 index ee3fbc3d00..0000000000 --- a/direct/src/plugin/p3dPythonRun.h +++ /dev/null @@ -1,207 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dPythonRun.h - * @author drose - * @date 2009-06-05 - */ - -#ifndef P3DPYTHONRUN_H -#define P3DPYTHONRUN_H - -#include "pandabase.h" - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#endif - -#include "run_p3dpython.h" -#include "p3d_lock.h" -#include "handleStream.h" -#include "p3dCInstance.h" -#include "pandaFileStreamBuf.h" -#include "pmap.h" -#include "pdeque.h" -#include "pmutex.h" -#include "get_tinyxml.h" -#include "filename.h" - -#include - -// Python 2.5 adds Py_ssize_t; earlier versions don't have it. -#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) -typedef int Py_ssize_t; -#define PY_SSIZE_T_MAX INT_MAX -#define PY_SSIZE_T_MIN INT_MIN -#endif - -/** - * This class is used to run, and communicate with, embedded Python in a sub- - * process. It is compiled and launched as a separate executable from the - * p3d_plugin dll, because that's the only way Windows can launch a sub- - * process, and also because it makes it possible to compile-time link with - * Panda and Python, instead of having to go through the clumsy dynamic- - * loading interface. - * - * Communication is via XML files exchanged via anonymous pipes from the - * parent process. This isn't terribly eficient, of course, but it's easy; - * and it's a fairly low-bandwidth channel so efficiency is not paramount. - * - * This executable is not designed to stand alone; it is designed to be - * invoked only by p3d_plugin. - */ -class P3DPythonRun { -public: - P3DPythonRun(const char *program_name, const char *archive_file, - FHandle input_handle, FHandle output_handle, - const char *log_pathname, bool interactive_console); - ~P3DPythonRun(); - - int run_python(); - - void set_window_open(P3DCInstance *inst, bool is_open); - void request_keyboard_focus(P3DCInstance *inst); - -private: - void run_interactive_console(); - void handle_command(TiXmlDocument *doc); - void handle_pyobj_command(TiXmlElement *xcommand, bool needs_response, - int want_response_id); - void handle_script_response_command(TiXmlElement *xcommand); - - void check_comm(); - static PyObject *st_check_comm(PyObject *, PyObject *args); - TiXmlDocument *wait_script_response(int response_id); - - PyObject *py_request_func(PyObject *args); - static PyObject *st_request_func(PyObject *, PyObject *args); - - void spawn_read_thread(); - void join_read_thread(); - - void start_instance(P3DCInstance *inst, TiXmlElement *xinstance); - void terminate_instance(int id); - void set_instance_info(P3DCInstance *inst, TiXmlElement *xinstance); - void add_package_info(P3DCInstance *inst, TiXmlElement *xpackage); - void set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams); - void setup_window(int id, TiXmlElement *xwparams); - void setup_window(P3DCInstance *inst, TiXmlElement *xwparams); - - void send_windows_message(int id, unsigned int msg, int wparam, int lparam); - - void terminate_session(); - -private: - TiXmlElement *pyobj_to_xml(PyObject *value); - PyObject *xml_to_pyobj(TiXmlElement *xvalue); - -private: - // This subclass of WindowHandle is associated with the parent window we are - // given by the parent process. We use it to add hooks for communicating - // with the parent window, for instance to ask for the parent window to - // manage keyboard focus when necessary. - class P3DWindowHandle : public WindowHandle { - public: - P3DWindowHandle(P3DPythonRun *p3dpython, P3DCInstance *inst, - const WindowHandle ©); - - public: - virtual void attach_child(WindowHandle *child); - virtual void detach_child(WindowHandle *child); - virtual void request_keyboard_focus(WindowHandle *child); - - private: - P3DPythonRun *_p3dpython; - P3DCInstance *_inst; - int _child_count; - - public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - WindowHandle::init_type(); - register_type(_type_handle, "P3DWindowHandle", - WindowHandle::get_class_type()); - } - virtual TypeHandle get_type() const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - - private: - static TypeHandle _type_handle; - }; - -private: - // This method runs only within the read thread. - THREAD_CALLBACK_DECLARATION(P3DPythonRun, rt_thread_run); - void rt_thread_run(); - -private: - typedef pmap Instances; - Instances _instances; - - int _session_id; - - Filename _archive_file; - int _py_argc; -#if PY_MAJOR_VERSION >= 3 - wchar_t *_py_argv[2]; - std::wstring _program_name; -#else - char *_py_argv[2]; - std::string _program_name; -#endif - bool _interactive_console; - - PyObject *_runner; - PyObject *_undefined_object_class; - PyObject *_undefined; - PyObject *_concrete_struct_class; - PyObject *_browser_object_class; - PyObject *_taskMgr; - - // This map keeps track of the PyObject pointers we have delivered to the - // parent process. We have to hold the reference count on each of these - // until the parent process tells us it's safe to release them. - typedef pmap SentObjects; - SentObjects _sent_objects; - int _next_sent_id; - - typedef pdeque Commands; - - // This is a special queue of responses extracted from the _commands queue, - // below. It's protected by the Panda mutex. - Commands _responses; - Mutex _responses_lock; - - // The remaining members are manipulated by the read thread. - Commands _commands; - - // This has to be an actual OS LOCK instead of Panda's Mutex, because we - // have to use a true thread here, not one of Panda's simple threads. - LOCK _commands_lock; - - HandleStream _pipe_read; - HandleStream _pipe_write; - pofstream _error_log; - - bool _read_thread_continue; - bool _program_continue; - bool _session_terminated; - THREAD _read_thread; - -public: - static P3DPythonRun *_global_ptr; -}; - -#include "p3dPythonRun.I" - -#endif diff --git a/direct/src/plugin/p3dReferenceCount.I b/direct/src/plugin/p3dReferenceCount.I deleted file mode 100644 index b4cac7c05f..0000000000 --- a/direct/src/plugin/p3dReferenceCount.I +++ /dev/null @@ -1,68 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dReferenceCount.I - * @author drose - * @date 2009-07-09 - */ - -/** - * - */ -inline P3DReferenceCount:: -P3DReferenceCount() { - _ref_count = 0; -} - -/** - * - */ -inline P3DReferenceCount:: -~P3DReferenceCount() { - assert(_ref_count == 0); -} - -/** - * Explicitly increments the reference count. - */ -inline void P3DReferenceCount:: -ref() const { - ++((P3DReferenceCount *)this)->_ref_count; -} - -/** - * Explicitly decrements the reference count. Usually, you should call - * p3d_unref_delete() instead. - * - * The return value is true if the new reference count is nonzero, false if it - * is zero. - */ -inline bool P3DReferenceCount:: -unref() const { - return --(((P3DReferenceCount *)this)->_ref_count) != 0; -} - -/** - * Returns the current reference count. - */ -inline int P3DReferenceCount:: -get_ref_count() const { - return _ref_count; -} - -/** - * This global helper function will unref the given P3DReferenceCount object, - * and if the reference count reaches zero, automatically delete it. - */ -template -inline void -p3d_unref_delete(RefCountType *ptr) { - if (!ptr->unref()) { - delete ptr; - } -} diff --git a/direct/src/plugin/p3dReferenceCount.cxx b/direct/src/plugin/p3dReferenceCount.cxx deleted file mode 100644 index 9747476e73..0000000000 --- a/direct/src/plugin/p3dReferenceCount.cxx +++ /dev/null @@ -1,14 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dReferenceCount.cxx - * @author drose - * @date 2009-07-09 - */ - -#include "p3dReferenceCount.h" diff --git a/direct/src/plugin/p3dReferenceCount.h b/direct/src/plugin/p3dReferenceCount.h deleted file mode 100644 index b11eb82931..0000000000 --- a/direct/src/plugin/p3dReferenceCount.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dReferenceCount.h - * @author drose - * @date 2009-07-09 - */ - -#ifndef P3DREFERENCECOUNT_H -#define P3DREFERENCECOUNT_H - -#include "p3d_plugin_common.h" - -/** - * A base class for reference-counted objects in this module. We follow the - * Panda convention, rather than the Python convention: the reference count of - * a new object is initially 0. - */ -class P3DReferenceCount { -public: - inline P3DReferenceCount(); - inline ~P3DReferenceCount(); - - inline void ref() const; - inline bool unref() const; - inline int get_ref_count() const; - -private: - int _ref_count; -}; - -template -inline void p3d_unref_delete(RefCountType *ptr); - -#include "p3dReferenceCount.I" - -#endif diff --git a/direct/src/plugin/p3dSession.I b/direct/src/plugin/p3dSession.I deleted file mode 100644 index 010a81c172..0000000000 --- a/direct/src/plugin/p3dSession.I +++ /dev/null @@ -1,49 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dSession.I - * @author drose - * @date 2009-06-03 - */ - -/** - * Returns a string that uniquely identifies this session. See - * P3dInstance::get_session_key(). - */ -inline const std::string &P3DSession:: -get_session_key() const { - return _session_key; -} - -/** - * Returns the log filename for this particular session, if the session was - * started and if it has a log file. Returns empty string if the session - * never started or if it lacks a log file. - */ -inline const std::string &P3DSession:: -get_log_pathname() const { - return _log_pathname; -} - -/** - * Returns true if the instances of this session are allowed to be scripted by - * its embedding web page, false otherwise. - */ -inline bool P3DSession:: -get_matches_script_origin() const { - return _matches_script_origin; -} - -/** - * Returns the number of instances currently running within the session. When - * this is zero, the session may be safely deleted. - */ -inline int P3DSession:: -get_num_instances() const { - return _instances.size(); -} diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx deleted file mode 100644 index 4a769ec9e1..0000000000 --- a/direct/src/plugin/p3dSession.cxx +++ /dev/null @@ -1,1791 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dSession.cxx - * @author drose - * @date 2009-06-03 - */ - -#include "p3dSession.h" -#include "p3dInstance.h" -#include "p3dInstanceManager.h" -#include "p3d_plugin_config.h" -#include "p3dUndefinedObject.h" -#include "p3dNoneObject.h" -#include "p3dBoolObject.h" -#include "p3dIntObject.h" -#include "p3dFloatObject.h" -#include "p3dPythonObject.h" -#include "p3dConcreteSequence.h" -#include "p3dConcreteStruct.h" -#include "binaryXml.h" -#include "mkdir_complete.h" -#include "wstring_encode.h" -#include "run_p3dpython.h" - -#include -#include - -#ifndef _WIN32 -#include -#include -#include -#include -#include -#endif - -#ifdef __APPLE__ -#include -#endif - -using std::string; -using std::wstring; - -/** - * Creates a new session, corresponding to a new subprocess with its own copy - * of Python. The initial parameters for the session are taken from the - * indicated instance object (but the instance itself is not automatically - * started within the session). - */ -P3DSession:: -P3DSession(P3DInstance *inst) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - _session_id = inst_mgr->get_unique_id(); - _session_key = inst->get_session_key(); - _matches_script_origin = inst->get_matches_script_origin(); - _keep_user_env = false; - _failed = false; - -#ifdef _WIN32 - _p3dpython_handle = INVALID_HANDLE_VALUE; -#else - _p3dpython_pid = -1; -#endif - _p3dpython_one_process = false; - _p3dpython_started = false; - _p3dpython_running = false; - - _started_read_thread = false; - _read_thread_continue = false; - - INIT_LOCK(_instances_lock); - INIT_THREAD(_read_thread); -} - - -/** - * - */ -P3DSession:: -~P3DSession() { - assert(!_p3dpython_running); - DESTROY_LOCK(_instances_lock); -} - -/** - * Terminates the session by shutting down Python and stopping the subprocess. - */ -void P3DSession:: -shutdown() { - set_failed(); - - int exit_code = 0; - - if (_p3dpython_started) { - // Tell the process we're going away. - TiXmlDocument doc; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "exit"); - doc.LinkEndChild(xcommand); - write_xml(_pipe_write, &doc, nout); - - // Also close the pipe, to help underscore the point. - _pipe_write.close(); - - // Closing _pipe_read before the thread has stopped can result in a hang. - // Don't need to close it yet. _pipe_read.close(); - - static const int max_wait_ms = 2000; - - if (_p3dpython_one_process) { - // Since it's running in a thread, we can't reliably force-kill it. So, - // just wait. - nout << "Waiting for Python thread to exit\n"; - JOIN_THREAD(_p3dpython_thread); - nout << "Done waiting.\n"; - _p3dpython_one_process = false; - - } else { - // Python's running in a sub-process, the preferred way. In this case, - // we can wait a brief amount of time before it closes itself; but if it - // doesn't, we can safely force-kill it. - -#ifdef _WIN32 - // Wait for a certain amount of time for the process to stop by itself. - while (WaitForSingleObject(_p3dpython_handle, max_wait_ms) == WAIT_TIMEOUT) { - // It didn't shut down cleanly, so kill it the hard way. - nout << "Force-killing python process.\n"; - TerminateProcess(_p3dpython_handle, 2); - } - - DWORD dw_exit_code = 0; - if (!GetExitCodeProcess(_p3dpython_handle, &dw_exit_code)) { - nout << "GetExitCodeProcess failed, error: " << GetLastError() << "\n"; - } else { - exit_code = (int)dw_exit_code; - } - - CloseHandle(_p3dpython_handle); - _p3dpython_handle = INVALID_HANDLE_VALUE; - -#else // _WIN32 - // Wait for a certain amount of time for the process to stop by itself. - struct timeval start; - gettimeofday(&start, nullptr); - int start_ms = start.tv_sec * 1000 + start.tv_usec / 1000; - - int status; - pid_t result = waitpid(_p3dpython_pid, &status, WNOHANG); - while (result != _p3dpython_pid) { - if (result == -1) { - perror("waitpid"); - break; - } - - struct timeval now; - gettimeofday(&now, nullptr); - int now_ms = now.tv_sec * 1000 + now.tv_usec / 1000; - int elapsed = now_ms - start_ms; - - if (elapsed > max_wait_ms) { - // Tired of waiting. Kill the process. - nout << "Force-killing python process, pid " << _p3dpython_pid - << "\n"; - kill(_p3dpython_pid, SIGKILL); - start_ms = now_ms; - } - - // Yield the timeslice and wait some more. - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1; - select(0, nullptr, nullptr, nullptr, &tv); - result = waitpid(_p3dpython_pid, &status, WNOHANG); - } - _p3dpython_pid = -1; - - nout << "Python process has successfully stopped.\n"; - if (WIFEXITED(status)) { - exit_code = WEXITSTATUS(status); - nout << " exited normally, status = " << exit_code << "\n"; - - } else if (WIFSIGNALED(status)) { - nout << " signalled by " << WTERMSIG(status) << ", core = " - << WCOREDUMP(status) << "\n"; - - // This seems to be a popular shell convention. - exit_code = 128 + WTERMSIG(status); - - } else if (WIFSTOPPED(status)) { - nout << " stopped by " << WSTOPSIG(status) << "\n"; - } - -#endif // _WIN32 - } - - _p3dpython_running = false; - _p3dpython_started = false; - } - - // If there are any leftover commands in the queue (presumably implying we - // have never started the python process), then delete them now, unsent. - Commands::iterator ci; - for (ci = _commands.begin(); ci != _commands.end(); ++ci) { - delete (*ci); - } - _commands.clear(); - - join_read_thread(); - - // Close the pipe now. - _pipe_read.close(); - - // If we had an exit status, pass it on to the runtime process. - if (exit_code != 0) { - _exit(exit_code); - } -} - -/** - * Adds the indicated instance to the session, and starts it running. It is - * an error if the instance has been started anywhere else. - * - * The instance must have the same session_key as the one that was passed to - * the P3DSession constructor. - */ -void P3DSession:: -start_instance(P3DInstance *inst) { - assert(inst->_session == nullptr); - assert(inst->get_session_key() == _session_key); - if (_failed) { - inst->set_failed(); - return; - } - - inst->ref(); - ACQUIRE_LOCK(_instances_lock); - inst->_session = this; - inst->_instance_started = true; - bool inserted = _instances.insert(Instances::value_type(inst->get_instance_id(), inst)).second; - RELEASE_LOCK(_instances_lock); - assert(inserted); - - TiXmlDocument *doc = new TiXmlDocument; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "start_instance"); - TiXmlElement *xinstance = inst->make_xml(); - - doc->LinkEndChild(xcommand); - xcommand->LinkEndChild(xinstance); - - send_command(doc); - inst->send_browser_script_object(); - - // We shouldn't have gotten here unless the instance is fully downloaded and - // ready to start. - assert(inst->get_packages_ready()); - - start_p3dpython(inst); -} - -/** - * Removes the indicated instance from the session, and stops it. It is an - * error if the instance is not already running on this session. - */ -void P3DSession:: -terminate_instance(P3DInstance *inst) { - TiXmlDocument *doc = new TiXmlDocument; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "terminate_instance"); - xcommand->SetAttribute("instance_id", inst->get_instance_id()); - - doc->LinkEndChild(xcommand); - - send_command(doc); - - ACQUIRE_LOCK(_instances_lock); - if (inst->_session == this) { - nout << "Assigning " << inst << "->log_pathname = " << _log_pathname << "\n"; - inst->_log_pathname = _log_pathname; - inst->_session = nullptr; - _instances.erase(inst->get_instance_id()); - } - RELEASE_LOCK(_instances_lock); - p3d_unref_delete(inst); -} - -/** - * Sends the indicated command to the running Python process. If the process - * has not yet been started, queues it up until it is ready. - * - * The command must be a newly-allocated TiXmlDocument; it will be deleted - * after it has been delivered to the process. - */ -void P3DSession:: -send_command(TiXmlDocument *command) { - if (_p3dpython_started) { - // Python is running. Send the command. - write_xml(_pipe_write, command, nout); - delete command; - } else { - // Python not yet running. Queue up the command instead. - _commands.push_back(command); - } -} - -/** - * Sends the indicated command to the running Python process, and waits for a - * response. Returns the newly-allocated response on success, or NULL on - * failure. - * - * The command must be a newly-allocated TiXmlDocument; it will be deleted - * after it has been delivered to the process. - * - * This will fail if the python process is not running or if it suddenly - * stops. - */ -TiXmlDocument *P3DSession:: -command_and_response(TiXmlDocument *command) { - if (!_p3dpython_started) { - return nullptr; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - int response_id = inst_mgr->get_unique_id(); - - // Add the "want_response_id" attribute to the toplevel command, so the sub- - // process knows we'll be waiting for its response. - TiXmlElement *xcommand = command->FirstChildElement("command"); - assert(xcommand != nullptr); - xcommand->SetAttribute("want_response_id", response_id); - - write_xml(_pipe_write, command, nout); - delete command; - - // Now block, waiting for the response to be delivered. - _response_ready.acquire(); - Responses::iterator ri = _responses.find(response_id); - while (ri == _responses.end()) { - if (!_p3dpython_running) { - // Hmm, looks like Python has gone away. - _response_ready.release(); - return nullptr; - } - - // Make sure we bake requests while we are waiting, to process recursive - // script requests. (The child process might have to wait for us to - // process some of these before it can fulfill the command we're actually - // waiting for.) - - // Release the mutex while we do this, so we can safely call back in - // recursively. - _response_ready.release(); - Instances::iterator ii; - // TODO: should we acquire _instances_lock? Deadlock concerns? - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - P3DInstance *inst = (*ii).second; - inst->bake_requests(); - } - _response_ready.acquire(); - - ri = _responses.find(response_id); - if (ri != _responses.end()) { - // We got the response we were waiting for while we had the mutex - // unlocked. - break; - } - -#ifdef _WIN32 - // Make sure we process the Windows event loop while we're waiting, or - // everything that depends on Windows messages within the subprocess will - // starve, and we could end up with deadlock. - - // A single call to PeekMessage() appears to be sufficient. This will - // scan the message queue and deliver messages to the appropriate threads, - // so that our subprocess can find them. If we don't do this, the - // messages that come into this parent window will never get delivered to - // the subprocess, even though somehow the subprocess will know they're - // coming and will block waiting for them. - - MSG msg; - PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE | PM_NOYIELD); - - // We wait with a timeout, so we can go back and spin the event loop some - // more. On Windows, the timeout needs to be small, so we continue to - // process windows messages in a timely fashion. - _response_ready.wait(0.01); - -#else - // On other platforms, we shouldn't need a timeout at all--we could just - // block indefinitely--but we go ahead and put one in anyway, just in case - // a notification slips past somehow, and also so we can see evidence that - // we're actively waiting. This timeout doesn't need to be nearly so - // small, since it's only a "just in case" sort of thing. - _response_ready.wait(0.5); -#endif // _WIN32 - - ri = _responses.find(response_id); - } - // When we exit the loop, we've found the desired response. - TiXmlDocument *response = (*ri).second; - _responses.erase(ri); - - _response_ready.release(); - - return response; -} - -/** - * Converts the XML representation of the particular object value into a - * corresponding P3D_object. Returns the object, a new reference. - */ -P3D_object *P3DSession:: -xml_to_p3dobj(const TiXmlElement *xvalue) { - const char *type = xvalue->Attribute("type"); - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - if (strcmp(type, "undefined") == 0) { - return inst_mgr->new_undefined_object(); - - } else if (strcmp(type, "none") == 0) { - return inst_mgr->new_none_object(); - - } else if (strcmp(type, "bool") == 0) { - int value; - if (xvalue->QueryIntAttribute("value", &value) == TIXML_SUCCESS) { - return inst_mgr->new_bool_object(value != 0); - } - - } else if (strcmp(type, "int") == 0) { - int value; - if (xvalue->QueryIntAttribute("value", &value) == TIXML_SUCCESS) { - return new P3DIntObject(value); - } - - } else if (strcmp(type, "float") == 0) { - double value; - if (xvalue->QueryDoubleAttribute("value", &value) == TIXML_SUCCESS) { - return new P3DFloatObject(value); - } - - } else if (strcmp(type, "string") == 0) { - // Using the string form here instead of the char * form, so we don't get - // tripped up on embedded null characters. - const string *value = xvalue->Attribute(string("value")); - if (value != nullptr) { - return new P3DStringObject(*value); - } - - } else if (strcmp(type, "concrete_sequence") == 0) { - P3DConcreteSequence *obj = new P3DConcreteSequence; - const TiXmlElement *xitem = xvalue->FirstChildElement("value"); - while (xitem != nullptr) { - P3D_object *item = xml_to_p3dobj(xitem); - if (item != nullptr) { - obj->append(item); - P3D_OBJECT_DECREF(item); - } - xitem = xitem->NextSiblingElement("value"); - } - return obj; - - } else if (strcmp(type, "concrete_struct") == 0) { - P3DConcreteStruct *obj = new P3DConcreteStruct; - const TiXmlElement *xitem = xvalue->FirstChildElement("value"); - while (xitem != nullptr) { - const char *key = xitem->Attribute("key"); - if (key != nullptr) { - P3D_object *item = xml_to_p3dobj(xitem); - if (item != nullptr) { - obj->set_property(key, item); - P3D_OBJECT_DECREF(item); - } - } - xitem = xitem->NextSiblingElement("value"); - } - return obj; - - } else if (strcmp(type, "browser") == 0) { - int object_id; - if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) { - SentObjects::iterator si = _sent_objects.find(object_id); - if (si == _sent_objects.end()) { - // Hmm, the child process gave us a bogus object ID. - return inst_mgr->new_undefined_object(); - } - - P3D_object *obj = (*si).second; - - P3D_OBJECT_INCREF(obj); - return obj; - } - - } else if (strcmp(type, "python") == 0) { - int object_id; - if (xvalue->QueryIntAttribute("object_id", &object_id) == TIXML_SUCCESS) { - return new P3DPythonObject(this, object_id); - } - } - - // Something went wrong in decoding. - return inst_mgr->new_undefined_object(); -} - -/** - * Allocates and returns a new XML structure corresponding to the indicated - * value. The supplied P3DObject's reference count is not decremented; the - * caller remains responsible for decrementing it later. - */ -TiXmlElement *P3DSession:: -p3dobj_to_xml(P3D_object *obj) { - TiXmlElement *xvalue = new TiXmlElement("value"); - - switch (P3D_OBJECT_GET_TYPE(obj)) { - case P3D_OT_undefined: - xvalue->SetAttribute("type", "undefined"); - break; - - case P3D_OT_none: - xvalue->SetAttribute("type", "none"); - break; - - case P3D_OT_bool: - xvalue->SetAttribute("type", "bool"); - xvalue->SetAttribute("value", (int)P3D_OBJECT_GET_BOOL(obj)); - break; - - case P3D_OT_int: - xvalue->SetAttribute("type", "int"); - xvalue->SetAttribute("value", P3D_OBJECT_GET_INT(obj)); - break; - - case P3D_OT_float: - xvalue->SetAttribute("type", "float"); - xvalue->SetDoubleAttribute("value", P3D_OBJECT_GET_FLOAT(obj)); - break; - - case P3D_OT_string: - { - xvalue->SetAttribute("type", "string"); - int size = P3D_OBJECT_GET_STRING(obj, nullptr, 0); - char *buffer = new char[size]; - P3D_OBJECT_GET_STRING(obj, buffer, size); - xvalue->SetAttribute("value", string(buffer, size)); - delete [] buffer; - } - break; - - case P3D_OT_object: - P3DObject *p3dobj = nullptr; - if (obj->_class == &P3DObject::_object_class) { - p3dobj = (P3DObject *)obj; - } - - if (p3dobj != nullptr && p3dobj->fill_xml(xvalue, this)) { - // This object has a specialized XML representation, valid for this - // particular session. It has already been filled into xvalue. - - } else { - // Otherwise, it must a host-provided object, or a Python object from - // another session; which means we should pass a reference down to this - // particular object, so the Python process knows to call back up to - // here to query it. - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - int object_id = inst_mgr->get_unique_id(); - bool inserted = _sent_objects.insert(SentObjects::value_type(object_id, obj)).second; - while (!inserted) { - // Hmm, we must have cycled around the entire int space? Either that, - // or there's a logic bug somewhere. Assume the former, and keep - // looking for an empty slot. - object_id = inst_mgr->get_unique_id(); - inserted = _sent_objects.insert(SentObjects::value_type(object_id, obj)).second; - } - - // Now that it's stored in the map, increment its reference count. - P3D_OBJECT_INCREF(obj); - - xvalue->SetAttribute("type", "browser"); - xvalue->SetAttribute("object_id", object_id); - } - break; - } - - return xvalue; -} - -/** - * This is called by the splash window to deliver a windows keyboard message - * to the Panda process. It will be called in a sub-thread, but that's OK, - * since write_xml() supports locking. - */ -void P3DSession:: -send_windows_message(P3DInstance *inst, unsigned int msg, int wparam, int lparam) { - if (_p3dpython_started) { - TiXmlDocument doc; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "windows_message"); - xcommand->SetAttribute("instance_id", inst->get_instance_id()); - xcommand->SetAttribute("msg", msg); - xcommand->SetAttribute("wparam", wparam); - xcommand->SetAttribute("lparam", lparam); - doc.LinkEndChild(xcommand); - write_xml(_pipe_write, &doc, nout); - } -} - -/** - * May be called in any thread to indicate that a new P3D_request is available - * in the indicated instance. - */ -void P3DSession:: -signal_request_ready(P3DInstance *inst) { - // Since a new request might require baking, we should wake up a blocked - // command_and_request() process, so the main thread can go back and bake - // the new request. - - // Technically, a response isn't really ready now, but we still need the - // main thread to wake up and look around for a bit. - _response_ready.acquire(); - _response_ready.notify(); - _response_ready.release(); -} - -/** - * If the session is still active, issues the command to the child process to - * release the indicated PyObject from its table. This is intended to be - * called strictly by the P3DPythonObject destructor. - */ -void P3DSession:: -drop_pyobj(int object_id) { - if (_p3dpython_started) { - TiXmlDocument doc; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "drop_pyobj"); - xcommand->SetAttribute("object_id", object_id); - doc.LinkEndChild(xcommand); - write_xml(_pipe_write, &doc, nout); - } -} - -/** - * Responds to a drop_p3dobj message from the child process indicating that a - * particular P3D_object is no longer being used by the child. This removes - * the corresponding P3D_object from our tables and decrements its reference - * count. - */ -void P3DSession:: -drop_p3dobj(int object_id) { - SentObjects::iterator si = _sent_objects.find(object_id); - if (si != _sent_objects.end()) { - P3D_object *obj = (*si).second; - P3D_OBJECT_DECREF(obj); - _sent_objects.erase(si); - } -} - -/** - * Starts Python running in a child process. - */ -void P3DSession:: -start_p3dpython(P3DInstance *inst) { - if (_p3dpython_started) { - // Already started. - return; - } - - if (inst->_panda3d_package == nullptr) { - nout << "Couldn't start Python: no panda3d dependency.\n"; - set_failed(); - return; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - _python_root_dir = inst->_panda3d_package->get_package_dir(); - replace_slashes(_python_root_dir); - - // If we're not to be preserving the user's current directory, then we'll - // need to change to the standard start directory. - _keep_user_env = false; - if (inst_mgr->get_trusted_environment() && - inst_mgr->get_console_environment() && - inst->_keep_user_env) { - _keep_user_env = true; - } - if (!_keep_user_env) { - _start_dir = inst_mgr->get_start_dir() + inst->get_start_dir_suffix(); - mkdir_complete(_start_dir, nout); - } - replace_slashes(_start_dir); - - // Also make sure the prc directory is present. - string prc_root = inst_mgr->get_root_dir() + "/prc"; - replace_slashes(prc_root); - mkdir_complete(prc_root, nout); - -#ifdef _WIN32 - char sep = ';'; -#else - char sep = ':'; -#endif // _WIN32 - - // Build up a search path that includes all of the required packages that - // have already been installed. We build this in reverse order, so that the - // higher-order packages come first in the list; that allows them to shadow - // settings in the lower-order packages. - assert(!inst->_packages.empty()); - string search_path; - size_t pi = inst->_packages.size() - 1; - search_path = inst->_packages[pi]->get_package_dir(); - while (pi > 0) { - --pi; - search_path += sep; - search_path += inst->_packages[pi]->get_package_dir(); - } - - replace_slashes(search_path); - nout << "Search path is " << search_path << "\n"; - - bool keep_pythonpath = false; - if (inst->_allow_python_dev) { - // If "allow_python_dev" is set in the instance's p3d_info.xml, *and* we - // have keep_pythonpath in the tokens, then we set keep_pythonpath true. - keep_pythonpath = (inst->get_fparams().lookup_token_int("keep_pythonpath") != 0); - } - - string sys_path = search_path; - string ld_path = search_path; - string dyld_path = search_path; - string python_path = search_path; - string prc_path = prc_root + sep + search_path; - - string prc_name = inst->get_fparams().lookup_token("prc_name"); - if (prc_name.empty()) { - prc_name = inst->_prc_name; - - if (!prc_name.empty()) { - // If the prc_name is taken from the p3d file (and not from the HTML - // tokens), then we also append the alt_host name to the prc_name, so - // that each alt_host variant will run in a different directory. - string alt_host = inst->get_fparams().lookup_token("alt_host"); - if (!alt_host.empty()) { - prc_name += "_"; - prc_name += alt_host; - } - } - } - if (!prc_name.empty()) { - // Add the prc_name to the path too, even if this directory doesn't - // actually exist. - string this_prc_dir = inst_mgr->get_root_dir() + "/prc"; - inst_mgr->append_safe_dir(this_prc_dir, prc_name); - replace_slashes(this_prc_dir); - prc_path = this_prc_dir + sep + prc_path; - } - - if (keep_pythonpath) { - // With keep_pythonpath true, we preserve the PYTHONPATH setting from the - // caller's environment; in fact, we put it in the front. This allows the - // caller's on-disk Python files to shadow the similar-named files in the - // p3d file, allowing easy iteration on the code in the p3d file. - if (get_env(python_path, "PYTHONPATH")) { - replace_slashes(python_path); - python_path += sep; - python_path += search_path; - } - - // We also preserve PRC_PATH. - if (get_env(prc_path, "PRC_PATH") || get_env(prc_path, "PANDA_PRC_PATH")) { - replace_slashes(prc_path); - prc_path += sep; - prc_path += search_path; - } - - nout << "keep_pythonpath is true\n" - << "PYTHONPATH set to: " << python_path << "\n" - << "PRC_PATH set to: " << prc_path << "\n"; - } - - // Get the name of the executable to run. Ideally, we'll run the executable - // successfully, in a sub-process; this will in turn load and run the - // dynamic library. If that fails for some reason, we can fall back to - // loading and running the library directly. - _p3dpython_exe = P3D_PLUGIN_P3DPYTHON; - string p3dpythonw_exe = _p3dpython_exe + "w"; - if (_p3dpython_exe.empty()) { - // Allow package to override the name of the p3dpython executables. - const char *p3dpython_name_xconfig = nullptr; - const char *p3dpythonw_name_xconfig = nullptr; - const TiXmlElement *panda3d_xconfig = inst->_panda3d_package->get_xconfig(); - if (panda3d_xconfig != nullptr) { - p3dpython_name_xconfig = panda3d_xconfig->Attribute("p3dpython_name"); - p3dpythonw_name_xconfig = panda3d_xconfig->Attribute("p3dpythonw_name"); - } - - string p3dpython_name = "p3dpython"; - if (p3dpython_name_xconfig != nullptr) { - nout << "p3dpython_name from panda3d xconfig: " << p3dpython_name_xconfig << "\n"; - p3dpython_name = p3dpython_name_xconfig; - } - - string p3dpythonw_name = p3dpython_name + "w"; - if (p3dpythonw_name_xconfig != nullptr) { - nout << "p3dpythonw_name from panda3d xconfig: " << p3dpythonw_name_xconfig << "\n"; - p3dpythonw_name = p3dpythonw_name_xconfig; - } - - // Build full executable path. - _p3dpython_exe = _python_root_dir + "/" + p3dpython_name; - p3dpythonw_exe = _python_root_dir + "/" + p3dpythonw_name; -#ifdef __APPLE__ - // On OSX, run from the packaged bundle, if it exists. - string bundle_exe = _python_root_dir + "/P3DPython.app/Contents/MacOS/p3dpython"; - if (access(bundle_exe.c_str(), X_OK) == 0) { - _p3dpython_exe = bundle_exe; - } -#endif - } -#ifdef _WIN32 - if (!inst_mgr->get_console_environment()) { - _p3dpython_exe = p3dpythonw_exe; - } - _p3dpython_exe += ".exe"; -#endif - replace_slashes(_p3dpython_exe); - nout << "_p3dpython_exe: " << _p3dpython_exe << "\n"; - - // Populate the new process' environment. - _env = string(); - - if (!_keep_user_env) { - // Reconstruct an environment just for running the process. Completely - // replace most of the existing environment variables with our own. - - // These are the enviroment variables we forward from the current - // environment, if they are set. - const char *keep[] = { - "HOME", "USER", -#ifdef _WIN32 - "SYSTEMROOT", "USERPROFILE", "COMSPEC", - "SYSTEMDRIVE", "ALLUSERSPROFILE", "APPDATA", "COMMONPROGRAMFILES", - "PROGRAMFILES", "WINDIR", "PROGRAMDATA", "USERDOMAIN", -#else - "LANGUAGE", "LC_ALL", "LC_MESSAGES", "LANG", -#endif -#ifdef HAVE_X11 - "DISPLAY", "XAUTHORITY", -#endif - nullptr - }; - for (int ki = 0; keep[ki] != nullptr; ++ki) { - string value; - if (get_env(value, keep[ki])) { - _env += keep[ki]; - _env += "="; - _env += value; - _env += '\0'; - } - } - - } else { - // In a trusted environment, when the application asks us to, we forward - // *all* environment variables, except those defined specifically below. - const char *dont_keep[] = { - "PATH", "LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH", - "PYTHONPATH", "PYTHONHOME", "PRC_PATH", "PANDA_PRC_PATH", - "TEMP", "CTPROJS", - nullptr - }; - -#ifdef _WIN32 - // Windows has a leading underscore in the name, and the word "environ" is - // a keyword. (!) - extern char **_environ; - char **global_environ = _environ; -#elif defined(__APPLE__) - // Apple doesn't guarantee that environ is available for shared libraries, - // but provides _NSGetEnviron(). - char **global_environ = *_NSGetEnviron(); -#else - // Posix is straightforward. - extern char **environ; - char **global_environ = environ; -#endif // _WIN32 - - char **ep; - for (ep = global_environ; *ep != nullptr; ++ep) { - string env = *ep; - size_t equals = env.find('='); - if (equals != string::npos) { - string var = env.substr(0, equals); - const char *varc = var.c_str(); - bool found = false; - for (int i = 0; dont_keep[i] != nullptr && !found; ++i) { -#ifdef _WIN32 - found = (_stricmp(dont_keep[i], varc) == 0); -#else - found = (strcmp(dont_keep[i], varc) == 0); -#endif - } - if (!found) { - // This variable is OK, keep it. - _env += env; - _env += '\0'; - } - } - } - } - - // We also append the original PATH et al to the *end* of the new - // definitions, even if keep_user_env is not set. This is necessary for - // os.system() and such to work as expected within the embedded app. It's - // also necessary for webbrowser on Linux. - string orig_path; - if (get_env(orig_path, "PATH")) { - sys_path += sep; - sys_path += orig_path; - } - string orig_ld_path; - if (get_env(orig_ld_path, "LD_LIBRARY_PATH")) { - ld_path += sep; - ld_path += orig_ld_path; - } - string orig_dyld_path; - if (get_env(orig_dyld_path, "DYLD_LIBRARY_PATH")) { - dyld_path += sep; - dyld_path += orig_dyld_path; - } - - // Define some new environment variables. - _env += "PATH="; - _env += sys_path; - _env += '\0'; - - _env += "LD_LIBRARY_PATH="; - _env += ld_path; - _env += '\0'; - - _env += "DYLD_LIBRARY_PATH="; - _env += dyld_path; - _env += '\0'; - - _env += "PYTHONPATH="; - _env += python_path; - _env += '\0'; - - // Let's leave PYTHONHOME empty. Setting it adds junk to our carefully- - // constructed PYTHONPATH. - _env += "PYTHONHOME="; - _env += '\0'; - - _env += "PRC_PATH="; - _env += prc_path; - _env += '\0'; - - _env += "PANDA_PRC_PATH="; - _env += prc_path; - _env += '\0'; - - _env += "TEMP="; - string temp_dir = inst_mgr->get_temp_directory(); - replace_slashes(temp_dir); - _env += temp_dir; - _env += '\0'; - - // Define each package's root directory in an environment variable named - // after the package, for the convenience of the packages in setting up - // their config files. - for (size_t pi = 0; pi < inst->_packages.size(); ++pi) { - P3DPackage *package = inst->_packages[pi]; - const string package_name = package->get_package_name(); - for (string::const_iterator si = package_name.begin(); - si != package_name.end(); - ++si) { - _env += toupper(*si); - } - _env += string("_ROOT="); - _env += package->get_package_dir(); - _env += '\0'; - - package->mark_used(); - } - - // Check for a few tokens that have special meaning at this level. - bool console_output = (inst->get_fparams().lookup_token_int("console_output") != 0); - bool one_process = (inst->get_fparams().lookup_token_int("one_process") != 0); - _interactive_console = (inst->get_fparams().lookup_token_int("interactive_console") != 0); - - if (!inst->_allow_python_dev) { - // interactive_console is only allowed to be enabled if allow_python_dev - // is also set within the p3d file. - _interactive_console = false; - } - - if (_interactive_console) { - // If we have interactive_console set, it follows we also need - // console_output. - console_output = true; - } - - // Get the log filename from the HTML tokens, or from the p3d_info.xml file. - string log_basename = inst->get_fparams().lookup_token("log_basename"); - if (log_basename.empty()) { - log_basename = inst->_log_basename; - - if (!log_basename.empty()) { - // If the log_basename is taken from the p3d file (and not from the HTML - // tokens), then we also append the alt_host name to the log_basename, - // so that each alt_host variant will run in a different directory. - string alt_host = inst->get_fparams().lookup_token("alt_host"); - if (!alt_host.empty()) { - log_basename += "_"; - log_basename += alt_host; - } - } - } - - if (log_basename.empty()) { -#ifdef P3D_PLUGIN_LOG_BASENAME3 - // No log_basename specified for the app; use the compiled-in default. - log_basename = P3D_PLUGIN_LOG_BASENAME3; -#endif - if (log_basename.empty()) { - log_basename = "p3dsession"; - } - } - - // However, it is always written into the log directory only; the user may - // not override the log file to put it anywhere else. - size_t slash = log_basename.rfind('/'); - if (slash != string::npos) { - log_basename = log_basename.substr(slash + 1); - } -#ifdef _WIN32 - slash = log_basename.rfind('\\'); - if (slash != string::npos) { - log_basename = log_basename.substr(slash + 1); - } -#endif // _WIN32 - - // Get the log history count from the HTML tokens, or from the p3d_info.xml - // file. - int log_history = inst->get_fparams().lookup_token_int("log_history"); - - // Check if we want to keep copies of recent logs on disk. - if (!log_basename.empty()) { - // Get a list of all logs on disk - std::vector all_logs; - string log_directory = inst_mgr->get_log_directory(); - inst_mgr->scan_directory(log_directory, all_logs); - - // If keeping logs, only logs with a -timestamp suffix are valid. - if (log_history > 0) { - // Remove exact match (no suffix) file, if it is on disk - string log_exact_leafname = (log_basename + string(".log")); - for (int i=0; i<(int)all_logs.size(); ++i) { - if (all_logs[i] == log_exact_leafname) { - string log_exact_pathname = (log_directory + log_exact_leafname); - unlink(log_exact_pathname.c_str()); - break; - } - } - } - - // Remove all but the most recent log_history timestamped logs - string log_basename_dash = (log_basename + string("-")); - string log_matching_pathname; - std::vector matching_logs; - for (int i=0; i<(int)all_logs.size(); ++i) { - if ((all_logs[i].size() > 4) && - (all_logs[i].find(log_basename_dash) == 0) && - (all_logs[i].substr(all_logs[i].size() - 4) == string(".log"))) { - log_matching_pathname = (log_directory + all_logs[i]); - matching_logs.push_back(log_matching_pathname); - } - } - for (int i=0; i<(int)matching_logs.size()-log_history; ++i) { - unlink(matching_logs[i].c_str()); - } - } - - // Append a timestamp suffix to the log_basename - if (!log_basename.empty() && (log_history > 0)) { -#ifdef _WIN32 - _tzset(); -#else - tzset(); -#endif - time_t log_time_seconds = time(nullptr); - struct tm *log_time_local_p = localtime(&log_time_seconds); - if (log_time_local_p != nullptr) { - struct tm log_time_local = *log_time_local_p; - static const size_t buffer_size = 16; - char buffer[buffer_size]; - sprintf(buffer, "%02d%02d%02d_%02d%02d%02d", - (int)(log_time_local.tm_year+1900-2000), - (int)(log_time_local.tm_mon+1), - (int)(log_time_local.tm_mday), - (int)(log_time_local.tm_hour), - (int)(log_time_local.tm_min), - (int)(log_time_local.tm_sec)); - log_basename += "-"; - log_basename += buffer; - } - } - - if (!console_output && !log_basename.empty()) { - _log_pathname = inst_mgr->get_log_directory(); - _log_pathname += log_basename; - - // We always tack on the extension ".log", to make it even more difficult - // to overwrite a system file. - _log_pathname += ".log"; - } - - // Create the pipes for communication. -#ifdef _WIN32 - // Create a bi-directional pipe to communicate with the sub-process. - HANDLE r_to, w_to, r_from, w_from; - - // Create the pipe to the process. - if (!CreatePipe(&r_to, &w_to, nullptr, 0)) { - nout << "failed to create pipe\n"; - set_failed(); - } else { - // Make sure the right end of the pipe is inheritable. - SetHandleInformation(r_to, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); - SetHandleInformation(w_to, HANDLE_FLAG_INHERIT, 0); - } - - // Create the pipe from the process. - if (!CreatePipe(&r_from, &w_from, nullptr, 0)) { - nout << "failed to create pipe\n"; - set_failed(); - } else { - // Make sure the right end of the pipe is inheritable. - SetHandleInformation(w_from, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); - SetHandleInformation(r_from, HANDLE_FLAG_INHERIT, 0); - } - - _output_handle = w_from; - _input_handle = r_to; - _pipe_read.open_read(r_from); - _pipe_write.open_write(w_to); - -#else - // Create a bi-directional pipe to communicate with the sub-process. - int to_fd[2]; - if (pipe(to_fd) < 0) { - perror("failed to create pipe"); - set_failed(); - } - int from_fd[2]; - if (pipe(from_fd) < 0) { - perror("failed to create pipe"); - set_failed(); - } - - _input_handle = to_fd[0]; - _output_handle = from_fd[1]; - _pipe_read.open_read(from_fd[0]); - _pipe_write.open_write(to_fd[1]); -#endif // _WIN32 - - if (_failed) { - return; - } - - nout << "Setting environment:\n"; - write_env(); - - // Get the filename of the Panda3D multifile. We need to pass this to - // p3dpython. - _mf_filename = inst->_panda3d_package->get_archive_file_pathname(); - - nout << "Attempting to start python from " << _p3dpython_exe << "\n"; - - bool started_p3dpython; - if (one_process) { - nout << "one_process is set; running Python within parent process.\n"; - started_p3dpython = false; - } else { -#ifdef _WIN32 - _p3dpython_handle = win_create_process(); - started_p3dpython = (_p3dpython_handle != INVALID_HANDLE_VALUE); -#else - _p3dpython_pid = posix_create_process(); - started_p3dpython = (_p3dpython_pid > 0); -#endif - if (!started_p3dpython) { - nout << "Failed to create process.\n"; - } - } - - if (!started_p3dpython) { - // Well, we couldn't run python in a sub-process, for some reason. Fall - // back to running it in a sub-thread within the same process. This isn't - // nearly as good, but I guess it's better than nothing. - - INIT_THREAD(_p3dpython_thread); - SPAWN_THREAD(_p3dpython_thread, p3dpython_thread_run, this); - _p3dpython_one_process = true; - } - _p3dpython_started = true; - _p3dpython_running = true; - - if (!_pipe_read) { - nout << "unable to open read pipe\n"; - } - if (!_pipe_write) { - nout << "unable to open write pipe\n"; - } - - spawn_read_thread(); - - // The very first command we send to the process is its session_id. - TiXmlDocument doc; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "init"); - xcommand->SetAttribute("session_id", _session_id); - doc.LinkEndChild(xcommand); - write_xml(_pipe_write, &doc, nout); - - // Also feed it any commands we may have queued up from before the process - // was started. - Commands::iterator ci; - for (ci = _commands.begin(); ci != _commands.end(); ++ci) { - write_xml(_pipe_write, (*ci), nout); - delete (*ci); - } - _commands.clear(); -} - -/** - * Sets the "failed" indication to display sadness to the user--we're unable - * to launch the instance for some reason. - * - * When this is called on the P3DSession instead of on a particular - * P3DInstance, it means that all instances attached to this session are - * marked failed. - */ -void P3DSession:: -set_failed() { - _failed = true; - - Instances::iterator ii; - ACQUIRE_LOCK(_instances_lock); - for (ii = _instances.begin(); ii != _instances.end(); ++ii) { - P3DInstance *inst = (*ii).second; - inst->set_failed(); - } - RELEASE_LOCK(_instances_lock); -} - -/** - * Starts the read thread. This thread is responsible for reading the - * standard input socket for XML requests and storing them in the _requests - * queue. - */ -void P3DSession:: -spawn_read_thread() { - assert(!_started_read_thread && !_read_thread_continue); - - _read_thread_continue = true; - SPAWN_THREAD(_read_thread, rt_thread_run, this); - _started_read_thread = true; -} - -/** - * Waits for the read thread to stop. - */ -void P3DSession:: -join_read_thread() { - if (!_started_read_thread) { - return; - } - - _read_thread_continue = false; - - JOIN_THREAD(_read_thread); - _started_read_thread = false; -} - -/** - * Changes the forward slashes to backslashes on Windows. Does nothing on the - * other platforms. - */ -void P3DSession:: -replace_slashes(string &str) { -#ifdef _WIN32 - // It turns out that some very low-level Windows functions fail when you - // give them a forward slash instead of a backslash. In particular, Windows - // fails to load the MSVS runtime DLL's (and their associated manifest - // files) correctly in this case. So we have to be sure to replace forward - // slashes in our PATH variable (and other environment variables, for good - // measure) with backslashes. - for (size_t i = 0; i < str.length(); ++i) { - if (str[i] == '/') { - str[i] = '\\'; - } - } -#endif // _WIN32 -} - -/** - * The main function for the read thread. - */ -void P3DSession:: -rt_thread_run() { - while (_read_thread_continue) { - TiXmlDocument *doc = read_xml(_pipe_read, nout); - if (doc == nullptr) { - // Some error on reading. Abort. - rt_terminate(); - _p3dpython_running = false; - _response_ready.acquire(); - _response_ready.notify(); - _response_ready.release(); - return; - } - - // Successfully read an XML document. - rt_handle_request(doc); - } - - nout << "Exiting rt_thread_run in " << this << "\n"; -} - -/** - * Processes a single request or notification received from an instance. This - * method runs in the read thread. - */ -void P3DSession:: -rt_handle_request(TiXmlDocument *doc) { - TiXmlElement *xresponse = doc->FirstChildElement("response"); - if (xresponse != nullptr) { - int response_id; - if (xresponse->QueryIntAttribute("response_id", &response_id) == TIXML_SUCCESS) { - // This is a response to a previous command-and-response. Send it to - // the parent thread. - _response_ready.acquire(); - bool inserted = _responses.insert(Responses::value_type(response_id, doc)).second; - assert(inserted); - _response_ready.notify(); - _response_ready.release(); - return; - } - } - - TiXmlElement *xrequest = doc->FirstChildElement("request"); - if (xrequest != nullptr) { - int instance_id; - if (xrequest->QueryIntAttribute("instance_id", &instance_id) == TIXML_SUCCESS) { - // Look up the particular instance this is related to. - ACQUIRE_LOCK(_instances_lock); - Instances::const_iterator ii; - ii = _instances.find(instance_id); - if (ii != _instances.end()) { - P3DInstance *inst = (*ii).second; - inst->add_raw_request(doc); - doc = nullptr; - } - RELEASE_LOCK(_instances_lock); - } - } - - if (doc != nullptr) { - delete doc; - } -} - -/** - * Got a closed pipe from the sub-process. Send a terminate request for all - * instances. - */ -void P3DSession:: -rt_terminate() { - Instances icopy; - ACQUIRE_LOCK(_instances_lock); - icopy = _instances; - RELEASE_LOCK(_instances_lock); - - // TODO: got a race condition here. What happens if someone deletes an - // instance while we're processing this loop? - - for (Instances::iterator ii = icopy.begin(); ii != icopy.end(); ++ii) { - P3DInstance *inst = (*ii).second; - inst->request_stop_main_thread(); - } -} - -#ifdef _WIN32 -/** - * Creates a sub-process to run _p3dpython_exe, with the appropriate command- - * line arguments, and the environment string defined in _env. Standard error - * is logged to _log_pathname, if that string is nonempty. - * - * Opens the two HandleStreams _pipe_read and _pipe_write as the read and - * write pipes to the child process's standard output and standard input, - * respectively. - * - * Returns the handle to the created process on success, or - * INVALID_HANDLE_VALUE on falure. - */ -HANDLE P3DSession:: -win_create_process() { - // Make sure we see an error dialog if there is a missing DLL. - SetErrorMode(0); - - // Open the log file. - HANDLE error_handle = GetStdHandle(STD_ERROR_HANDLE); - bool got_error_handle = false; - if (!_log_pathname.empty()) { - wstring log_pathname_w; - string_to_wstring(log_pathname_w, _log_pathname); - HANDLE handle = CreateFileW - (log_pathname_w.c_str(), GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - nullptr, CREATE_ALWAYS, 0, nullptr); - if (handle != INVALID_HANDLE_VALUE) { - error_handle = handle; - SetHandleInformation(error_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); - got_error_handle = true; - } else { - nout << "Unable to open " << _log_pathname << "\n"; - } - } - - STARTUPINFOW startup_info; - ZeroMemory(&startup_info, sizeof(startup_info)); - startup_info.cb = sizeof(startup_info); - - // Set up the IO handles. We send stderr and stdout to our error_handle. - startup_info.hStdError = error_handle; - startup_info.hStdOutput = error_handle; - startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - startup_info.dwFlags |= STARTF_USESTDHANDLES; - - // We want to show the output window these days. - startup_info.wShowWindow = SW_SHOW; - startup_info.dwFlags |= STARTF_USESHOWWINDOW; - - // If _keep_user_env is true, meaning not to change the current directory, - // then pass NULL in to CreateProcess(). Otherwise pass in _start_dir. - const wchar_t *start_dir_cstr; - wstring start_dir_w; - if (_keep_user_env) { - start_dir_cstr = nullptr; - nout << "Not changing working directory.\n"; - } else { - string_to_wstring(start_dir_w, _start_dir); - start_dir_cstr = start_dir_w.c_str(); - nout << "Setting working directory: " << _start_dir << "\n"; - } - - // Construct the command-line string, containing the quoted command-line - // arguments. - std::ostringstream stream; - stream << "\"" << _p3dpython_exe << "\" \"" << _mf_filename - << "\" \"" << _input_handle << "\" \"" << _output_handle - << "\" \"" << _interactive_console << "\""; - - // I'm not sure why CreateProcess wants a non-const char pointer for its - // command-line string, but I'm not taking chances. It gets a non-const - // char array that it can modify. - wstring command_line_str; - string_to_wstring(command_line_str, stream.str()); - wchar_t *command_line = new wchar_t[command_line_str.size() + 1]; - memcpy(command_line, command_line_str.c_str(), sizeof(wchar_t) * command_line_str.size() + 1); - - nout << "Command line: " << command_line_str << "\n"; - - wstring p3dpython_exe_w; - string_to_wstring(p3dpython_exe_w, _p3dpython_exe); - wstring env_w; - string_to_wstring(env_w, _env); - - PROCESS_INFORMATION process_info; - BOOL result = CreateProcessW - (p3dpython_exe_w.c_str(), command_line, nullptr, nullptr, TRUE, - CREATE_UNICODE_ENVIRONMENT, (void *)env_w.c_str(), - start_dir_cstr, &startup_info, &process_info); - bool started_program = (result != 0); - - if (!started_program) { - nout << "CreateProcess failed, error: " << GetLastError() << "\n"; - } - - delete[] command_line; - - // Close the pipe handles that are now owned by the child. - CloseHandle(_output_handle); - CloseHandle(_input_handle); - if (got_error_handle) { - CloseHandle(error_handle); - } - - if (!started_program) { - _pipe_read.close(); - _pipe_write.close(); - return INVALID_HANDLE_VALUE; - } - - CloseHandle(process_info.hThread); - return process_info.hProcess; -} -#endif // _WIN32 - - -#ifndef _WIN32 -/** - * Creates a sub-process to run _p3dpython_exe, with the appropriate command- - * line arguments, and the environment string defined in _env. Standard error - * is logged to _log_pathname, if that string is nonempty. - * - * Opens the two HandleStreams _pipe_read and _pipe_write as the read and - * write pipes to the child process's standard output and standard input, - * respectively. - * - * Returns the pid of the created process on success, or -1 on falure. - */ -int P3DSession:: -posix_create_process() { - // If the program file doesn't exist or isn't executable, don't even bother - // to try. - if (access(_p3dpython_exe.c_str(), X_OK) != 0) { - return -1; - } - - // Fork and exec. - pid_t child = fork(); - if (child < 0) { - perror("fork"); - return -1; - } - - if (child == 0) { - // Here we are in the child process. - - // Close the parent's ends of the pipes. - _pipe_read.close(); - _pipe_write.close(); - - if (!_log_pathname.empty()) { - // Open a logfile. - int logfile_fd = open(_log_pathname.c_str(), - O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (logfile_fd < 0) { - nout << "Unable to open " << _log_pathname << "\n"; - } else { - // Redirect stderr and stdout onto our logfile. - dup2(logfile_fd, STDERR_FILENO); - dup2(logfile_fd, STDOUT_FILENO); - close(logfile_fd); - } - } - - if (_keep_user_env) { - nout << "Not changing working directory.\n"; - } else { - nout << "Setting working directory: " << _start_dir << "\n"; - if (chdir(_start_dir.c_str()) < 0) { - nout << "Could not chdir to " << _start_dir << "\n"; - // This is a warning, not an error. We don't actually care that much - // about the starting directory. - } - } - - // build up an array of char strings for the environment. - std::vector ptrs; - size_t p = 0; - size_t zero = _env.find('\0', p); - while (zero != string::npos) { - ptrs.push_back(_env.data() + p); - p = zero + 1; - zero = _env.find('\0', p); - } - ptrs.push_back(nullptr); - - std::stringstream input_handle_stream; - input_handle_stream << _input_handle; - string input_handle_str = input_handle_stream.str(); - - std::stringstream output_handle_stream; - output_handle_stream << _output_handle; - string output_handle_str = output_handle_stream.str(); - - execle(_p3dpython_exe.c_str(), _p3dpython_exe.c_str(), - _mf_filename.c_str(), input_handle_str.c_str(), - output_handle_str.c_str(), - _interactive_console ? "1" : "0", (char *)0, &ptrs[0]); - nout << "Failed to exec " << _p3dpython_exe << "\n"; - _exit(1); - } - - // Close the handles that are now owned by the child. - close(_input_handle); - close(_output_handle); - - // Let's wait a few milliseconds and see if the child is going to - // immediately exit with a failure status. This isn't 100% reliable, but - // it's a lot easier than sending back a "yes I successfully started the - // program" message. Maybe I'll put in the more reliable test later. - - struct timeval start; - gettimeofday(&start, nullptr); - int start_ms = start.tv_sec * 1000 + start.tv_usec / 1000; - - int status; - pid_t result = waitpid(child, &status, WNOHANG); - while (result != child) { - if (result == -1) { - perror("waitpid"); - break; - } - - struct timeval now; - gettimeofday(&now, nullptr); - int now_ms = now.tv_sec * 1000 + now.tv_usec / 1000; - int elapsed = now_ms - start_ms; - if (elapsed > 100) { - // OK, we've waited, and the child process is still alive. Assume it - // will stay that way. - nout << "child still alive after " << elapsed << " ms\n"; - return child; - } - - // Yield the timeslice and wait some more. - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1; - select(0, nullptr, nullptr, nullptr, &tv); - result = waitpid(child, &status, WNOHANG); - } - - // The child process died for some reason; maybe it couldn't exec() its - // process. Report an error condition. - nout << "Python process stopped immediately.\n"; - if (WIFEXITED(status)) { - int code = WEXITSTATUS(status); - - nout << " exited normally, status = " << code << "\n"; - if (code != 0) { - _exit(code); - } - - } else if (WIFSIGNALED(status)) { - nout << " signalled by " << WTERMSIG(status) << ", core = " - << WCOREDUMP(status) << "\n"; - - // This seems to be a popular shell convention. - _exit(128 + WTERMSIG(status)); - - } else if (WIFSTOPPED(status)) { - nout << " stopped by " << WSTOPSIG(status) << "\n"; - } - - return -1; -} -#endif // _WIN32 - -/** - * This method is called in a sub-thread to fire up p3dpython within this same - * process, but only if the above attempt to create a sub-process failed. - */ -void P3DSession:: -p3dpython_thread_run() { - nout << "running p3dpython_thread_run()\n"; - - // Set the environment. Hopefully this won't be too destructive to the - // current process. - - // Note that on OSX at least, changing the DYLD_LIBRARY_PATH after the - // process has started has no effect (and furthermore you can't specify a - // full path to dlopen() calls), so this whole one-process approach is - // fatally flawed on OSX. - size_t p = 0; - size_t zero = _env.find('\0', p); - while (zero != string::npos) { - const char *start = _env.data() + p; -#ifdef _WIN32 - _putenv(start); -#else - const char *equals = strchr(start, '='); - if (equals != nullptr) { - string variable(start, equals - start); - setenv(variable.c_str(), equals + 1, true); - } -#endif // _WIN32 - p = zero + 1; - zero = _env.find('\0', p); - } - - // Now load the library. - string libp3dpython = _python_root_dir + "/libp3dpython"; -#ifdef _WIN32 -#ifdef _DEBUG - libp3dpython += "_d.dll"; -#else - libp3dpython += ".dll"; -#endif - SetErrorMode(0); - HMODULE module = LoadLibrary(libp3dpython.c_str()); - if (module == nullptr) { - // Couldn't load the DLL. - nout << "Couldn't load " << libp3dpython << "\n"; - return; - } - - #define get_func GetProcAddress - -#else // _WIN32 - // Posix case. - #ifdef __APPLE__ - libp3dpython += ".dylib"; - #else - libp3dpython += ".so"; - #endif - void *module = dlopen(libp3dpython.c_str(), RTLD_LAZY | RTLD_LOCAL); - if (module == nullptr) { - // Couldn't load the .so. - nout << "Couldn't load " << libp3dpython << "\n"; - return; - } - - #define get_func dlsym - -#endif // _WIN32 - - run_p3dpython_func *run_p3dpython = (run_p3dpython_func *)get_func(module, "run_p3dpython"); - if (run_p3dpython == nullptr) { - nout << "Couldn't find run_p3dpython\n"; - return; - } - - int status = run_p3dpython(libp3dpython.c_str(), _mf_filename.c_str(), - _input_handle, _output_handle, _log_pathname.c_str(), - _interactive_console); - if (status != 0) { - nout << "Failure on startup.\n"; - _exit(status); - } -} - -/** - * Implements getenv(), respecting Windows' Unicode environment. Returns true - * if the variable is defined, false if it is not. If it is defined, fills - * value with its definition. - */ -bool P3DSession:: -get_env(string &value, const string &varname) { -#ifdef _WIN32 - wstring varname_w; - string_to_wstring(varname_w, varname); - const wchar_t *vc = _wgetenv(varname_w.c_str()); - if (vc == nullptr) { - return false; - } - wstring_to_string(value, vc); - return true; -#else // _WIN32 - const char *vc = getenv(varname.c_str()); - if (vc == nullptr) { - return false; - } - value = vc; - return true; -#endif -} - -/** - * Writes _env, which is formatted as a string containing zero-byte-terminated - * environment defintions, to the nout stream, one definition per line. - */ -void P3DSession:: -write_env() const { - size_t p = 0; - size_t zero = _env.find('\0', p); - while (zero != string::npos) { - nout << " "; - nout.write(_env.data() + p, zero - p); - nout << "\n"; - p = zero + 1; - zero = _env.find('\0', p); - } -} diff --git a/direct/src/plugin/p3dSession.h b/direct/src/plugin/p3dSession.h deleted file mode 100644 index eca5702fd6..0000000000 --- a/direct/src/plugin/p3dSession.h +++ /dev/null @@ -1,166 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dSession.h - * @author drose - * @date 2009-06-03 - */ - -#ifndef P3DSESSION_H -#define P3DSESSION_H - -#include "p3d_plugin_common.h" -#include "handleStream.h" -#include "p3dPackage.h" -#include "p3dConditionVar.h" -#include "p3dReferenceCount.h" -#include "get_tinyxml.h" - -#include -#include - -class P3DInstance; -class P3DProgressWindow; - -/** - * Corresponds to a single session: a subprocess with a unique instance of - * Python running within it, which might include one or more P3DInstance - * objects running in the same memory space with each other. - */ -class P3DSession : public P3DReferenceCount { -public: - P3DSession(P3DInstance *inst); - ~P3DSession(); - - void shutdown(); - - inline const std::string &get_session_key() const; - inline const std::string &get_log_pathname() const; - inline bool get_matches_script_origin() const; - - void start_instance(P3DInstance *inst); - void terminate_instance(P3DInstance *inst); - - inline int get_num_instances() const; - - void send_command(TiXmlDocument *command); - TiXmlDocument *command_and_response(TiXmlDocument *command); - P3D_object *xml_to_p3dobj(const TiXmlElement *xvalue); - TiXmlElement *p3dobj_to_xml(P3D_object *obj); - void send_windows_message(P3DInstance *inst, unsigned int msg, - int wparam, int lparam); - - void signal_request_ready(P3DInstance *inst); - - void drop_pyobj(int object_id); - void drop_p3dobj(int object_id); - -private: - void start_p3dpython(P3DInstance *inst); - void set_failed(); - - void spawn_read_thread(); - void join_read_thread(); - - static void replace_slashes(std::string &str); - -private: - // These methods run only within the read thread. - THREAD_CALLBACK_DECLARATION(P3DSession, rt_thread_run); - void rt_thread_run(); - void rt_terminate(); - void rt_handle_request(TiXmlDocument *doc); - -#ifdef _WIN32 - HANDLE win_create_process(); -#else - int posix_create_process(); -#endif - - // In case we can't get a separate process, we'll run p3dpython in a sub- - // thread. - THREAD_CALLBACK_DECLARATION(P3DSession, p3dpython_thread_run); - void p3dpython_thread_run(); - - static bool get_env(std::string &value, const std::string &varname); - void write_env() const; - -private: - int _session_id; - std::string _session_key; - std::string _log_pathname; - std::string _python_root_dir; - std::string _start_dir; - bool _matches_script_origin; - bool _keep_user_env; - bool _failed; - - // This information is passed to create_process(), or to - // p3dpython_thread_run(). - std::string _p3dpython_exe; - std::string _p3dpython_dll; - std::string _mf_filename; - std::string _env; - FHandle _input_handle, _output_handle; - bool _interactive_console; - - typedef std::map Instances; - Instances _instances; - LOCK _instances_lock; - - // Commands that are queued up to send down the pipe. Normally these only - // accumulate before the python process has been started; after that, - // commands are written to the pipe directly. - typedef std::vector Commands; - Commands _commands; - - // This map keeps track of the P3D_object pointers we have delivered to the - // child process. We have to keep each of these until the child process - // tells us it's safe to delete them. - typedef std::map SentObjects; - SentObjects _sent_objects; - - P3DPackage *_panda3d; - - // If this is true, then CreateProcess() or fork() failed (or we had - // one_process set true in the tokens), and we're forced to run p3dpython in - // a sub-thread within the same process, rather than in a separate process. - // This means we can't have multiple sessions running simultaneously, - // because Python don't play that way. - bool _p3dpython_one_process; - - // Members for communicating with the p3dpython child process (or thread, as - // the case may be). -#ifdef _WIN32 - HANDLE _p3dpython_handle; -#else - int _p3dpython_pid; -#endif - THREAD _p3dpython_thread; - bool _p3dpython_started; - bool _p3dpython_running; - - // The _response_ready mutex protects this structure. - typedef std::map Responses; - Responses _responses; - P3DConditionVar _response_ready; - - // The remaining members are manipulated by or for the read thread. - bool _started_read_thread; - HandleStream _pipe_read; - HandleStream _pipe_write; - - bool _read_thread_continue; - THREAD _read_thread; - - friend class P3DInstance; -}; - -#include "p3dSession.I" - -#endif diff --git a/direct/src/plugin/p3dSplashWindow.I b/direct/src/plugin/p3dSplashWindow.I deleted file mode 100644 index c9562a083a..0000000000 --- a/direct/src/plugin/p3dSplashWindow.I +++ /dev/null @@ -1,47 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dSplashWindow.I - * @author drose - * @date 2009-06-17 - */ - -/** - * Returns the current file parameters. - */ -inline const P3DFileParams &P3DSplashWindow:: -get_fparams() const { - return _fparams; -} - -/** - * Returns the current window parameters. - */ -inline const P3DWindowParams &P3DSplashWindow:: -get_wparams() const { - return _wparams; -} - -/** - * Returns the current setting of the "visible" flag. If false, the splash - * window is hidden. - */ -inline bool P3DSplashWindow:: -get_visible() const { - return _visible; -} - -/** - * - */ -inline P3DSplashWindow::ImageData:: -ImageData() { - _width = 0; - _height = 0; - _num_channels = 0; -} diff --git a/direct/src/plugin/p3dSplashWindow.cxx b/direct/src/plugin/p3dSplashWindow.cxx deleted file mode 100644 index 13bcc09ff2..0000000000 --- a/direct/src/plugin/p3dSplashWindow.cxx +++ /dev/null @@ -1,522 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dSplashWindow.cxx - * @author drose - * @date 2009-06-17 - */ - -#include "p3dSplashWindow.h" -#include "wstring_encode.h" - -// We use the public domain stb_image library for loading images. Define the -// stb_image implementation. We only use it in this unit. -#define STB_IMAGE_STATIC -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -using std::max; -using std::min; -using std::string; - -// The number of pixels to move the block per byte downloaded, when we don't -// know the actual file size we're downloading. -const double P3DSplashWindow::_unknown_progress_rate = 1.0 / 4096; - -/** - * By the time the SplashWindow is created, the instance has received both its - * fparams and its wparams. Copy them both into this class for reference. - */ -P3DSplashWindow:: -P3DSplashWindow(P3DInstance *inst, bool make_visible) : - _inst(inst), - _fparams(inst->get_fparams()), - _wparams(inst->get_wparams()) -{ - _visible = make_visible; - _fgcolor_r = 0x00; - _fgcolor_g = 0x00; - _fgcolor_b = 0x00; - _bgcolor_r = 0xff; - _bgcolor_g = 0xff; - _bgcolor_b = 0xff; - _barcolor_r = 0x6c; - _barcolor_g = 0xa5; - _barcolor_b = 0xe0; - _bar_bgcolor_r = _bgcolor_r; - _bar_bgcolor_g = _bgcolor_g; - _bar_bgcolor_b = _bgcolor_b; - _bar_border = 1; - _bar_bottom = 24; - _bar_width = 398; - _bar_height = 22; - _bar_width_ratio = 0.6; - _bar_height_ratio = 0.1; - _font_family = "Helvetica"; - _font_size = 12; - _font_style = FS_normal; - _font_weight = FW_normal; - _button_width = 0; - _button_height = 0; - _button_x = 0; - _button_y = 0; - _button_active = false; - _mouse_x = -1; - _mouse_y = -1; - _mouse_down = false; - _button_depressed = false; - _bstate = BS_hidden; -} - -/** - * - */ -P3DSplashWindow:: -~P3DSplashWindow() { -} - -/** - * Changes the window parameters, e.g. to resize or reposition the window; or - * sets the parameters for the first time, creating the initial window. - */ -void P3DSplashWindow:: -set_wparams(const P3DWindowParams &wparams) { - _wparams = wparams; - _win_width = _wparams.get_win_width(); - _win_height = _wparams.get_win_height(); -} - -/** - * Makes the splash window visible or invisible, so as not to compete with the - * embedded Panda window in the same space. - */ -void P3DSplashWindow:: -set_visible(bool visible) { - nout << "P3DSplashWindow::set_visible(" << visible << ")\n"; - _visible = visible; -} - -/** - * Specifies the name of a JPEG or PNG image file that is displayed in the - * center of the splash window. - * - * image_placement defines the specific context in which this particular image - * is displayed. It is similar to the P3DInstance's image_type, but it is a - * more specific, lower-level usage. - */ -void P3DSplashWindow:: -set_image_filename(const string &image_filename, ImagePlacement image_placement) { -} - -/** - * Specifies the color that is used to display the text above the loading bar. - * - * This may only be set before wparams is set. - */ -void P3DSplashWindow:: -set_fgcolor(int r, int g, int b) { - nout << "fgcolor " << r << ", " << g << ", " << b << "\n"; - _fgcolor_r = r; - _fgcolor_g = g; - _fgcolor_b = b; -} - -/** - * Specifies the solid color that is displayed behind the splash image, if - * any, or before the splash image is loaded. - * - * This may only be set before wparams is set. - */ -void P3DSplashWindow:: -set_bgcolor(int r, int g, int b) { - nout << "bgcolor " << r << ", " << g << ", " << b << "\n"; - _bgcolor_r = r; - _bgcolor_g = g; - _bgcolor_b = b; -} - -/** - * Specifies the color that is used to fill the loading bar. - * - * This may only be set before wparams is set. - */ -void P3DSplashWindow:: -set_barcolor(int r, int g, int b) { - nout << "barcolor " << r << ", " << g << ", " << b << "\n"; - _barcolor_r = r; - _barcolor_g = g; - _barcolor_b = b; -} - -/** - * Specifies the solid color that is displayed behind the loading bar. - * - * This may only be set before wparams is set. - */ -void P3DSplashWindow:: -set_bar_bgcolor(int r, int g, int b) { - nout << "bar_bgcolor " << r << ", " << g << ", " << b << "\n"; - _bar_bgcolor_r = r; - _bar_bgcolor_g = g; - _bar_bgcolor_b = b; -} - -/** - * Sets the width in pixels of the border around the loading bar, or 0 not to - * draw a bar at all. - * - * This may only be set before wparams is set. - */ -void P3DSplashWindow:: -set_bar_border(int border) { - nout << "bar_border " << border << "\n"; - _bar_border = border; -} - -/** - * Sets the amount of background pixels between the bottom edge of the window - * and the bottom edge of the loading bar border. - * - * This may only be set before wparams is set. - */ -void P3DSplashWindow:: -set_bar_bottom(int bottom) { - nout << "bar_bottom " << bottom << "\n"; - _bar_bottom = bottom; -} - -/** - * Sets the width of the loading bar. If percent is true, it is interpreted - * as a percentage of the window width. If false, it is interpreted as an - * absolute width in pixels. - * - * This may only be set before wparams is set. - */ -void P3DSplashWindow:: -set_bar_width(int width, bool percent) { - nout << "bar_width " << width; - if (percent) { - nout << '%'; - } - nout << '\n'; - - if (percent) { - _bar_width = -1; - _bar_width_ratio = abs(width) / 100.0; - } else { - _bar_width = abs(width); - _bar_width_ratio = 1.0; - } -} - -/** - * Sets the height of the loading bar. If percent is true, it is interpreted - * as a percentage of the window height. If false, it is interpreted as an - * absolute height in pixels. - * - * This may only be set before wparams is set. - */ -void P3DSplashWindow:: -set_bar_height(int height, bool percent) { - nout << "bar_height " << height; - if (percent) { - nout << '%'; - } - nout << '\n'; - - if (percent) { - _bar_height = -1; - _bar_height_ratio = abs(height) / 100.0; - } else { - _bar_height = abs(height); - _bar_height_ratio = 1.0; - } -} - -/** - * Sets the font family of the text above the loading bar. - * - * This may only be set before wparams is set. - */ -void P3DSplashWindow:: -set_font_family(const string &family) { - nout << "font_family " << family << "\n"; - _font_family = family; -} - -/** - * Sets the font size in pixels of the text above the loading bar. The - * default value is 12. - * - * This may only be set before wparams is set. - */ -void P3DSplashWindow:: -set_font_size(int size) { - nout << "font_size " << size << "\n"; - _font_size = size; -} - -/** - * Sets the font style of the text above the loading bar. - * - * This may only be set before wparams is set. - */ -void P3DSplashWindow:: -set_font_style(FontStyle style) { - nout << "font_style " << style << "\n"; - _font_style = style; -} - -/** - * Sets the font weight of the text above the loading bar. The default is - * FW_normal. It should be a multiple of 100 in the range 100-900. - * - * This may only be set before wparams is set. - */ -void P3DSplashWindow:: -set_font_weight(int weight) { - nout << "font_weight " << weight << "\n"; - _font_weight = weight; -} - -/** - * Specifies the text that is displayed above the install progress bar. - */ -void P3DSplashWindow:: -set_install_label(const string &install_label) { -} - -/** - * Moves the install progress bar from 0.0 to 1.0. - */ -void P3DSplashWindow:: -set_install_progress(double install_progress, - bool is_progress_known, size_t received_data) { -} - -/** - * Deals with the event callback from the OS window system. Returns true if - * the event is handled, false if ignored. - */ -bool P3DSplashWindow:: -handle_event(const P3D_event_data &event) { - return false; -} - -/** - * Sets whether the button should be visible and active (true) or invisible - * and inactive (false). If active, the button image will be displayed in the - * window, and a click event will be generated when the user clicks the - * button. - */ -void P3DSplashWindow:: -set_button_active(bool flag) { - _button_active = flag; - - // Now light up the button according to the current mouse position. - set_mouse_data(_mouse_x, _mouse_y, _mouse_down); -} - -/** - * The Panda window is asking us to manage keyboard focus in proxy for it. - * This is used on Vista, where the Panda window may be disallowed from - * directly assigning itself keyboard focus. - */ -void P3DSplashWindow:: -request_keyboard_focus() { -} - -/** - * Reads the image filename and sets image parameters width, height, - * num_channels, and data. Returns true on success, false on failure. - */ -bool P3DSplashWindow:: -read_image_data(ImageData &image, string &data, - const string &image_filename) { - image._width = 0; - image._height = 0; - image._num_channels = 0; - data.clear(); - - if (image_filename.empty()) { - return false; - } - - nout << "Reading splash file image: " << image_filename << "\n"; - - unsigned char *imgdata = stbi_load(image_filename.c_str(), &image._width, - &image._height, &image._num_channels, 0); - - if (imgdata == nullptr) { - nout << "Couldn't read splash file image: " << image_filename << "\n"; - const char *reason = stbi_failure_reason(); - if (reason != nullptr) { - nout << "stbi_failure_reason: " << reason << "\n"; - } - return false; - } - - size_t data_size = image._width * image._height * image._num_channels; - data.resize(data_size); - memcpy(&data[0], imgdata, data_size); - - stbi_image_free(imgdata); - return true; -} - -/** - * Given the window width and height, determine the rectangle in which to - * place the progress bar. - */ -void P3DSplashWindow:: -get_bar_placement(int &bar_x, int &bar_y, - int &bar_width, int &bar_height) { - - bar_width = (int)(_win_width * _bar_width_ratio); - bar_height = (int)(_win_height * _bar_height_ratio); - - if (_bar_width >= 0) { - bar_width = min(bar_width, _bar_width); - } - if (_bar_height >= 0) { - bar_height = min(bar_height, _bar_height); - } - - // Horizontally center the bar, and set it at a fixed distance from the - // bottom edge of the splash window. - bar_x = (_win_width - bar_width) / 2; - bar_y = _win_height - _bar_bottom - _bar_border - bar_height; -} - -/** - * Specifies the image that contains the "ready" button image, which in turn - * determines the clickable dimensions of the button within the window. - */ -void P3DSplashWindow:: -set_button_range(const ImageData &image) { - // The clickable area has a certain minimum size, even if it's a very small - // image. - _button_width = max(image._width, 64); - _button_height = max(image._height, 64); - - // But it can't be larger than the window itself. - _button_width = min(_button_width, _win_width); - _button_height = min(_button_height, _win_height); - - // Compute the top-left corner of the button image in window coordinates. - _button_x = (_win_width - _button_width) / 2; - _button_y = (_win_height - _button_height) / 2; -} - -/** - * Intended to be called by the subclasses as the mouse is tracked through the - * window, whether the button is currently active or not. This updates the - * internal state of the mouse pointer, and also (if the button is active) - * updates the button state appropriately, and generates the click event when - * the mouse button transitions from down to up over the button area. - */ -void P3DSplashWindow:: -set_mouse_data(int mouse_x, int mouse_y, bool mouse_down) { - ButtonState orig_bstate = _bstate; - - _mouse_x = mouse_x; - _mouse_y = mouse_y; - _mouse_down = mouse_down; - - ButtonState bstate = BS_hidden; - bool click_detected = false; - - if (!_button_active) { - // The button isn't active, so it's hidden, regardless of the mouse - // position. - bstate = BS_hidden; - } else { - // Is the mouse pointer within the button region? - bool is_within = (_mouse_x >= _button_x && _mouse_x < _button_x + _button_width && - _mouse_y >= _button_y && _mouse_y < _button_y + _button_height); - if (is_within) { - // The mouse is within the button region. This means either click or - // rollover state, according to the mouse button. - if (_mouse_down) { - // We only count it mouse-down if you've clicked down while over the - // button (or you never released the button since the last time you - // clicked down). Clicking down somewhere else and dragging over the - // button doesn't count. - if (orig_bstate == BS_rollover || _button_depressed) { - _button_depressed = true; - bstate = BS_click; - } else { - // Otherwise, we're mousing over the button region with the button - // held down. Hmm, don't think the button should light up. - bstate = BS_ready; - } - } else { - _button_depressed = false; - if (orig_bstate == BS_click) { - // If we just transitioned from mouse down to mouse up, this means a - // click. And the button automatically hides itself after a - // successful click. - bstate = BS_hidden; - _button_active = false; - click_detected = true; - } else { - bstate = BS_rollover; - } - } - } else { - // The mouse is not within the button region. This means ready state. - bstate = BS_ready; - if (!_mouse_down) { - _button_depressed = false; - } - } - } - - set_bstate(bstate); - - // If we detected a click operation in the above, make the callback here, at - // the end of the method, after we have finished updating the button state. - if (click_detected) { - button_click_detected(); - } -} - -/** - * Called when a button click by the user is detected in set_mouse_data(), - * this method simply turns around and notifies the instance. It's a virtual - * method to give subclasses a chance to redirect this message to the main - * thread or process, as necessary. - * - * Note that this method might be called in a sub-thread. - */ -void P3DSplashWindow:: -button_click_detected() { - assert(_inst != nullptr); - nout << "Play button clicked by user\n"; - _inst->splash_button_clicked_sub_thread(); -} - -/** - * Changes the button state as the mouse interacts with it. - */ -void P3DSplashWindow:: -set_bstate(ButtonState bstate) { - if (_bstate != bstate) { - _bstate = bstate; - // If we've changed button states, we need to refresh the window. - refresh(); - } -} - -/** - * Requests that the window will be repainted. This may or may not be - * implemented for a particular specialization of P3DSplashWindow. - */ -void P3DSplashWindow:: -refresh() { -} diff --git a/direct/src/plugin/p3dSplashWindow.h b/direct/src/plugin/p3dSplashWindow.h deleted file mode 100644 index 4f67b5c1c0..0000000000 --- a/direct/src/plugin/p3dSplashWindow.h +++ /dev/null @@ -1,156 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dSplashWindow.h - * @author drose - * @date 2009-06-17 - */ - -#ifndef P3DSPLASHWINDOW_H -#define P3DSPLASHWINDOW_H - -#include "p3d_plugin_common.h" -#include "p3dFileParams.h" -#include "p3dWindowParams.h" - -class P3DInstance; - -/** - * This window is displayed temporarily, in place of an instance's actual - * window, during the initial launch of an applet, and also during the initial - * download of Panda3D code if necessary. - * - * This is the base implementation; it contains no specific code to open a - * window. - */ -class P3DSplashWindow { -public: - P3DSplashWindow(P3DInstance *inst, bool make_visible); - virtual ~P3DSplashWindow(); - - inline const P3DFileParams &get_fparams() const; - - virtual void set_wparams(const P3DWindowParams &wparams); - inline const P3DWindowParams &get_wparams() const; - - virtual void set_visible(bool visible); - inline bool get_visible() const; - - enum ImagePlacement { - IP_background, - IP_button_ready, - IP_button_rollover, - IP_button_click, - IP_none - }; - enum FontStyle { - FS_normal, - FS_italic, - FS_oblique - }; - enum FontWeight { - FW_normal = 400, - FW_medium = 500, - FW_bold = 700, - FW_black = 900 - }; - - virtual void set_image_filename(const std::string &image_filename, - ImagePlacement image_placement); - void set_fgcolor(int r, int g, int b); - void set_bgcolor(int r, int g, int b); - void set_barcolor(int r, int g, int b); - void set_bar_bgcolor(int r, int g, int b); - void set_bar_border(int border); - void set_bar_bottom(int bottom); - void set_bar_width(int width, bool percent=false); - void set_bar_height(int height, bool percent=false); - void set_font_family(const std::string &family); - void set_font_size(int size); - void set_font_style(FontStyle style); - void set_font_weight(int weight); - virtual void set_install_label(const std::string &install_label); - virtual void set_install_progress(double install_progress, - bool is_progress_known, size_t received_data); - - virtual bool handle_event(const P3D_event_data &event); - - virtual void set_button_active(bool flag); - virtual void request_keyboard_focus(); - -protected: - // This ImageData base class provides minimal functionality for storing a - // loaded image. Most of the real meat of this class is provided by the - // various subclasses. - class ImageData { - public: - inline ImageData(); - int _width, _height, _num_channels; - }; - - bool read_image_data(ImageData &image, std::string &data, - const std::string &image_filename); - void get_bar_placement(int &bar_x, int &bar_y, - int &bar_width, int &bar_height); - void set_button_range(const ImageData &image); - void set_mouse_data(int mouse_x, int mouse_y, bool mouse_down); - - // The current visual state of the button. - enum ButtonState { - BS_hidden, - BS_ready, - BS_rollover, - BS_click, - }; - - virtual void button_click_detected(); - virtual void set_bstate(ButtonState bstate); - virtual void refresh(); - -protected: - P3DInstance *_inst; - P3DFileParams _fparams; - P3DWindowParams _wparams; - int _win_width, _win_height; - bool _visible; - - int _fgcolor_r, _fgcolor_g, _fgcolor_b; - int _bgcolor_r, _bgcolor_g, _bgcolor_b; - int _barcolor_r, _barcolor_g, _barcolor_b; - int _bar_bgcolor_r, _bar_bgcolor_g, _bar_bgcolor_b; - int _bar_border; - -private: - int _bar_bottom; - int _bar_width, _bar_height; - double _bar_width_ratio, _bar_height_ratio; - -protected: - std::string _font_family; - int _font_size; - FontStyle _font_style; - int _font_weight; - - // The region of the window for accepting button clicks. - int _button_width, _button_height; - int _button_x, _button_y; - bool _button_active; - - // Tracking the mouse pointer within the window, for the purposes of - // clicking the button. - int _mouse_x, _mouse_y; - bool _mouse_down; - bool _button_depressed; - ButtonState _bstate; - - static const double _unknown_progress_rate; -}; - -#include "p3dSplashWindow.I" - -#endif diff --git a/direct/src/plugin/p3dStringObject.cxx b/direct/src/plugin/p3dStringObject.cxx deleted file mode 100644 index 8d87a2dc8c..0000000000 --- a/direct/src/plugin/p3dStringObject.cxx +++ /dev/null @@ -1,109 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dStringObject.cxx - * @author drose - * @date 2009-06-30 - */ - -#include "p3dStringObject.h" - -/** - * - */ -P3DStringObject:: -P3DStringObject(const std::string &value) : _value(value) { -} - -/** - * - */ -P3DStringObject:: -P3DStringObject(const char *data, size_t size) : _value(data, size) { -} - -/** - * - */ -P3DStringObject:: -P3DStringObject(const P3DStringObject ©) : - P3DObject(copy), - _value(copy._value) -{ -} - -/** - * - */ -P3DStringObject:: -~P3DStringObject() { -} - -/** - * Returns the fundamental type of this kind of object. - */ -P3D_object_type P3DStringObject:: -get_type() { - return P3D_OT_string; -} - -/** - * Returns the object value coerced to a boolean, if possible. - */ -bool P3DStringObject:: -get_bool() { - return !_value.empty(); -} - -/** - * Fills the indicated C++ string object with the value of this object coerced - * to a string. - */ -void P3DStringObject:: -make_string(std::string &value) { - value = _value; -} - -/** - * Writes a formatted representation of the value to the indicated string. - * This is intended for developer assistance. - */ -void P3DStringObject:: -output(std::ostream &out) { - out << '"'; - for (std::string::const_iterator si = _value.begin(); si != _value.end(); ++si) { - if (isprint(*si)) { - switch (*si) { - case '"': - out << "\\\x22"; - break; - - default: - out << *si; - } - } else { - switch (*si) { - case '\n': - out << "\\n"; - break; - - case '\t': - out << "\\t"; - break; - - default: - { - char buffer[128]; - sprintf(buffer, "%02x", (unsigned char)(*si)); - out << "\\x" << buffer; - } - } - } - } - out << '"'; -} diff --git a/direct/src/plugin/p3dStringObject.h b/direct/src/plugin/p3dStringObject.h deleted file mode 100644 index 3e358e56b9..0000000000 --- a/direct/src/plugin/p3dStringObject.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dStringObject.h - * @author drose - * @date 2009-06-30 - */ - -#ifndef P3DSTRINGOBJECT_H -#define P3DSTRINGOBJECT_H - -#include "p3d_plugin_common.h" -#include "p3dObject.h" - -/** - * An object type that contains a string value. - */ -class P3DStringObject : public P3DObject { -public: - P3DStringObject(const std::string &value); - P3DStringObject(const char *data, size_t size); - P3DStringObject(const P3DStringObject ©); - -public: - virtual ~P3DStringObject(); - - virtual P3D_object_type get_type(); - virtual bool get_bool(); - virtual void make_string(std::string &value); - - virtual void output(std::ostream &out); - -private: - std::string _value; -}; - -#endif diff --git a/direct/src/plugin/p3dTemporaryFile.I b/direct/src/plugin/p3dTemporaryFile.I deleted file mode 100644 index c1d8eeb7e2..0000000000 --- a/direct/src/plugin/p3dTemporaryFile.I +++ /dev/null @@ -1,20 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dTemporaryFile.I - * @author drose - * @date 2009-08-19 - */ - -/** - * Returns the temporary filename. - */ -inline const std::string &P3DTemporaryFile:: -get_filename() const { - return _filename; -} diff --git a/direct/src/plugin/p3dTemporaryFile.cxx b/direct/src/plugin/p3dTemporaryFile.cxx deleted file mode 100644 index bb7c8ca7a1..0000000000 --- a/direct/src/plugin/p3dTemporaryFile.cxx +++ /dev/null @@ -1,33 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dTemporaryFile.cxx - * @author drose - * @date 2009-08-19 - */ - -#include "p3dTemporaryFile.h" -#include "p3dInstanceManager.h" - -/** - * Constructs a new, unique temporary filename. - */ -P3DTemporaryFile:: -P3DTemporaryFile(const std::string &extension) { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - _filename = inst_mgr->make_temp_filename(extension); -} - -/** - * Deletes the temporary file, if it exists. - */ -P3DTemporaryFile:: -~P3DTemporaryFile() { - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - inst_mgr->release_temp_filename(_filename); -} diff --git a/direct/src/plugin/p3dTemporaryFile.h b/direct/src/plugin/p3dTemporaryFile.h deleted file mode 100644 index 57fb6cef5a..0000000000 --- a/direct/src/plugin/p3dTemporaryFile.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dTemporaryFile.h - * @author drose - * @date 2009-08-19 - */ - -#ifndef P3DTEMPORARYFILE_H -#define P3DTEMPORARYFILE_H - -#include "p3d_plugin_common.h" - -/** - * This represents a temporary filename for some transitory purpose. This - * returns a filename which is guaranteed to be unique at the time the - * constructor was called. - * - * The file on disk, if it exists, will automatically be deleted when the - * destructor is called. - */ -class P3DTemporaryFile { -public: - P3DTemporaryFile(const std::string &extension); - ~P3DTemporaryFile(); - - inline const std::string &get_filename() const; - -private: - std::string _filename; -}; - -inline std::ostream &operator << (std::ostream &out, P3DTemporaryFile &tfile) { - return out << tfile.get_filename(); -} - -#include "p3dTemporaryFile.I" - -#endif diff --git a/direct/src/plugin/p3dUndefinedObject.cxx b/direct/src/plugin/p3dUndefinedObject.cxx deleted file mode 100644 index 0ed227573f..0000000000 --- a/direct/src/plugin/p3dUndefinedObject.cxx +++ /dev/null @@ -1,46 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dUndefinedObject.cxx - * @author drose - * @date 2009-07-07 - */ - -#include "p3dUndefinedObject.h" - -/** - * - */ -P3DUndefinedObject:: -P3DUndefinedObject() { -} - -/** - * Returns the fundamental type of this kind of object. - */ -P3D_object_type P3DUndefinedObject:: -get_type() { - return P3D_OT_undefined; -} - -/** - * Returns the object value coerced to a boolean, if possible. - */ -bool P3DUndefinedObject:: -get_bool() { - return false; -} - -/** - * Fills the indicated C++ string object with the value of this object coerced - * to a string. - */ -void P3DUndefinedObject:: -make_string(std::string &value) { - value = "Undefined"; -} diff --git a/direct/src/plugin/p3dUndefinedObject.h b/direct/src/plugin/p3dUndefinedObject.h deleted file mode 100644 index 3cba1d73b4..0000000000 --- a/direct/src/plugin/p3dUndefinedObject.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dUndefinedObject.h - * @author drose - * @date 2009-07-07 - */ - -#ifndef P3DUNDEFINEDOBJECT_H -#define P3DUNDEFINEDOBJECT_H - -#include "p3d_plugin_common.h" -#include "p3dObject.h" - -/** - * An object type that represents an undefined value. Python doesn't have - * such a concept, but JavaScript does, and it is sometimes an important - * return value. - */ -class P3DUndefinedObject : public P3DObject { -public: - P3DUndefinedObject(); - -public: - virtual P3D_object_type get_type(); - virtual bool get_bool(); - virtual void make_string(std::string &value); -}; - -#endif diff --git a/direct/src/plugin/p3dWinSplashWindow.I b/direct/src/plugin/p3dWinSplashWindow.I deleted file mode 100644 index bae5fb0680..0000000000 --- a/direct/src/plugin/p3dWinSplashWindow.I +++ /dev/null @@ -1,29 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dWinSplashWindow.I - * @author drose - * @date 2009-06-17 - */ - -/** - * - */ -inline P3DWinSplashWindow::WinImageData:: -WinImageData() { - _filename_changed = false; - _bitmap = nullptr; -} - -/** - * - */ -inline P3DWinSplashWindow::WinImageData:: -~WinImageData() { - dump_image(); -} diff --git a/direct/src/plugin/p3dWinSplashWindow.cxx b/direct/src/plugin/p3dWinSplashWindow.cxx deleted file mode 100644 index 256acb5eb8..0000000000 --- a/direct/src/plugin/p3dWinSplashWindow.cxx +++ /dev/null @@ -1,926 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dWinSplashWindow.cxx - * @author drose - * @date 2009-06-17 - */ - -#include "p3dWinSplashWindow.h" - -#ifdef _WIN32 - -#ifndef WM_MOUSEWHEEL -#define WM_MOUSEWHEEL 0x20a -#endif - -bool P3DWinSplashWindow::_registered_window_class = false; - -/** - * - */ -P3DWinSplashWindow:: -P3DWinSplashWindow(P3DInstance *inst, bool make_visible) : - P3DSplashWindow(inst, make_visible) -{ - _thread = nullptr; - _thread_id = 0; - _hwnd = nullptr; - _font = nullptr; - _fg_brush = nullptr; - _bg_brush = nullptr; - _bar_brush = nullptr; - _bar_bg_brush = nullptr; - _thread_running = false; - _install_progress = 0.0; - _progress_known = true; - _received_data = 0; - - _drawn_bstate = BS_hidden; - _drawn_progress = 0.0; - _drawn_progress_known = true; - _drawn_received_data = 0; - _focus_seq = 0; - - _request_focus_tick = 0; - - INIT_LOCK(_install_lock); -} - -/** - * - */ -P3DWinSplashWindow:: -~P3DWinSplashWindow() { - stop_thread(); - - DESTROY_LOCK(_install_lock); -} - -/** - * Changes the window parameters, e.g. to resize or reposition the window; or - * sets the parameters for the first time, creating the initial window. - */ -void P3DWinSplashWindow:: -set_wparams(const P3DWindowParams &wparams) { - P3DSplashWindow::set_wparams(wparams); - - if (_thread_id == 0) { - start_thread(); - } -} - -/** - * Makes the splash window visible or invisible, so as not to compete with the - * embedded Panda window in the same space. - */ -void P3DWinSplashWindow:: -set_visible(bool visible) { - P3DSplashWindow::set_visible(visible); - - if (_visible) { - ShowWindow(_hwnd, SW_SHOWNORMAL); - } else { - ShowWindow(_hwnd, SW_HIDE); - } -} - -/** - * Specifies the name of a JPEG image file that is displayed in the center of - * the splash window. - */ -void P3DWinSplashWindow:: -set_image_filename(const std::string &image_filename, ImagePlacement image_placement) { - nout << "image_filename = " << image_filename << ", thread_id = " << _thread_id << "\n"; - WinImageData *image = nullptr; - switch (image_placement) { - case IP_background: - image = &_background_image; - break; - - case IP_button_ready: - image = &_button_ready_image; - set_button_range(_button_ready_image); - break; - - case IP_button_rollover: - image = &_button_rollover_image; - break; - - case IP_button_click: - image = &_button_click_image; - break; - } - if (image != nullptr) { - ACQUIRE_LOCK(_install_lock); - if (image->_filename != image_filename) { - image->_filename = image_filename; - image->_filename_changed = true; - } - RELEASE_LOCK(_install_lock); - } - - if (_thread_id != 0) { - // Post a silly message to spin the message loop. - PostThreadMessage(_thread_id, WM_USER, 0, 0); - - if (!_thread_running && _thread_continue) { - // The user must have closed the window. Let's shut down the instance, - // too. - _inst->request_stop_main_thread(); - } - } -} - -/** - * Specifies the text that is displayed above the install progress bar. - */ -void P3DWinSplashWindow:: -set_install_label(const std::string &install_label) { - ACQUIRE_LOCK(_install_lock); - if (_install_label != install_label) { - _install_label = install_label; - } - RELEASE_LOCK(_install_lock); - - if (_thread_id != 0) { - // Post a silly message to spin the message loop. - PostThreadMessage(_thread_id, WM_USER, 0, 0); - - if (!_thread_running && _thread_continue) { - // The user must have closed the window. Let's shut down the instance, - // too. - _inst->request_stop_main_thread(); - } - } -} - -/** - * Moves the install progress bar from 0.0 to 1.0. - */ -void P3DWinSplashWindow:: -set_install_progress(double install_progress, - bool is_progress_known, size_t received_data) { - ACQUIRE_LOCK(_install_lock); - _install_progress = install_progress; - _progress_known = is_progress_known; - _received_data = received_data; - RELEASE_LOCK(_install_lock); - - if (_thread_id != 0) { - // Post a silly message to spin the message loop. - PostThreadMessage(_thread_id, WM_USER, 0, 0); - - if (!_thread_running && _thread_continue) { - // The user must have closed the window. Let's shut down the instance, - // too. - _inst->request_stop_main_thread(); - } - } -} - -/** - * The Panda window is asking us to manage keyboard focus in proxy for it. - * This is used on Vista, where the Panda window may be disallowed from - * directly assigning itself keyboard focus. - */ -void P3DWinSplashWindow:: -request_keyboard_focus() { - // Store the time at which we last requested focus. - _request_focus_tick = GetTickCount(); - - // Increment the _focus_seq to tell the thread to call SetFocus(). - ACQUIRE_LOCK(_install_lock); - ++_focus_seq; - RELEASE_LOCK(_install_lock); - - if (_thread_id != 0) { - // Post a silly message to spin the message loop. - PostThreadMessage(_thread_id, WM_USER, 0, 0); - } -} - -/** - * Registers the window class for this window, if needed. - */ -void P3DWinSplashWindow:: -register_window_class() { - if (!_registered_window_class) { - HINSTANCE application = GetModuleHandle(nullptr); - - WNDCLASS wc; - ZeroMemory(&wc, sizeof(WNDCLASS)); - wc.lpfnWndProc = (WNDPROC)st_window_proc; - wc.hInstance = application; - wc.hCursor = LoadCursor(nullptr, IDC_ARROW); - wc.lpszClassName = "panda3d_splash"; - - if (!RegisterClass(&wc)) { - nout << "Could not register window class panda3d_splash\n"; - } - _registered_window_class = true; - } -} - -/** - * Unregisters the window class for this window. It is necessary to do this - * before unloading the DLL. - */ -void P3DWinSplashWindow:: -unregister_window_class() { - if (_registered_window_class) { - HINSTANCE application = GetModuleHandle(nullptr); - - if (!UnregisterClass("panda3d_splash", application)) { - nout << "Could not unregister window class panda3d_splash\n"; - } - _registered_window_class = false; - } -} - -/** - * Called when a button click by the user is detected in set_mouse_data(), - * this method simply turns around and notifies the instance. It's a virtual - * method to give subclasses a chance to redirect this message to the main - * thread or process, as necessary. - */ -void P3DWinSplashWindow:: -button_click_detected() { - P3DSplashWindow::button_click_detected(); -} - -/** - * Spawns the sub-thread. - */ -void P3DWinSplashWindow:: -start_thread() { - _thread_continue = true; - _thread_running = true; - _thread = CreateThread(nullptr, 0, &win_thread_run, this, 0, &_thread_id); - if (_thread == nullptr) { - // Thread never got started. - _thread_running = false; - } -} - -/** - * Terminates and joins the sub-thread. - */ -void P3DWinSplashWindow:: -stop_thread() { - _thread_continue = false; - - if (_thread_id != 0) { - // Post a silly message to spin the message loop. - PostThreadMessage(_thread_id, WM_USER, 0, 0); - } - - if (_thread != nullptr){ - // If the thread doesn't close right away, call PeekMessage() to check for - // Windows messages that the thread might be waiting for. - while (WaitForSingleObject(_thread, 200) == WAIT_TIMEOUT) { - MSG msg; - PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE | PM_NOYIELD); - nout << "Waiting for thread\n"; - } - - CloseHandle(_thread); - _thread = nullptr; - - // Now that the thread has exited, we can safely close its window. (We - // couldn't close the window in the thread, because that would cause a - // deadlock situation--the thread can't acknowledge the window closing - // until we spin the event loop in the parent thread.) - close_window(); - } -} - -/** - * The sub-thread's main run method. - */ -void P3DWinSplashWindow:: -thread_run() { - make_window(); - - int last_focus_seq = 0; - MSG msg; - int retval; - retval = GetMessage(&msg, nullptr, 0, 0); - while (retval != 0 && _thread_continue) { - if (retval == -1) { - nout << "Error processing message queue.\n"; - break; - } - TranslateMessage(&msg); - DispatchMessage(&msg); - - ACQUIRE_LOCK(_install_lock); - - update_image(_background_image); - update_image(_button_ready_image); - update_image(_button_rollover_image); - update_image(_button_click_image); - - if (_drawn_label != _install_label) { - // The label has changed. Redraw. - _drawn_label = _install_label; - InvalidateRect(_hwnd, nullptr, TRUE); - } - - // Also redraw when the progress bar changes. - bool needs_update_progress = false; - if (_progress_known != _drawn_progress_known) { - needs_update_progress = true; - } else if (_progress_known) { - if (_install_progress != _drawn_progress) { - needs_update_progress = true; - } - } else { - if (_received_data != _drawn_received_data) { - needs_update_progress = true; - } - } - if (needs_update_progress) { - _drawn_progress = _install_progress; - _drawn_progress_known = _progress_known; - _drawn_received_data = _received_data; - InvalidateRect(_hwnd, nullptr, TRUE); - } - - if (_drawn_bstate != _bstate) { - // The button has changed state. Redraw it. - _drawn_bstate = _bstate; - InvalidateRect(_hwnd, nullptr, TRUE); - } - - if (_focus_seq != last_focus_seq) { - last_focus_seq = _focus_seq; - if (SetFocus(_hwnd) == nullptr && GetLastError() != 0) { - nout << "SetFocus(" << _hwnd << ") failed: " << GetLastError() << "\n"; - } - } - - RELEASE_LOCK(_install_lock); - - retval = GetMessage(&msg, nullptr, 0, 0); - } - - // Tell our parent thread that we're done. - _thread_running = false; - - // Close the instance. - _inst->request_stop_sub_thread(); -} - -/** - * The OS-specific thread callback function. - */ -DWORD P3DWinSplashWindow:: -win_thread_run(LPVOID data) { - ((P3DWinSplashWindow *)data)->thread_run(); - return 0; -} - -/** - * Creates the window for displaying progress. Runs within the sub-thread. - */ -void P3DWinSplashWindow:: -make_window() { - register_window_class(); - HINSTANCE application = GetModuleHandle(nullptr); - - int width = 320; - int height = 240; - if (_wparams.get_win_width() != 0 && _wparams.get_win_height() != 0) { - width = _wparams.get_win_width(); - height = _wparams.get_win_height(); - } - - int x = _wparams.get_win_x(); - int y = _wparams.get_win_y(); - if (x == -1) x = CW_USEDEFAULT; - if (y == -1) y = CW_USEDEFAULT; - if (x == -2) x = (int)(0.5 * (GetSystemMetrics(SM_CXSCREEN) - width)); - if (y == -2) y = (int)(0.5 * (GetSystemMetrics(SM_CYSCREEN) - height)); - - if (_wparams.get_window_type() == P3D_WT_embedded) { - // Create an embedded window. - DWORD window_style = - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - - const P3D_window_handle &handle = _wparams.get_parent_window(); - assert(handle._window_handle_type == P3D_WHT_win_hwnd); - HWND parent_hwnd = handle._handle._win_hwnd._hwnd; - - _hwnd = - CreateWindow("panda3d_splash", "Panda3D", window_style, - x, y, width, height, - parent_hwnd, nullptr, application, 0); - - if (!_hwnd) { - nout << "Could not create embedded window!\n"; - return; - } - - } else { - // Create a toplevel window. - DWORD window_style = - WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | - WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | - WS_SIZEBOX | WS_MAXIMIZEBOX; - - RECT win_rect = { 0, 0, width, height }; - // Adjust window size based on desired client area size - AdjustWindowRect(&win_rect, window_style, FALSE); - _hwnd = - CreateWindow("panda3d_splash", "Panda3D", window_style, - x, y, - win_rect.right - win_rect.left, - win_rect.bottom - win_rect.top, - nullptr, nullptr, application, 0); - if (!_hwnd) { - nout << "Could not create toplevel window!\n"; - return; - } - } - SetWindowLongPtr(_hwnd, GWLP_USERDATA, (LONG_PTR)this); - nout << "Created splash window " << _hwnd << "\n"; - - if (_visible) { - ShowWindow(_hwnd, SW_SHOWNORMAL); - } else { - ShowWindow(_hwnd, SW_HIDE); - } - - // Load the requested font. - _font = CreateFontA(-_font_size, 0, 0, 0, _font_weight, - (_font_style != FS_normal), FALSE, FALSE, - ANSI_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, - CLEARTYPE_QUALITY, VARIABLE_PITCH, _font_family.c_str()); - - if (_font == nullptr) { - nout << "CreateFont failed: " << GetLastError() << "\n"; - _font = (HFONT)GetStockObject(ANSI_VAR_FONT); - } - - _fg_brush = CreateSolidBrush(RGB(_fgcolor_r, _fgcolor_g, _fgcolor_b)); - _bg_brush = CreateSolidBrush(RGB(_bgcolor_r, _bgcolor_g, _bgcolor_b)); - _bar_brush = CreateSolidBrush(RGB(_barcolor_r, _barcolor_g, _barcolor_b)); - _bar_bg_brush = CreateSolidBrush(RGB(_bar_bgcolor_r, _bar_bgcolor_g, _bar_bgcolor_b)); -} - -/** - * Loads the image from the named file (if it has changed), converts to to - * BITMAP form, and stores it in _bitmap. Runs only in the sub-thread. - */ -void P3DWinSplashWindow:: -update_image(WinImageData &image) { - if (!image._filename_changed) { - // No changes. - return; - } - image._filename_changed = false; - - // Clear the old image. - image.dump_image(); - - // Since we'll be displaying a new image, we need to refresh the window. - InvalidateRect(_hwnd, nullptr, TRUE); - - // Go read the image. - std::string data; - if (!read_image_data(image, data, image._filename)) { - return; - } - - // Massage the data into Windows' conventions. - int row_stride = image._width * image._num_channels; - int new_row_stride = (image._width * 4); - - int new_data_length = new_row_stride * image._height; - char *new_data = new char[new_data_length]; - - if (image._num_channels == 4) { - // We have to reverse the order of the RGB channels: libjpeg and Windows - // follow an opposite convention. - for (int yi = 0; yi < image._height; ++yi) { - const char *sp = data.data() + yi * row_stride; - char *dp = new_data + yi * new_row_stride; - for (int xi = 0; xi < image._width; ++xi) { - dp[0] = sp[2]; - dp[1] = sp[1]; - dp[2] = sp[0]; - dp[3] = sp[3]; - sp += 4; - dp += 4; - } - } - } else if (image._num_channels == 3) { - // We have to reverse the order of the RGB channels: libjpeg and Windows - // follow an opposite convention. - for (int yi = 0; yi < image._height; ++yi) { - const char *sp = data.data() + yi * row_stride; - char *dp = new_data + yi * new_row_stride; - for (int xi = 0; xi < image._width; ++xi) { - dp[0] = sp[2]; - dp[1] = sp[1]; - dp[2] = sp[0]; - dp[3] = (char)0xff; - sp += 3; - dp += 4; - } - } - } else if (image._num_channels == 1) { - // A grayscale image. Replicate out the channels. - for (int yi = 0; yi < image._height; ++yi) { - const char *sp = data.data() + yi * row_stride; - char *dp = new_data + yi * new_row_stride; - for (int xi = 0; xi < image._width; ++xi) { - dp[0] = sp[0]; - dp[1] = sp[0]; - dp[2] = sp[0]; - dp[3] = (char)0xff; - sp += 1; - dp += 4; - } - } - } - - // Now load the image. - BITMAPINFOHEADER bmih; - bmih.biSize = sizeof(bmih); - bmih.biWidth = image._width; - bmih.biHeight = -image._height; - bmih.biPlanes = 1; - bmih.biBitCount = 32; - bmih.biCompression = BI_RGB; - bmih.biSizeImage = 0; - bmih.biXPelsPerMeter = 0; - bmih.biYPelsPerMeter = 0; - bmih.biClrUsed = 0; - bmih.biClrImportant = 0; - - BITMAPINFO bmi; - memcpy(&bmi, &bmih, sizeof(bmih)); - - HDC dc = GetDC(_hwnd); - image._bitmap = CreateDIBitmap(dc, &bmih, CBM_INIT, new_data, &bmi, 0); - ReleaseDC(_hwnd, dc); - - delete[] new_data; - - nout << "Loaded image: " << image._filename << "\n"; -} - -/** - * Closes the window created above. This call is actually made in the main - * thread. - */ -void P3DWinSplashWindow:: -close_window() { - if (_hwnd != nullptr) { - ShowWindow(_hwnd, SW_HIDE); - CloseWindow(_hwnd); - _hwnd = nullptr; - } - - if (_fg_brush != nullptr) { - DeleteObject(_fg_brush); - _fg_brush = nullptr; - } - if (_bg_brush != nullptr) { - DeleteObject(_bg_brush); - _bg_brush = nullptr; - } - if (_bar_brush != nullptr) { - DeleteObject(_bar_brush); - _bar_brush = nullptr; - } - if (_bar_bg_brush != nullptr) { - DeleteObject(_bar_bg_brush); - _bar_bg_brush = nullptr; - } - - _background_image.dump_image(); - _button_ready_image.dump_image(); - _button_rollover_image.dump_image(); - _button_click_image.dump_image(); -} - -/** - * Paints the contents of the window into the indicated DC. - */ -void P3DWinSplashWindow:: -paint_window(HDC dc) { - RECT rect; - GetClientRect(_hwnd, &rect); - - int width = rect.right - rect.left; - int height = rect.bottom - rect.top; - if (width != _win_width || height != _win_height) { - _win_width = width; - _win_height = height; - set_button_range(_button_ready_image); - } - - // Double-buffer with an offscreen bitmap first. - HDC bdc = CreateCompatibleDC(dc); - HBITMAP buffer = CreateCompatibleBitmap(dc, _win_width, _win_height); - SelectObject(bdc, buffer); - - // Start by painting the background color. - FillRect(bdc, &rect, _bg_brush); - - // Then paint the background image on top of that. - paint_image(bdc, _background_image, false); - - // And then, paint the button, if any, on top of *that*. - switch (_drawn_bstate) { - case BS_hidden: - break; - case BS_ready: - paint_image(bdc, _button_ready_image, true); - break; - case BS_rollover: - if (!paint_image(bdc, _button_rollover_image, true)) { - paint_image(bdc, _button_ready_image, true); - } - break; - case BS_click: - if (!paint_image(bdc, _button_click_image, true)) { - paint_image(bdc, _button_ready_image, true); - } - break; - } - - // Draw the progress bar. We don't draw this bar at all unless we have - // nonzero progress. - if (!_drawn_progress_known || _drawn_progress != 0.0) { - paint_progress_bar(bdc); - } - - // Now blit the buffer to the window. - BitBlt(dc, 0, 0, _win_width, _win_height, bdc, 0, 0, SRCCOPY); - - DeleteObject(bdc); - DeleteObject(buffer); -} - -/** - * Draws the indicated image, centered within the window. Returns true on - * success, false if the image is not defined. - */ -bool P3DWinSplashWindow:: -paint_image(HDC dc, const WinImageData &image, bool use_alpha) { - if (image._bitmap == nullptr) { - return false; - } - - // Paint the background splash image. - HDC mem_dc = CreateCompatibleDC(dc); - SelectObject(mem_dc, image._bitmap); - - // Determine the relative size of bitmap and window. - int win_cx = _win_width / 2; - int win_cy = _win_height / 2; - - BLENDFUNCTION bf; - bf.BlendOp = AC_SRC_OVER; - bf.BlendFlags = 0; - bf.SourceConstantAlpha = 0xff; - bf.AlphaFormat = AC_SRC_ALPHA; - - if (image._width <= _win_width && image._height <= _win_height) { - // The bitmap fits within the window; center it. - - // This is the top-left corner of the bitmap in window coordinates. - int p_x = win_cx - image._width / 2; - int p_y = win_cy - image._height / 2; - - if (!use_alpha) { - BitBlt(dc, p_x, p_y, image._width, image._height, - mem_dc, 0, 0, SRCCOPY); - } else { - AlphaBlend(dc, p_x, p_y, image._width, image._height, - mem_dc, 0, 0, image._width, image._height, - bf); - } - - } else { - // The bitmap is larger than the window; scale it down. - double x_scale = (double)_win_width / (double)image._width; - double y_scale = (double)_win_height / (double)image._height; - double scale = std::min(x_scale, y_scale); - int sc_width = (int)(image._width * scale); - int sc_height = (int)(image._height * scale); - - int p_x = win_cx - sc_width / 2; - int p_y = win_cy - sc_height / 2; - - if (!use_alpha) { - StretchBlt(dc, p_x, p_y, sc_width, sc_height, - mem_dc, 0, 0, image._width, image._height, SRCCOPY); - } else { - // For some reason, AlphaBlend has issues when scaling a black-and-white - // image to draw onto the window: it draws the image in the last fill - // color used on the dc, instead of black. This only happens when the - // image consists only of black and white, and only when the image is - // being scaled. Weird. But StretchBlt, above, doesn't have this - // problem. - AlphaBlend(dc, p_x, p_y, sc_width, sc_height, - mem_dc, 0, 0, image._width, image._height, - bf); - } - } - - SelectObject(mem_dc, nullptr); - DeleteDC(mem_dc); - - return true; -} - -/** - * Draws the progress bar and the label within the window. - */ -void P3DWinSplashWindow:: -paint_progress_bar(HDC dc) { - int bar_x, bar_y, bar_width, bar_height; - get_bar_placement(bar_x, bar_y, bar_width, bar_height); - - RECT bar_rect = { bar_x, bar_y, bar_x + bar_width, bar_y + bar_height }; - - // Clear the entire progress bar to white (or the background color). - FillRect(dc, &bar_rect, _bar_bg_brush); - - // Draw the interior of the progress bar in blue (or the bar color). - if (_drawn_progress_known) { - int progress_width = (int)(bar_width * _drawn_progress + 0.5); - if (progress_width != 0) { - RECT prog_rect = { bar_x, bar_y, bar_x + progress_width, bar_y + bar_height }; - FillRect(dc, &prog_rect, _bar_brush); - } - } else { - // Progress is unknown. Draw a moving block, not a progress bar filling - // up. - int block_width = (int)(bar_width * 0.1 + 0.5); - int block_travel = bar_width - block_width; - int progress = (int)(_received_data * _unknown_progress_rate); - progress = progress % (block_travel * 2); - if (progress > block_travel) { - progress = block_travel * 2 - progress; - } - - RECT prog_rect = { bar_x + progress, bar_y, - bar_x + progress + block_width, bar_y + bar_height }; - FillRect(dc, &prog_rect, _bar_brush); - } - - // Now draw a black (or foreground) border around the progress bar. - if (_bar_border >= 0) { - RECT border_rect = bar_rect; - - for (int i = 0; i < _bar_border; ++i) { - --border_rect.left; - --border_rect.top; - ++border_rect.right; - ++border_rect.bottom; - FrameRect(dc, &border_rect, _fg_brush); - } - } - - if (!_drawn_label.empty()) { - // Now draw the install_label right above it. - const char *text = _drawn_label.c_str(); - - // Measure the text, for centering. - SelectObject(dc, _font); - SIZE text_size; - GetTextExtentPoint32(dc, text, strlen(text), &text_size); - - int text_width = text_size.cx; - int text_height = text_size.cy; - int text_x = (_win_width - text_width) / 2; - int text_y = bar_y - (int)(text_height * 1.5) - _bar_border; - - // Clear the rectangle behind the text to white. - RECT text_rect = { text_x - 2, text_y - 2, text_x + text_width + 4, text_y + text_height + 4 }; - - FillRect(dc, &text_rect, _bg_brush); - - // And finally, draw the text. - SetTextColor(dc, RGB(_fgcolor_r, _fgcolor_g, _fgcolor_b)); - SetBkColor(dc, RGB(_bgcolor_r, _bgcolor_g, _bgcolor_b)); - DrawText(dc, text, -1, &text_rect, - DT_VCENTER | DT_CENTER | DT_SINGLELINE); - } -} - -/** - * The windows event-processing handler. - */ -LRESULT P3DWinSplashWindow:: -window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - switch (msg) { - case WM_DESTROY: - PostQuitMessage(0); - break; - - case WM_SIZE: - InvalidateRect(hwnd, nullptr, FALSE); - break; - - case WM_ERASEBKGND: - return true; - - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC dc = BeginPaint(hwnd, &ps); - paint_window(dc); - EndPaint(hwnd, &ps); - } - return true; - - case WM_MOUSEMOVE: - set_mouse_data(LOWORD(lparam), HIWORD(lparam), _mouse_down); - break; - - case WM_LBUTTONDOWN: - SetCapture(hwnd); - set_mouse_data(_mouse_x, _mouse_y, true); - break; - - case WM_LBUTTONUP: - set_mouse_data(_mouse_x, _mouse_y, false); - ReleaseCapture(); - break; - - case WM_KILLFOCUS: - // Someone on the desktop is playing games with us. It keeps wanting to - // grab the keyboard focus back immediately after we successfully call - // SetFocus(). Well, we really mean it, darn it all. If we got a - // WM_KILLFOCUS within a few milliseconds of calling SetFocus(), well, - // call SetFocus() again, until it sticks. - { - int elapsed = GetTickCount() - _request_focus_tick; - if (elapsed < 200) { - if (SetFocus(_hwnd) == nullptr && GetLastError() != 0) { - nout << "Secondary SetFocus failed: " << GetLastError() << "\n"; - } - } - } - break; - - // Keyboard events that are to be proxied to the Panda window. - case WM_MOUSEWHEEL: - case WM_IME_SETCONTEXT: - case WM_IME_NOTIFY: - case WM_IME_STARTCOMPOSITION: - case WM_IME_ENDCOMPOSITION: - case WM_IME_COMPOSITION: - case WM_CHAR: - case WM_SYSKEYDOWN: - case WM_SYSCOMMAND: - case WM_KEYDOWN: - case WM_SYSKEYUP: - case WM_KEYUP: - if (_inst->get_session() != nullptr) { - _inst->get_session()->send_windows_message(_inst, msg, wparam, lparam); - } - break; - }; - - return DefWindowProc(hwnd, msg, wparam, lparam); -} - -/** - * The windows event-processing handler, static version. - */ -LRESULT P3DWinSplashWindow:: -st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - LONG_PTR self = GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (self == nullptr) { - // We haven't assigned the pointer yet. - return DefWindowProc(hwnd, msg, wparam, lparam); - } - - return ((P3DWinSplashWindow *)self)->window_proc(hwnd, msg, wparam, lparam); -} - -/** - * Frees the previous image data. - */ -void P3DWinSplashWindow::WinImageData:: -dump_image() { - if (_bitmap != nullptr) { - DeleteObject(_bitmap); - _bitmap = nullptr; - } -} - -#endif // _WIN32 diff --git a/direct/src/plugin/p3dWinSplashWindow.h b/direct/src/plugin/p3dWinSplashWindow.h deleted file mode 100644 index 713157c921..0000000000 --- a/direct/src/plugin/p3dWinSplashWindow.h +++ /dev/null @@ -1,122 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dWinSplashWindow.h - * @author drose - * @date 2009-06-17 - */ - -#ifndef P3DWINSPLASHWINDOW_H -#define P3DWINSPLASHWINDOW_H - -#include "p3d_plugin_common.h" - -#ifdef _WIN32 - -#include "p3dSplashWindow.h" -#include "p3d_lock.h" - -#include - -/** - * This is the Windows implementation of the initial-download window. - */ -class P3DWinSplashWindow : public P3DSplashWindow { -public: - P3DWinSplashWindow(P3DInstance *inst, bool make_visible); - virtual ~P3DWinSplashWindow(); - - virtual void set_wparams(const P3DWindowParams &wparams); - virtual void set_visible(bool visible); - - virtual void set_image_filename(const std::string &image_filename, - ImagePlacement image_placement); - virtual void set_install_label(const std::string &install_label); - virtual void set_install_progress(double install_progress, - bool is_progress_known, size_t received_data); - virtual void request_keyboard_focus(); - - static void register_window_class(); - static void unregister_window_class(); - -protected: - virtual void button_click_detected(); - -private: - void start_thread(); - void stop_thread(); - -private: - class WinImageData; - - // These methods run only within the window thread. - void thread_run(); - static DWORD WINAPI win_thread_run(LPVOID data); - - void make_window(); - void update_image(WinImageData &image); - void close_window(); - - void paint_window(HDC dc); - bool paint_image(HDC dc, const WinImageData &image, bool use_alpha); - void paint_progress_bar(HDC dc); - LRESULT window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); - static LRESULT WINAPI st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); - -private: - class WinImageData : public ImageData { - public: - inline WinImageData(); - inline ~WinImageData(); - void dump_image(); - - std::string _filename; - bool _filename_changed; - HBITMAP _bitmap; - }; - - WinImageData _background_image; - WinImageData _button_ready_image; - WinImageData _button_rollover_image; - WinImageData _button_click_image; - - bool _got_install; - std::string _install_label; - double _install_progress; - bool _progress_known; - size_t _received_data; - LOCK _install_lock; - - ButtonState _drawn_bstate; - std::string _drawn_label; - double _drawn_progress; - bool _drawn_progress_known; - size_t _drawn_received_data; - int _focus_seq; - - int _request_focus_tick; - - bool _thread_continue; - bool _thread_running; - HANDLE _thread; - DWORD _thread_id; - HWND _hwnd; - HFONT _font; - HBRUSH _fg_brush; - HBRUSH _bg_brush; - HBRUSH _bar_brush; - HBRUSH _bar_bg_brush; - - static bool _registered_window_class; -}; - -#include "p3dWinSplashWindow.I" - -#endif // _WIN32 - -#endif diff --git a/direct/src/plugin/p3dWindowParams.I b/direct/src/plugin/p3dWindowParams.I deleted file mode 100644 index 667d94210a..0000000000 --- a/direct/src/plugin/p3dWindowParams.I +++ /dev/null @@ -1,69 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dWindowParams.I - * @author drose - * @date 2009-06-22 - */ - -/** - * Returns the window_type that was passed to the constructor, or to - * set_window_type(). - */ -inline P3D_window_type P3DWindowParams:: -get_window_type() const { - return _window_type; -} - -/** - * Changes the window_type. - */ -inline void P3DWindowParams:: -set_window_type(P3D_window_type window_type) { - _window_type = window_type; -} - -/** - * Returns the window origin X coordinate that was passed to the constructor. - */ -inline int P3DWindowParams:: -get_win_x() const { - return _win_x; -} - -/** - * Returns the window origin Y coordinate that was passed to the constructor. - */ -inline int P3DWindowParams:: -get_win_y() const { - return _win_y; -} - -/** - * Returns the window width that was passed to the constructor. - */ -inline int P3DWindowParams:: -get_win_width() const { - return _win_width; -} - -/** - * Returns the window height that was passed to the constructor. - */ -inline int P3DWindowParams:: -get_win_height() const { - return _win_height; -} - -/** - * Returns the parent window handle that was passed to the constructor. - */ -inline const P3D_window_handle &P3DWindowParams:: -get_parent_window() const { - return _parent_window; -} diff --git a/direct/src/plugin/p3dWindowParams.cxx b/direct/src/plugin/p3dWindowParams.cxx deleted file mode 100644 index 29ed954823..0000000000 --- a/direct/src/plugin/p3dWindowParams.cxx +++ /dev/null @@ -1,109 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dWindowParams.cxx - * @author drose - * @date 2009-06-22 - */ - -#include "p3dWindowParams.h" - -/** - * - */ -P3DWindowParams:: -P3DWindowParams() : - _window_type(P3D_WT_hidden), - _win_x(-1), _win_y(-1), - _win_width(0), _win_height(0) -{ -} - -/** - * - */ -P3DWindowParams:: -P3DWindowParams(P3D_window_type window_type, - int win_x, int win_y, - int win_width, int win_height, - P3D_window_handle parent_window) : - _window_type(window_type), - _win_x(win_x), _win_y(win_y), - _win_width(win_width), _win_height(win_height), - _parent_window(parent_window) -{ -} - -/** - * - */ -void P3DWindowParams:: -operator = (const P3DWindowParams &other) { - _window_type = other._window_type; - _win_x = other._win_x; - _win_y = other._win_y; - _win_width = other._win_width; - _win_height = other._win_height; - _parent_window = other._parent_window; -} - -/** - * Returns a newly-allocated XML structure that corresponds to the window - * parameter data within this instance. - */ -TiXmlElement *P3DWindowParams:: -make_xml(P3DInstance *inst) { - TiXmlElement *xwparams = new TiXmlElement("wparams"); - - switch (_window_type) { - case P3D_WT_embedded: - xwparams->SetAttribute("window_type", "embedded"); - xwparams->SetAttribute("win_x", _win_x); - xwparams->SetAttribute("win_y", _win_y); - xwparams->SetAttribute("win_width", _win_width); - xwparams->SetAttribute("win_height", _win_height); -#ifdef _WIN32 - assert(_parent_window._window_handle_type == P3D_WHT_win_hwnd); - xwparams->SetAttribute("parent_hwnd", (int)_parent_window._handle._win_hwnd._hwnd); - -#elif defined(__APPLE__) - xwparams->SetAttribute("subprocess_window", inst->_shared_filename); - -#elif defined(HAVE_X11) - // TinyXml doesn't support a "long" attribute. We'll use stringstream to - // do it ourselves. - { - std::ostringstream strm; - assert(_parent_window._window_handle_type == P3D_WHT_x11_window); - strm << _parent_window._handle._x11_window._xwindow; - xwparams->SetAttribute("parent_xwindow", strm.str()); - } -#endif - break; - - case P3D_WT_toplevel: - xwparams->SetAttribute("window_type", "toplevel"); - xwparams->SetAttribute("win_x", _win_x); - xwparams->SetAttribute("win_y", _win_y); - xwparams->SetAttribute("win_width", _win_width); - xwparams->SetAttribute("win_height", _win_height); - break; - - case P3D_WT_fullscreen: - xwparams->SetAttribute("window_type", "fullscreen"); - xwparams->SetAttribute("win_width", _win_width); - xwparams->SetAttribute("win_height", _win_height); - break; - - case P3D_WT_hidden: - xwparams->SetAttribute("window_type", "hidden"); - break; - } - - return xwparams; -} diff --git a/direct/src/plugin/p3dWindowParams.h b/direct/src/plugin/p3dWindowParams.h deleted file mode 100644 index 91d8639b28..0000000000 --- a/direct/src/plugin/p3dWindowParams.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dWindowParams.h - * @author drose - * @date 2009-06-22 - */ - -#ifndef P3DWINDOWPARAMS_H -#define P3DWINDOWPARAMS_H - -#include "p3d_plugin_common.h" -#include "get_tinyxml.h" - -class P3DInstance *inst; - -/** - * Encapsulates the window parameters. - */ -class P3DWindowParams { -public: - P3DWindowParams(); - P3DWindowParams(P3D_window_type window_type, - int win_x, int win_y, - int win_width, int win_height, - P3D_window_handle parent_window); - - void operator = (const P3DWindowParams &other); - - inline P3D_window_type get_window_type() const; - inline void set_window_type(P3D_window_type window_type); - - inline int get_win_x() const; - inline int get_win_y() const; - inline int get_win_width() const; - inline int get_win_height() const; - inline const P3D_window_handle &get_parent_window() const; - - TiXmlElement *make_xml(P3DInstance *inst); - -private: - P3D_window_type _window_type; - int _win_x, _win_y; - int _win_width, _win_height; - P3D_window_handle _parent_window; -}; - -#include "p3dWindowParams.I" - -#endif diff --git a/direct/src/plugin/p3dX11SplashWindow.I b/direct/src/plugin/p3dX11SplashWindow.I deleted file mode 100644 index 22407f96ed..0000000000 --- a/direct/src/plugin/p3dX11SplashWindow.I +++ /dev/null @@ -1,27 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dX11SplashWindow.I - * @author drose - * @date 2009-09-08 - */ - -/** - * - */ -inline P3DX11SplashWindow::X11ImageData:: -X11ImageData() { - _filename_changed = false; -} - -/** - * - */ -inline P3DX11SplashWindow::X11ImageData:: -~X11ImageData() { -} diff --git a/direct/src/plugin/p3dX11SplashWindow.cxx b/direct/src/plugin/p3dX11SplashWindow.cxx deleted file mode 100644 index 07e5fc4d99..0000000000 --- a/direct/src/plugin/p3dX11SplashWindow.cxx +++ /dev/null @@ -1,1394 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dX11SplashWindow.cxx - * @author rdb - * @date 2009-07-08 - */ - -#include "p3dX11SplashWindow.h" - -#ifdef HAVE_X11 - -#include "get_tinyxml.h" -#include "binaryXml.h" -#include -#include -#include -#include -#include -#include - -using std::string; -using std::vector; - -/** - * - */ -P3DX11SplashWindow:: -P3DX11SplashWindow(P3DInstance *inst, bool make_visible) : - P3DSplashWindow(inst, make_visible) -{ - // Init for parent process - _subprocess_pid = -1; - - // Init for read thread - _started_read_thread = false; - INIT_THREAD(_read_thread); - - // Init for subprocess - _composite_image = nullptr; - _needs_new_composite = false; - _display = None; - _window = None; - _screen = 0; - _font = nullptr; - _graphics_context = None; - _bar_context = None; - _bar_bg_context = None; - _fg_pixel = -1; - _bg_pixel = -1; - _bar_pixel = -1; - _bar_bg_pixel = -1; - _own_display = false; - _install_progress = 0.0; - _progress_known = true; - _received_data = 0; -} - -/** - * - */ -P3DX11SplashWindow:: -~P3DX11SplashWindow() { - stop_subprocess(); -} - -/** - * Changes the window parameters, e.g. to resize or reposition the window; or - * sets the parameters for the first time, creating the initial window. - */ -void P3DX11SplashWindow:: -set_wparams(const P3DWindowParams &wparams) { - P3DSplashWindow::set_wparams(wparams); - - if (_subprocess_pid == -1) { - start_subprocess(); - } -} - -/** - * Makes the splash window visible or invisible, so as not to compete with the - * embedded Panda window in the same space. - */ -void P3DX11SplashWindow:: -set_visible(bool visible) { - P3DSplashWindow::set_visible(visible); - - TiXmlDocument doc; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "set_visible"); - xcommand->SetAttribute("visible", (int)_visible); - doc.LinkEndChild(xcommand); - write_xml(_pipe_write, &doc, nout); -} - -/** - * Specifies the name of a JPEG image file that is displayed in the center of - * the splash window. - */ -void P3DX11SplashWindow:: -set_image_filename(const string &image_filename, ImagePlacement image_placement) { - nout << "image_filename = " << image_filename << "\n"; - if (_subprocess_pid == -1) { - return; - } - - TiXmlDocument doc; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "set_image_filename"); - xcommand->SetAttribute("image_filename", image_filename); - xcommand->SetAttribute("image_placement", (int)image_placement); - doc.LinkEndChild(xcommand); - write_xml(_pipe_write, &doc, nout); - - check_stopped(); -} - -/** - * Specifies the text that is displayed above the install progress bar. - */ -void P3DX11SplashWindow:: -set_install_label(const string &install_label) { - if (_subprocess_pid == -1) { - return; - } - - TiXmlDocument doc; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "set_install_label"); - xcommand->SetAttribute("install_label", install_label); - doc.LinkEndChild(xcommand); - write_xml(_pipe_write, &doc, nout); - - check_stopped(); -} - -/** - * Moves the install progress bar from 0.0 to 1.0. - */ -void P3DX11SplashWindow:: -set_install_progress(double install_progress, - bool is_progress_known, size_t received_data) { - if (_subprocess_pid == -1) { - return; - } - - TiXmlDocument doc; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "set_install_progress"); - xcommand->SetDoubleAttribute("install_progress", install_progress); - xcommand->SetAttribute("progress_known", (int)is_progress_known); - xcommand->SetAttribute("received_data", (int)received_data); - doc.LinkEndChild(xcommand); - write_xml(_pipe_write, &doc, nout); - - check_stopped(); -} - -/** - * Sets whether the button should be visible and active (true) or invisible - * and inactive (false). If active, the button image will be displayed in the - * window, and a click event will be generated when the user clicks the - * button. - */ -void P3DX11SplashWindow:: -set_button_active(bool flag) { - if (_subprocess_pid == -1) { - return; - } - - TiXmlDocument doc; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "set_button_active"); - xcommand->SetAttribute("button_active", (int)flag); - doc.LinkEndChild(xcommand); - write_xml(_pipe_write, &doc, nout); - - check_stopped(); -} - -/** - * Called when a button click by the user is detected in set_mouse_data(), - * this method simply turns around and notifies the instance. It's a virtual - * method to give subclasses a chance to redirect this message to the main - * thread or process, as necessary. - */ -void P3DX11SplashWindow:: -button_click_detected() { - // This method is called in the child process, and must relay the - // information to the parent process. - TiXmlDocument doc; - TiXmlElement *xcommand = new TiXmlElement("click"); - doc.LinkEndChild(xcommand); - write_xml(_pipe_write, &doc, nout); -} - -/** - * Changes the button state as the mouse interacts with it. - */ -void P3DX11SplashWindow:: -set_bstate(ButtonState bstate) { - if (_bstate != bstate) { - // When the button state changes, we need to remake the composite image. - _needs_new_composite = true; - P3DSplashWindow::set_bstate(bstate); - } -} - -/** - * Spawns the subprocess that runs the window. We have to use a subprocess - * instead of just a sub-thread, to protect X11 against mutual access. - */ -void P3DX11SplashWindow:: -start_subprocess() { - assert(_subprocess_pid == -1); - - // Create a bi-directional pipe to communicate with the sub-process. - int to_fd[2]; - if (pipe(to_fd) < 0) { - perror("failed to create pipe"); - } - int from_fd[2]; - if (pipe(from_fd) < 0) { - perror("failed to create pipe"); - } - - // Fork and exec. - pid_t child = fork(); - if (child < 0) { - close(to_fd[0]); - close(to_fd[1]); - close(from_fd[0]); - close(from_fd[1]); - perror("fork"); - return; - } - - if (child == 0) { - // Here we are in the child process. - init_xml(); - - // Open the read end of the pipe, and close the write end. - _pipe_read.open_read(to_fd[0]); - close(to_fd[1]); - _pipe_write.open_write(from_fd[1]); - close(from_fd[0]); - - subprocess_run(); - _exit(0); - } - - // In the parent process. - _subprocess_pid = child; - _pipe_write.open_write(to_fd[1]); - close(to_fd[0]); - _pipe_read.open_read(from_fd[0]); - close(from_fd[1]); - - spawn_read_thread(); -} - -/** - * Terminates the subprocess. - */ -void P3DX11SplashWindow:: -stop_subprocess() { - if (_subprocess_pid == -1) { - // Already stopped. - return; - } - - // Ask the subprocess to stop. - TiXmlDocument doc; - TiXmlElement *xcommand = new TiXmlElement("command"); - xcommand->SetAttribute("cmd", "exit"); - doc.LinkEndChild(xcommand); - write_xml(_pipe_write, &doc, nout); - - // Also close the pipe, to help underscore the point. - _pipe_write.close(); - - static const int max_wait_ms = 2000; - - // Wait for a certain amount of time for the process to stop by itself. - struct timeval start; - gettimeofday(&start, nullptr); - int start_ms = start.tv_sec * 1000 + start.tv_usec / 1000; - - int status; - pid_t result = waitpid(_subprocess_pid, &status, WNOHANG); - while (result != _subprocess_pid) { - if (result == -1) { - perror("waitpid"); - break; - } - - struct timeval now; - gettimeofday(&now, nullptr); - int now_ms = now.tv_sec * 1000 + now.tv_usec / 1000; - int elapsed = now_ms - start_ms; - - if (elapsed > max_wait_ms) { - // Tired of waiting. Kill the process. - nout << "Force-killing splash window process, pid " << _subprocess_pid - << "\n"; - kill(_subprocess_pid, SIGKILL); - start_ms = now_ms; - } - - // Yield the timeslice and wait some more. - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1; - select(0, nullptr, nullptr, nullptr, &tv); - result = waitpid(_subprocess_pid, &status, WNOHANG); - } - - nout << "Splash window process has successfully stopped.\n"; - if (WIFEXITED(status)) { - nout << " exited normally, status = " - << WEXITSTATUS(status) << "\n"; - } else if (WIFSIGNALED(status)) { - nout << " signalled by " << WTERMSIG(status) << ", core = " - << WCOREDUMP(status) << "\n"; - } else if (WIFSTOPPED(status)) { - nout << " stopped by " << WSTOPSIG(status) << "\n"; - } - - join_read_thread(); -} - -/** - * Shuts down the instance if the window is closed prematurely (for instance, - * due to user action). - */ -void P3DX11SplashWindow:: -check_stopped() { - if (_subprocess_pid == -1) { - // Already stopped. - return; - } - - int status; - int result = waitpid(_subprocess_pid, &status, WNOHANG); - if (result == 0) { - // Process is still running. - return; - } - - if (result == -1) { - // Error in waitpid. - perror("waitpid"); - return; - } - - // Process has stopped. - assert(result == _subprocess_pid); - - nout << "Splash window process has stopped unexpectedly.\n"; - if (WIFEXITED(status)) { - nout << " exited normally, status = " - << WEXITSTATUS(status) << "\n"; - } else if (WIFSIGNALED(status)) { - nout << " signalled by " << WTERMSIG(status) << ", core = " - << WCOREDUMP(status) << "\n"; - } else if (WIFSTOPPED(status)) { - nout << " stopped by " << WSTOPSIG(status) << "\n"; - } - - _subprocess_pid = -1; - join_read_thread(); - - _inst->request_stop_main_thread(); -} - -/** - * Starts the read thread. We need this thread to listen for feedback from - * the subprocess. (At the moment, the only kind of feedback we might receive - * is whether the button has been clicked.) - */ -void P3DX11SplashWindow:: -spawn_read_thread() { - SPAWN_THREAD(_read_thread, rt_thread_run, this); - _started_read_thread = true; -} - -/** - * Waits for the read thread to stop. - */ -void P3DX11SplashWindow:: -join_read_thread() { - if (!_started_read_thread) { - return; - } - - JOIN_THREAD(_read_thread); - _started_read_thread = false; -} - -/** - * The main function for the read thread. - */ -void P3DX11SplashWindow:: -rt_thread_run() { - while (true) { - TiXmlDocument *doc = read_xml(_pipe_read, nout); - if (doc == nullptr) { - // Some error on reading. The splash window must have gone away, e.g. - // because the user explicitly closed it; tell the instance to exit. - _inst->request_stop_sub_thread(); - return; - } - - // Successfully read an XML document. - rt_handle_request(doc); - } -} - -/** - * Processes a single request or notification received from an instance. - */ -void P3DX11SplashWindow:: -rt_handle_request(TiXmlDocument *doc) { - // Eh, don't even bother decoding the XML. We know it can only be a click - // notification. - delete doc; - - P3DSplashWindow::button_click_detected(); -} - -/** - * The subprocess's main run method. - */ -void P3DX11SplashWindow:: -subprocess_run() { - // Since we're now isolated in a subprocess, we can safely make all the X - // calls we like, and run independently of the browser process. - - make_window(); - setup_gc(); - if (_graphics_context == None) { - // No point in continuing if we couldn't get a graphics context. - close_window(); - return; - } - - ButtonState prev_bstate = BS_hidden; - string prev_label; - double prev_progress = 0.0; - bool prev_progress_known = true; - size_t prev_received_data = 0; - - bool needs_redraw = true; - bool needs_draw_label = false; - bool needs_redraw_progress = false; - bool needs_update_progress = false; - - _subprocess_continue = true; - while (_subprocess_continue) { - // First, scan for X events. - XEvent event; - while (XCheckWindowEvent(_display, _window, ~0, &event)) { - switch (event.type) { - case Expose: - case GraphicsExpose: - needs_redraw = true; - break; - - case ConfigureNotify: - if (event.xconfigure.width != _win_width || - event.xconfigure.height != _win_height) { - _win_width = event.xconfigure.width; - _win_height = event.xconfigure.height; - - set_button_range(_button_ready_image); - - // If the window changes size, we need to recompute the composed - // image. - _needs_new_composite = true; - } - needs_redraw = true; - break; - - case MotionNotify: - set_mouse_data(event.xmotion.x, event.xmotion.y, _mouse_down); - break; - - case ButtonPress: - set_mouse_data(_mouse_x, _mouse_y, true); - break; - - case ButtonRelease: - set_mouse_data(_mouse_x, _mouse_y, false); - break; - } - } - - update_image(_background_image); - update_image(_button_ready_image); - update_image(_button_rollover_image); - update_image(_button_click_image); - - if (_needs_new_composite) { - needs_redraw = true; - compose_image(); - } - - if (_bstate != prev_bstate) { - needs_redraw = true; - prev_bstate = _bstate; - } - - if (_install_label != prev_label) { - needs_redraw = true; - prev_label = _install_label; - } - - if (_progress_known != prev_progress_known) { - needs_update_progress = true; - needs_redraw_progress = true; - } else if (_progress_known) { - if (_install_progress != prev_progress) { - needs_update_progress = true; - if (_install_progress < prev_progress) { - needs_redraw_progress = true; - } - } - } else { - if (_received_data != prev_received_data) { - needs_update_progress = true; - needs_redraw_progress = true; - } - } - - if (needs_update_progress) { - prev_progress = _install_progress; - prev_progress_known = _progress_known; - prev_received_data = _received_data; - - if (_progress_known && _install_progress == 0.0) { - // If the progress bar drops to zero, repaint the screen to take the - // progress bar away. - needs_redraw = true; - } - } - - if (needs_redraw) { - redraw(); - XFlush(_display); - - needs_redraw = false; - needs_draw_label = true; - needs_redraw_progress = true; - } - - // Don't draw an install label or a progress bar unless we have some - // nonzero progress. - if (!_progress_known || _install_progress != 0.0) { - int bar_x, bar_y, bar_width, bar_height; - get_bar_placement(bar_x, bar_y, bar_width, bar_height); - - if (needs_draw_label) { - int direction, ascent, descent; - XCharStruct extents; - XTextExtents(_font, _install_label.c_str(), _install_label.size(), - &direction, &ascent, &descent, &extents); - - int text_width = extents.width; - int text_height = extents.ascent + extents.descent; - int text_x = (_win_width - text_width) / 2; - int text_y = bar_y - descent - _bar_border - 4; - - XClearArea(_display, _window, - text_x - 2, text_y - text_height - 2, - text_width + 4, text_height + 4, false); - XDrawString(_display, _window, _graphics_context, text_x, text_y, - _install_label.c_str(), _install_label.size()); - - needs_draw_label = false; - } - - if (needs_redraw_progress) { - // Draw the bar background. - if (_bar_bg_context != None) { - XFillRectangle(_display, _window, _bar_bg_context, - bar_x, bar_y, bar_width, bar_height); - } else { - XClearArea(_display, _window, - bar_x, bar_y, bar_width, bar_height, false); - } - - // Draw the border around the bar. - int border_x = bar_x - 1; - int border_y = bar_y - 1; - int border_width = bar_width + 1; - int border_height = bar_height + 1; - - for (int i = 0; i < _bar_border; ++i) { - XDrawRectangle(_display, _window, _graphics_context, - border_x, border_y, border_width, border_height); - border_x -= 1; - border_y -= 1; - border_width += 2; - border_height += 2; - } - needs_update_progress = true; - needs_redraw_progress = false; - } - - if (needs_update_progress) { - if (_progress_known) { - int progress_width = (int)((bar_width - 1) * _install_progress + 0.5); - XFillRectangle(_display, _window, _bar_context, - bar_x, bar_y, - progress_width + 1, bar_height); - } else { - // Progress is unknown. Draw a moving block, not a progress bar - // filling up. - int block_width = (int)(bar_width * 0.1 + 0.5); - int block_travel = (bar_width - 1) - block_width; - int progress = (int)(_received_data * _unknown_progress_rate); - progress = progress % (block_travel * 2); - if (progress > block_travel) { - progress = block_travel * 2 - progress; - } - - XFillRectangle(_display, _window, _bar_context, - bar_x + progress, bar_y, - block_width + 1, bar_height); - } - needs_update_progress = false; - } - } - - - // Now check for input from the parent. - bool input_ready = _pipe_read.has_gdata(); - if (!input_ready) { - int read_fd = _pipe_read.get_handle(); - fd_set fds; - FD_ZERO(&fds); - FD_SET(read_fd, &fds); - - // Sleep a bit to yield the timeslice if there's nothing new. - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1000; // 1 usec is not enough. - - int result = select(read_fd + 1, &fds, nullptr, nullptr, &tv); - if (result > 0) { - // There is some noise on the pipe, so read it. - input_ready = true; - } else if (result == -1) { - // Error in select. - perror("select"); - } - } - - while (input_ready) { - // Empty the pipe of whatever is in it. - receive_command(); - input_ready = _pipe_read.has_gdata(); - } - - // Sleep a good amount in order not to lock up the system. - struct timespec req; - req.tv_sec = 0; - req.tv_nsec = 50000000; // 50 ms - nanosleep(&req, nullptr); - } - - close_window(); -} - -/** - * Receives a command from the parent. - */ -void P3DX11SplashWindow:: -receive_command() { - TiXmlDocument *doc = read_xml(_pipe_read, nout); - if (doc == nullptr) { - // Pipe closed or something. - _subprocess_continue = false; - return; - } - - TiXmlElement *xcommand = doc->FirstChildElement("command"); - if (xcommand != nullptr) { - const char *cmd = xcommand->Attribute("cmd"); - if (cmd != nullptr) { - if (strcmp(cmd, "exit") == 0) { - _subprocess_continue = false; - - } else if (strcmp(cmd, "set_visible") == 0) { - int visible = 0; - if (xcommand->Attribute("visible", &visible) != nullptr) { - _visible = visible; - if (_visible) { - XMapWindow(_display, _window); - } else { - XUnmapWindow(_display, _window); - } - } - - } else if (strcmp(cmd, "set_image_filename") == 0) { - const string *image_filename = xcommand->Attribute(string("image_filename")); - int image_placement; - if (image_filename != nullptr && - xcommand->QueryIntAttribute("image_placement", &image_placement) == TIXML_SUCCESS) { - - X11ImageData *image = nullptr; - switch ((ImagePlacement)image_placement) { - case IP_background: - image = &_background_image; - break; - - case IP_button_ready: - image = &_button_ready_image; - set_button_range(_button_ready_image); - break; - - case IP_button_rollover: - image = &_button_rollover_image; - break; - - case IP_button_click: - image = &_button_click_image; - break; - - case IP_none: - break; - } - if (image != nullptr) { - if (image->_filename != *image_filename) { - image->_filename = *image_filename; - image->_filename_changed = true; - } - } - } - - } else if (strcmp(cmd, "set_install_label") == 0) { - const char *str = xcommand->Attribute("install_label"); - if (str != nullptr) { - if (_install_label != string(str)) { - _install_label = str; - } - } - - } else if (strcmp(cmd, "set_install_progress") == 0) { - double install_progress = 0.0; - int progress_known = 1; - int received_data = 0; - xcommand->Attribute("install_progress", &install_progress); - xcommand->Attribute("progress_known", &progress_known); - xcommand->Attribute("received_data", &received_data); - - _install_progress = install_progress; - _progress_known = (progress_known != 0); - _received_data = (size_t)received_data; - - } else if (strcmp(cmd, "set_button_active") == 0) { - int button_active = 0; - xcommand->Attribute("button_active", &button_active); - - P3DSplashWindow::set_button_active(button_active != 0); - } - } - } -} - -/** - * Redraws the window. - */ -void P3DX11SplashWindow:: -redraw() { - if (_composite_image == nullptr) { - // Clear the whole window, if there's no image. - XClearWindow(_display, _window); - - } else { - // If we have an image, draw it. - int xo = (_win_width - _composite_width) / 2; - int yo = (_win_height - _composite_height) / 2; - XPutImage(_display, _window, _graphics_context, _composite_image, 0, 0, - xo, yo, _composite_width, _composite_height); - - // Then clear the rectangles around it carefully (rather than just - // clearing the whole window first, to avoid flicking). - if (yo != 0 && _win_width != 0) { - // Top - XClearArea(_display, _window, 0, 0, _win_width, yo, False); - // Bottom - XClearArea(_display, _window, 0, _win_height - yo, _win_width, yo, False); - } - if (xo != 0 && _composite_height != 0) { - // Left - XClearArea(_display, _window, 0, yo, xo, _composite_height, False); - // Right - XClearArea(_display, _window, _win_width - xo, yo, xo, _composite_height, False); - } - } -} - -/** - * Creates the window for displaying progress. Runs within the sub-process. - */ -void P3DX11SplashWindow:: -make_window() { - _win_width = 320; - _win_height = 240; - if (_wparams.get_win_width() != 0 && _wparams.get_win_height() != 0) { - _win_width = _wparams.get_win_width(); - _win_height = _wparams.get_win_height(); - } - - X11_Window parent = 0; - - // Hum, if we use the display provided by the browser, it causes a crash in - // some browsers when you make an Xlib call with the plugin window - // minimized. So I kept XOpenDisplay until we have a better workaround. - - // _display = (X11_Display*) _wparams.get_parent_window()._xdisplay; - // _own_display = false; if (_display == 0) { - _display = XOpenDisplay(nullptr); - _own_display = true; - // } - assert(_display != nullptr); - _screen = DefaultScreen(_display); - - int x = _wparams.get_win_x(); - int y = _wparams.get_win_y(); - if (x == -1) x = 0; - if (y == -1) y = 0; - if (x == -2) x = (int)(0.5 * (DisplayWidth(_display, _screen) - _win_width)); - if (y == -2) y = (int)(0.5 * (DisplayHeight(_display, _screen) - _win_height)); - - if (_wparams.get_window_type() == P3D_WT_embedded) { - // Create an embedded window. - const P3D_window_handle &handle = _wparams.get_parent_window(); - assert(handle._window_handle_type == P3D_WHT_x11_window); - parent = handle._handle._x11_window._xwindow; - } else { - // Create a toplevel window. - parent = XRootWindow(_display, _screen); - } - - assert(parent != None); - - int depth = DefaultDepth(_display, _screen); - Visual *dvisual = DefaultVisual(_display, _screen); - - long event_mask = - ButtonPressMask | ButtonReleaseMask | - PointerMotionMask | StructureNotifyMask | ExposureMask; - - // Allocate the foreground and background colors. - Colormap colormap = DefaultColormap(_display, _screen); - - XColor fg; - fg.red = _fgcolor_r * 0x101; - fg.green = _fgcolor_g * 0x101; - fg.blue = _fgcolor_b * 0x101; - fg.flags = DoRed | DoGreen | DoBlue; - _fg_pixel = -1; - if (XAllocColor(_display, colormap, &fg)) { - _fg_pixel = fg.pixel; - } - - XColor bg; - bg.red = _bgcolor_r * 0x101; - bg.green = _bgcolor_g * 0x101; - bg.blue = _bgcolor_b * 0x101; - bg.flags = DoRed | DoGreen | DoBlue; - _bg_pixel = -1; - if (XAllocColor(_display, colormap, &bg)) { - _bg_pixel = bg.pixel; - } - - // Initialize window attributes - XSetWindowAttributes wa; - wa.background_pixel = XWhitePixel(_display, _screen); - if (_bg_pixel != -1) { - wa.background_pixel = _bg_pixel; - } - wa.border_pixel = 0; - wa.event_mask = event_mask; - - unsigned long attrib_mask = CWBackPixel | CWBorderPixel | CWEventMask; - - _window = XCreateWindow - (_display, parent, x, y, _win_width, _win_height, - 0, depth, InputOutput, dvisual, attrib_mask, &wa); - - // Now hint the window manager about the window origin and size. This is - // necessary because window managers are free to ignore the window origin - // specified in the XCreateWindow call. - XSizeHints *size_hints_p = XAllocSizeHints(); - if (_wparams.get_win_x() != -1 || _wparams.get_win_y() != -1) { - // If the user requested (-1, -1), the default position, we let the window - // manager choose a position by omitting the pos hint. - size_hints_p->x = x; - size_hints_p->y = y; - size_hints_p->flags |= USPosition; - } - size_hints_p->width = _win_width; - size_hints_p->height = _win_height; - size_hints_p->flags |= USSize; - XSetWMNormalHints(_display, _window, size_hints_p); - XFree(size_hints_p); - - if (_visible) { - XMapWindow(_display, _window); - } -} - -/** - * Sets up the graphics context for drawing the text. - */ -void P3DX11SplashWindow:: -setup_gc() { - if (_graphics_context != None) { - return; - } - - char style = 'r'; - if (_font_style == FS_oblique) { - style = 'o'; - } else if (_font_style == FS_italic) { - style = 'i'; - } - - // Determine the order at which to try the various weights. From: - // https:developer.mozilla.orgen-USdocsWebCSSfont-weight - const char *const *try_weights; - const int num_weights = 7; - - if (_font_weight > 700) { - static const char *const weights[] = {"black", "bold", "demibold", "semibold", "medium", "regular", "extralight"}; - try_weights = weights; - - } else if (_font_weight > 600) { - static const char *const weights[] = {"bold", "black", "demibold", "semibold", "medium", "regular", "extralight"}; - try_weights = weights; - - } else if (_font_weight > 500) { - static const char *const weights[] = {"demibold", "semibold", "bold", "black", "medium", "regular", "extralight"}; - try_weights = weights; - - } else if (_font_weight == 500) { - static const char *const weights[] = {"medium", "regular", "extralight", "demibold", "semibold", "bold", "black"}; - try_weights = weights; - - } else if (_font_weight >= 400) { - static const char *const weights[] = {"regular", "medium", "extralight", "demibold", "semibold", "bold", "black"}; - try_weights = weights; - - } else { - static const char *const weights[] = {"extralight", "regular", "medium", "demibold", "semibold", "bold", "black"}; - try_weights = weights; - } - - char font_name[1024]; - - // Go through the weights array to find the best matching font. - for (int i = 0; i < num_weights; ++i) { - const char *weight_name = try_weights[i]; - - // Compose the proper pattern for finding the desired font face. - snprintf(font_name, 1024, "-*-%s-%s-%c-normal--%d-*-*-*-*-*-iso8859-1", - _font_family.c_str(), weight_name, style, _font_size); - - _font = XLoadQueryFont(_display, font_name); - if (_font != nullptr) { - break; - } - nout << "Font " << font_name << " unavailable.\n"; - - if (style == 'i' || style == 'o') { - // If oblique is not found, try italic, and vice versa. - char style2 = 216 - style; - snprintf(font_name, 1024, "-*-%s-%s-%c-normal--%d-*-*-*-*-*-iso8859-1", - _font_family.c_str(), weight_name, style2, _font_size); - - _font = XLoadQueryFont(_display, font_name); - if (_font != nullptr) { - break; - } - nout << "Font " << font_name << " unavailable.\n"; - } - } - - if (_font != nullptr) { - nout << "Loaded font " << font_name << "\n"; - } else { - nout << "Using fallback font 6x13.\n"; - _font = XLoadQueryFont(_display, "6x13"); - } - - XGCValues gcval; - gcval.font = _font->fid; - gcval.function = GXcopy; - gcval.plane_mask = AllPlanes; - gcval.foreground = BlackPixel(_display, _screen); - if (_fg_pixel != -1) { - gcval.foreground = _fg_pixel; - } - gcval.background = WhitePixel(_display, _screen); - if (_bg_pixel != -1) { - gcval.background = _bg_pixel; - } - _graphics_context = XCreateGC(_display, _window, - GCFont | GCFunction | GCPlaneMask | GCForeground | GCBackground, &gcval); - - // Also create a gc for filling in the interior of the progress bar in a - // pleasant blue color (or whatever color the user requested). - XColor bar; - bar.red = _barcolor_r * 0x101; - bar.green = _barcolor_g * 0x101; - bar.blue = _barcolor_b * 0x101; - bar.flags = DoRed | DoGreen | DoBlue; - - Colormap colormap = DefaultColormap(_display, _screen); - if (XAllocColor(_display, colormap, &bar)) { - _bar_pixel = bar.pixel; - gcval.foreground = bar.pixel; - } - - _bar_context = XCreateGC(_display, _window, - GCFont | GCFunction | GCPlaneMask | GCForeground | GCBackground, &gcval); - - // And another for the background color of the bar. - if (_bar_bgcolor_r != _bgcolor_r || _bar_bgcolor_g != _bgcolor_g || - _bar_bgcolor_b != _bgcolor_b) { - XColor bar_bg; - bar_bg.red = _bar_bgcolor_r * 0x101; - bar_bg.green = _bar_bgcolor_g * 0x101; - bar_bg.blue = _bar_bgcolor_b * 0x101; - bar_bg.flags = DoRed | DoGreen | DoBlue; - - if (XAllocColor(_display, colormap, &bar_bg)) { - _bar_bg_pixel = bar_bg.pixel; - gcval.foreground = bar_bg.pixel; - } - - _bar_bg_context = XCreateGC(_display, _window, - GCFont | GCFunction | GCPlaneMask | GCForeground | GCBackground, &gcval); - } -} - -/** - * Closes the window created above. - */ -void P3DX11SplashWindow:: -close_window() { - if (_composite_image != nullptr) { - XDestroyImage(_composite_image); - _composite_image = nullptr; - } - - if (_bar_context != None) { - if (_bar_context != _graphics_context) { - XFreeGC(_display, _bar_context); - } - _bar_context = None; - - // Also free the color we allocated. - Colormap colormap = DefaultColormap(_display, _screen); - XFreeColors(_display, colormap, &_bar_pixel, 1, 0); - } - - if (_bar_bg_context != None) { - if (_bar_bg_context != _graphics_context) { - XFreeGC(_display, _bar_bg_context); - } - _bar_bg_context = None; - - // Also free the color we allocated. - Colormap colormap = DefaultColormap(_display, _screen); - XFreeColors(_display, colormap, &_bar_bg_pixel, 1, 0); - } - - if (_fg_pixel != -1) { - Colormap colormap = DefaultColormap(_display, _screen); - XFreeColors(_display, colormap, &_fg_pixel, 1, 0); - } - - if (_bg_pixel != -1) { - Colormap colormap = DefaultColormap(_display, _screen); - XFreeColors(_display, colormap, &_bg_pixel, 1, 0); - } - - if (_graphics_context != None) { - XFreeGC(_display, _graphics_context); - _graphics_context = None; - } - - if (_window != None) { - XDestroyWindow(_display, _window); - _window = None; - } - - if (_display != None && _own_display) { - XCloseDisplay(_display); - _display = None; - } -} - -/** - * Loads the splash image, converts to to an XImage, and stores it in _image. - * Runs only in the child process. - * - * If the image is changed, sets needs_redraw to true. - */ -void P3DX11SplashWindow:: -update_image(X11ImageData &image) { - if (!image._filename_changed) { - // No changes. - return; - } - image._filename_changed = false; - - // We'll need to rebuild the composite image. - _needs_new_composite = true; - - // Go read the image. - if (!read_image_data(image, image._data, image._filename)) { - return; - } -} - -/** - * Constructs the XImage to display onscreen. It's a composition of the - * background image and/or one of the button images, scaled to fit the window. - */ -void P3DX11SplashWindow:: -compose_image() { - if (_composite_image != nullptr) { - XDestroyImage(_composite_image); - _composite_image = nullptr; - } - _needs_new_composite = false; - - vector image1; - int image1_width = 0, image1_height = 0; - scale_image(image1, image1_width, image1_height, _background_image); - - vector image2; - int image2_width = 0, image2_height = 0; - - switch (_bstate) { - case BS_hidden: - break; - case BS_ready: - scale_image(image2, image2_width, image2_height, _button_ready_image); - break; - case BS_rollover: - if (!scale_image(image2, image2_width, image2_height, _button_rollover_image)) { - scale_image(image2, image2_width, image2_height, _button_ready_image); - } - break; - case BS_click: - if (!scale_image(image2, image2_width, image2_height, _button_click_image)) { - scale_image(image2, image2_width, image2_height, _button_ready_image); - } - break; - } - - if (image1.empty() && image2.empty()) { - // We have no image. Never mind. - return; - } - - if (image2.empty()) { - // We have no button image; image1 will serve as the result. - - } else { - // We do have a button image. Compose the button image on top of the - // background image (or on top of a white image if we have no background). - - // We compose them here on the client, because X11 doesn't natively - // provide an alpha-blending mechanism (at least, not without the XRender - // extension). - vector image0; - int image0_width, image0_height; - compose_two_images(image0, image0_width, image0_height, - image1, image1_width, image1_height, - image2, image2_width, image2_height); - image1.swap(image0); - image1_width = image0_width; - image1_height = image0_height; - } - - // Now construct an XImage from the result. - Visual *dvisual = DefaultVisual(_display, _screen); - double r_ratio = dvisual->red_mask / 255.0; - double g_ratio = dvisual->green_mask / 255.0; - double b_ratio = dvisual->blue_mask / 255.0; - int data_length = 4 * image1_width * image1_height; - assert(data_length == image1.size()); - uint32_t *new_data = (uint32_t*)malloc(data_length); - - int j = 0; - for (int i = 0; i < data_length; i += 4) { - unsigned int r, g, b; - r = (unsigned int)(image1[i+0] * r_ratio); - g = (unsigned int)(image1[i+1] * g_ratio); - b = (unsigned int)(image1[i+2] * b_ratio); - new_data[j++] = ((r & dvisual->red_mask) | - (g & dvisual->green_mask) | - (b & dvisual->blue_mask)); - } - - // Now load the image. - _composite_image = XCreateImage(_display, CopyFromParent, DefaultDepth(_display, _screen), - ZPixmap, 0, (char *)new_data, image1_width, image1_height, 32, 0); - _composite_width = image1_width; - _composite_height = image1_height; -} - -/** - * Scales the image into the window size, and expands it to four channels. - * Returns true if the image is valid, false if it is empty. - */ -bool P3DX11SplashWindow:: -scale_image(vector &image0, int &image0_width, int &image0_height, - X11ImageData &image) { - if (image._data.empty()) { - return false; - } - - const unsigned char *orig_data = (const unsigned char *)image._data.data(); - int row_stride = image._width * image._num_channels; - int data_length = image._height * row_stride; - assert(data_length == image._data.size()); - - if (image._width <= _win_width && image._height <= _win_height) { - // It fits within the window - just keep it. - image0_width = image._width; - image0_height = image._height; - int new_row_stride = image0_width * 4; - int new_data_length = image0_height * new_row_stride; - - image0.clear(); - image0.reserve(new_data_length); - image0.insert(image0.begin(), new_data_length, 0); - unsigned char *new_data = &image0[0]; - - if (image._num_channels == 4) { - // Easy case. Already four channels. - assert(data_length == new_data_length && row_stride == new_row_stride); - memcpy(new_data, orig_data, data_length); - - } else if (image._num_channels == 3) { - // Expand three channels to four. - for (int yi = 0; yi < image._height; ++yi) { - const unsigned char *sp = orig_data + yi * row_stride; - unsigned char *dp = new_data + yi * new_row_stride; - for (int xi = 0; xi < image._width; ++xi) { - dp[0] = sp[0]; - dp[1] = sp[1]; - dp[2] = sp[2]; - dp[3] = 0xff; - sp += 3; - dp += 4; - } - } - } else if (image._num_channels == 1) { - // A grayscale image. Replicate out the channels. - for (int yi = 0; yi < image._height; ++yi) { - const unsigned char *sp = orig_data + yi * row_stride; - unsigned char *dp = new_data + yi * new_row_stride; - for (int xi = 0; xi < image._width; ++xi) { - dp[0] = sp[0]; - dp[1] = sp[0]; - dp[2] = sp[0]; - dp[3] = 0xff; - sp += 1; - dp += 4; - } - } - } - - } else { - // Yuck, the bad case - we need to scale it down. - double scale = std::min((double)_win_width / (double)image._width, - (double)_win_height / (double)image._height); - image0_width = (int)(image._width * scale); - image0_height = (int)(image._height * scale); - int new_row_stride = image0_width * 4; - int new_data_length = image0_height * new_row_stride; - - image0.clear(); - image0.reserve(new_data_length); - image0.insert(image0.begin(), new_data_length, 0); - unsigned char *new_data = &image0[0]; - - for (int yi = 0; yi < image0_height; ++yi) { - int orig_yi = (yi * image._height) / image0_height; - const unsigned char *sp = orig_data + orig_yi * row_stride; - unsigned char *dp = new_data + yi * new_row_stride; - for (int xi = 0; xi < image0_width; ++xi) { - int orig_xi = (xi * image._width) / image0_width; - const unsigned char *spx = sp + orig_xi * image._num_channels; - if (image._num_channels == 4) { - dp[0] = spx[0]; - dp[1] = spx[1]; - dp[2] = spx[2]; - dp[3] = spx[3]; - } else if (image._num_channels == 3) { - dp[0] = spx[0]; - dp[1] = spx[1]; - dp[2] = spx[2]; - dp[3] = 0xff; - } else if (image._num_channels == 1) { - dp[0] = spx[0]; - dp[1] = spx[0]; - dp[2] = spx[0]; - dp[3] = 0xff; - } - dp += 4; - } - } - } - - return true; -} - -/** - * Constructs into image0 the alpha-composite of image1 beneath image2. - */ -void P3DX11SplashWindow:: -compose_two_images(vector &image0, int &image0_width, int &image0_height, - const vector &image1, int image1_width, int image1_height, - const vector &image2, int image2_width, int image2_height) { - // First, the resulting image size is the larger of the two. - image0_width = std::max(image1_width, image2_width); - image0_height = std::max(image1_height, image2_height); - - int new_row_stride = image0_width * 4; - int new_data_length = image0_height * new_row_stride; - - // Now copy in the first image. If the first image exactly fills the output - // image, this is easy. - if (image1_width == image0_width && image1_height == image0_height) { - image0 = image1; - - } else { - // If the first image doesn't fill it, it's only a little bit more work. - // Start by finding the top-left pixel. - int xo = (image0_width - image1_width) / 2; - int yo = (image0_height - image1_height) / 2; - - // Initialize the image to all white pixels. - image0.clear(); - image0.reserve(new_data_length); - image0.insert(image0.begin(), new_data_length, 0xff); - - int image0_row_stride = image0_width * 4; - int image1_row_stride = image1_width * 4; - for (int yi = 0; yi < image1_height; ++yi) { - const unsigned char *sp = &image1[0] + yi * image1_row_stride; - unsigned char *dp = &image0[0] + (yi + yo) * image0_row_stride; - memcpy(dp + xo * 4, sp, image1_row_stride); - } - } - - // Now blend in the second image. Find the top-left pixel. - int xo = (image0_width - image2_width) / 2; - int yo = (image0_height - image2_height) / 2; - - int image0_row_stride = image0_width * 4; - int image2_row_stride = image2_width * 4; - - for (int yi = 0; yi < image2_height; ++yi) { - const unsigned char *sp = &image2[0] + yi * image2_row_stride; - unsigned char *dp = &image0[0] + (yi + yo) * image0_row_stride; - dp += xo * 4; - for (int xi = 0; xi < image2_width; ++xi) { - double alpha = (double)sp[3] / 255.0; - dp[0] = (unsigned char)(dp[0] + alpha * (sp[0] - dp[0])); - dp[1] = (unsigned char)(dp[1] + alpha * (sp[1] - dp[1])); - dp[2] = (unsigned char)(dp[2] + alpha * (sp[2] - dp[2])); - dp += 4; - sp += 4; - } - } -} - -#endif // HAVE_X11 diff --git a/direct/src/plugin/p3dX11SplashWindow.h b/direct/src/plugin/p3dX11SplashWindow.h deleted file mode 100644 index 72c6ac00d0..0000000000 --- a/direct/src/plugin/p3dX11SplashWindow.h +++ /dev/null @@ -1,144 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dX11SplashWindow.h - * @author rdb - * @date 2009-07-08 - */ - -#ifndef P3DX11SPLASHWINDOW_H -#define P3DX11SPLASHWINDOW_H - -#include "p3d_plugin_common.h" - -#ifdef HAVE_X11 - -#include "p3dSplashWindow.h" -#include "handleStream.h" -#include "plugin_get_x11.h" - -#include - -/** - * This is the Windows implementation of the initial-download window. - */ -class P3DX11SplashWindow : public P3DSplashWindow { -public: - P3DX11SplashWindow(P3DInstance *inst, bool make_visible); - virtual ~P3DX11SplashWindow(); - - virtual void set_wparams(const P3DWindowParams &wparams); - virtual void set_visible(bool visible); - virtual void set_image_filename(const std::string &image_filename, - ImagePlacement image_placement); - virtual void set_install_label(const std::string &install_label); - virtual void set_install_progress(double install_progress, - bool is_progress_known, size_t received_data); - - virtual void set_button_active(bool flag); - -protected: - virtual void button_click_detected(); - virtual void set_bstate(ButtonState bstate); - -private: - void start_subprocess(); - void stop_subprocess(); - void check_stopped(); - - void spawn_read_thread(); - void join_read_thread(); - -private: - // These methods run only within the read thread. - THREAD_CALLBACK_DECLARATION(P3DX11SplashWindow, rt_thread_run); - void rt_thread_run(); - void rt_terminate(); - void rt_handle_request(TiXmlDocument *doc); - -private: - // Data members that are stored in the parent process. - pid_t _subprocess_pid; - HandleStream _pipe_read; - HandleStream _pipe_write; - - // The remaining members are manipulated by or for the read thread. - bool _started_read_thread; - THREAD _read_thread; - -private: - // These methods run only within the subprocess. - class X11ImageData; - - void subprocess_run(); - void receive_command(); - - void redraw(); - void make_window(); - void setup_gc(); - void close_window(); - - void update_image(X11ImageData &image); - void compose_image(); - bool scale_image(std::vector &image0, int &image0_width, int &image0_height, - X11ImageData &image); - - void compose_two_images(std::vector &image0, int &image0_width, int &image0_height, - const std::vector &image1, int image1_width, int image1_height, - const std::vector &image2, int image2_width, int image2_height); - -private: - // Data members that are stored in the subprocess. - class X11ImageData : public ImageData { - public: - inline X11ImageData(); - inline ~X11ImageData(); - - std::string _filename; - bool _filename_changed; - std::string _data; - }; - - X11ImageData _background_image; - X11ImageData _button_ready_image; - X11ImageData _button_rollover_image; - X11ImageData _button_click_image; - - XImage *_composite_image; - int _composite_width, _composite_height; - bool _needs_new_composite; - - bool _subprocess_continue; - - bool _own_display; - std::string _install_label; - double _install_progress; - bool _progress_known; - size_t _received_data; - - std::string _label_text; - - X11_Display *_display; - int _screen; - XFontStruct *_font; - GC _graphics_context; - GC _bar_context; - GC _bar_bg_context; - unsigned long _fg_pixel; - unsigned long _bg_pixel; - unsigned long _bar_pixel; - unsigned long _bar_bg_pixel; - - X11_Window _window; -}; - -#include "p3dX11SplashWindow.I" - -#endif // HAVE_X11 - -#endif diff --git a/direct/src/plugin/p3d_lock.h b/direct/src/plugin/p3d_lock.h deleted file mode 100644 index 7c11ca5bb4..0000000000 --- a/direct/src/plugin/p3d_lock.h +++ /dev/null @@ -1,123 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3d_lock.h - * @author drose - * @date 2009-06-05 - */ - -#ifndef P3D_LOCK_H -#define P3D_LOCK_H - -// Provides some simple macros that implement platform-independet mutex locks, -// as well as platform-independent thread constructs. - -#ifdef _WIN32 - -// Windows case - -// Locks are straightforward. -class _lock { -public: - CRITICAL_SECTION _l; - int _count; -}; - -#define LOCK _lock -#define INIT_LOCK(lock) { InitializeCriticalSection(&(lock)._l); (lock)._count = 0; } -#define ACQUIRE_LOCK(lock) { EnterCriticalSection(&(lock)._l); ++((lock)._count); } -#define RELEASE_LOCK(lock) { --((lock)._count); LeaveCriticalSection(&(lock)._l); } -#define DESTROY_LOCK(lock) DeleteCriticalSection(&(lock)._l) - -/* -#define LOCK CRITICAL_SECTION -#define INIT_LOCK(lock) InitializeCriticalSection(&(lock)) -#define ACQUIRE_LOCK(lock) EnterCriticalSection(&(lock)) -#define RELEASE_LOCK(lock) LeaveCriticalSection(&(lock)) -#define DESTROY_LOCK(lock) DeleteCriticalSection(&(lock)) -*/ - -// Threads. -#define THREAD HANDLE -#define INIT_THREAD(thread) (thread) = nullptr; -#define SPAWN_THREAD(thread, callback_function, this) \ - (thread) = CreateThread(nullptr, 0, &win_ ## callback_function, (this), 0, nullptr) -#define JOIN_THREAD(thread) \ - { \ - assert((thread) != nullptr); \ - WaitForSingleObject((thread), INFINITE); \ - CloseHandle((thread)); \ - (thread) = nullptr; \ - } - -// Declare this macro within your class declaration. This implements the -// callback function wrapper necessary to hook into the above SPAWN_THREAD -// call. The wrapper will in turn call the method function you provide. -#define THREAD_CALLBACK_DECLARATION(class, callback_function) \ - static DWORD WINAPI \ - win_ ## callback_function(LPVOID data) { \ - ((class *)data)->callback_function(); \ - return 0; \ - } - - -#else // _WIN32 - -// Posix case -#include - -// We declare this to be a recursive lock, since we might make a request_ready -// call from within the API, which in turn is allowed to call back into the -// API. -#define LOCK pthread_mutex_t -#define INIT_LOCK(lock) { \ - pthread_mutexattr_t attr; \ - pthread_mutexattr_init(&attr); \ - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \ - pthread_mutex_init(&(lock), &attr); \ - pthread_mutexattr_destroy(&attr); \ - } -#define ACQUIRE_LOCK(lock) pthread_mutex_lock(&(lock)) -#define RELEASE_LOCK(lock) pthread_mutex_unlock(&(lock)) -#define DESTROY_LOCK(lock) pthread_mutex_destroy(&(lock)) - -#define THREAD pthread_t -#define INIT_THREAD(thread) (thread) = 0; -#define SPAWN_THREAD(thread, callback_function, this) \ - { \ - pthread_attr_t attr; \ - pthread_attr_init(&attr); \ - pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); \ - pthread_create(&(thread), &attr, &posix_ ## callback_function, (void *)(this)); \ - pthread_attr_destroy(&attr); \ - } - -#define JOIN_THREAD(thread) \ - { \ - assert((thread) != 0); \ - void *return_val; \ - int success = pthread_join((thread), &return_val); \ - (thread) = 0; \ - if (success != 0) { \ - nout << "Failed to join: " << success << "\n"; \ - } else { \ - nout << "Successfully joined thread: " << return_val << "\n"; \ - } \ - } - -// As above, declare this macro within your class declaration. -#define THREAD_CALLBACK_DECLARATION(class, callback_function) \ - static void * \ - posix_ ## callback_function(void *data) { \ - ((class *)data)->callback_function(); \ - return nullptr; \ - } - -#endif // _WIN32 - -#endif diff --git a/direct/src/plugin/p3d_plugin.cxx b/direct/src/plugin/p3d_plugin.cxx deleted file mode 100644 index 7e6c01108b..0000000000 --- a/direct/src/plugin/p3d_plugin.cxx +++ /dev/null @@ -1,622 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3d_plugin.cxx - * @author drose - * @date 2009-05-29 - */ - -#include "p3d_plugin_common.h" -#include "p3d_plugin_config.h" -#include "p3dInstanceManager.h" -#include "p3dInstance.h" -#include "p3dWindowParams.h" -#include "p3dUndefinedObject.h" -#include "p3dNoneObject.h" -#include "p3dBoolObject.h" -#include "p3dIntObject.h" -#include "p3dFloatObject.h" -#include "p3dStringObject.h" - -#include -#include - -// Use a simple lock to protect the C-style API functions in this module from -// parallel access by multiple threads in the host. - -bool initialized_lock = false; -LOCK _api_lock; - -bool -P3D_initialize(int api_version, const char *contents_filename, - const char *host_url, P3D_verify_contents verify_contents, - const char *platform, const char *log_directory, - const char *log_basename, bool trusted_environment, - bool console_environment, - const char *root_dir, const char *host_dir, - const char *start_dir) { - if (api_version < 10 || api_version > P3D_API_VERSION) { - // Can't accept an incompatible version. - return false; - } - - if (api_version < 13) { - // Prior to version 13, verify_contents was a bool. Convert "true" to - // P3D_VC_normal and "false" to P3D_VC_none. - if ((int)verify_contents != 0) { - verify_contents = P3D_VC_normal; - } else { - verify_contents = P3D_VC_none; - } - } - - if (!initialized_lock) { - INIT_LOCK(_api_lock); - initialized_lock = true; - } - ACQUIRE_LOCK(_api_lock); - - if (contents_filename == nullptr){ - contents_filename = ""; - } - - if (host_url == nullptr){ - host_url = ""; - } - - if (platform == nullptr) { - platform = ""; - } - - if (log_directory == nullptr) { - log_directory = ""; - } - - if (log_basename == nullptr) { - log_basename = ""; - } - - if (api_version < 12 || root_dir == nullptr) { - root_dir = ""; - } - - if (api_version < 16 || host_dir == nullptr) { - host_dir = ""; - } - - if (api_version < 17 || start_dir == nullptr) { - start_dir = ""; - } - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - bool result = inst_mgr->initialize(api_version, contents_filename, host_url, - verify_contents, platform, - log_directory, log_basename, - trusted_environment, console_environment, - root_dir, host_dir, start_dir); - RELEASE_LOCK(_api_lock); - return result; -} - -void -P3D_finalize() { - nout << "P3D_finalize called\n"; - P3DInstanceManager::delete_global_ptr(); -} - -void -P3D_set_plugin_version(int major, int minor, int sequence, - bool official, const char *distributor, - const char *coreapi_host_url, - const char *coreapi_timestamp_str, - const char *coreapi_set_ver) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - if (distributor == nullptr) { - distributor = ""; - } - if (coreapi_host_url == nullptr) { - coreapi_host_url = ""; - } - - ACQUIRE_LOCK(_api_lock); - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - - time_t coreapi_timestamp = 0; - if (inst_mgr->get_api_version() < 15) { - // Before version 15, this was passed as a time_t. - coreapi_timestamp = (time_t)coreapi_timestamp_str; - } else { - // Passing a time_t causes problems with disagreements about word size, so - // since version 15 we pass it as a string. - coreapi_timestamp = strtoul(coreapi_timestamp_str, nullptr, 10); - } - - if (inst_mgr->get_api_version() < 14 || coreapi_set_ver == nullptr) { - // Prior to version 14 this parameter was absent. - coreapi_set_ver = ""; - } - - inst_mgr->set_plugin_version(major, minor, sequence, official, distributor, - coreapi_host_url, coreapi_timestamp, - coreapi_set_ver); - RELEASE_LOCK(_api_lock); -} - -void -P3D_set_super_mirror(const char *super_mirror_url) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - if (super_mirror_url == nullptr) { - super_mirror_url = ""; - } - - ACQUIRE_LOCK(_api_lock); - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - inst_mgr->set_super_mirror(super_mirror_url); - RELEASE_LOCK(_api_lock); -} - -P3D_instance * -P3D_new_instance(P3D_request_ready_func *func, - const P3D_token tokens[], size_t num_tokens, - int argc, const char *argv[], void *user_data) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3DInstance *result = inst_mgr->create_instance(func, tokens, num_tokens, - argc, argv, user_data); - RELEASE_LOCK(_api_lock); - return result; -} - -bool -P3D_instance_start(P3D_instance *instance, bool is_local, - const char *p3d_filename, int p3d_offset) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - if (p3d_filename == nullptr) { - p3d_filename = ""; - } - ACQUIRE_LOCK(_api_lock); - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - if (inst_mgr->get_api_version() < 11) { - // Prior to version 11, there was no p3d_offset parameter. So, we default - // it to 0. - p3d_offset = 0; - } - - P3DInstance *inst = inst_mgr->validate_instance(instance); - bool result = false; - if (inst != nullptr) { - // We don't actually start it immediately; the instance will have to - // download the p3d url and read it, reading the python version, before it - // can start. - result = inst_mgr->set_p3d_filename(inst, is_local, - p3d_filename, p3d_offset); - } - RELEASE_LOCK(_api_lock); - return result; -} - -int -P3D_instance_start_stream(P3D_instance *instance, const char *p3d_url) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - if (p3d_url == nullptr) { - p3d_url = ""; - } - ACQUIRE_LOCK(_api_lock); - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3DInstance *inst = inst_mgr->validate_instance(instance); - int result = -1; - if (inst != nullptr) { - result = inst_mgr->make_p3d_stream(inst, p3d_url); - } - RELEASE_LOCK(_api_lock); - return result; -} - -void -P3D_instance_finish(P3D_instance *instance) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3DInstance *inst = inst_mgr->validate_instance(instance); - if (inst != nullptr) { - inst_mgr->finish_instance(inst); - } - RELEASE_LOCK(_api_lock); -} - -void -P3D_instance_setup_window(P3D_instance *instance, - P3D_window_type window_type, - int win_x, int win_y, - int win_width, int win_height, - const P3D_window_handle *parent_window) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - P3DWindowParams wparams(window_type, win_x, win_y, - win_width, win_height, *parent_window); - - ACQUIRE_LOCK(_api_lock); - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3DInstance *inst = inst_mgr->validate_instance(instance); - if (inst != nullptr) { - inst->set_wparams(wparams); - } - RELEASE_LOCK(_api_lock); -} - -P3D_object_type -P3D_object_get_type(P3D_object *object) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - P3D_object_type result = P3D_OBJECT_GET_TYPE(object); - RELEASE_LOCK(_api_lock); - return result; -} - -bool -P3D_object_get_bool(P3D_object *object) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - bool result = P3D_OBJECT_GET_BOOL(object); - RELEASE_LOCK(_api_lock); - return result; -} - -int -P3D_object_get_int(P3D_object *object) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - int result = P3D_OBJECT_GET_INT(object); - RELEASE_LOCK(_api_lock); - return result; -} - -double -P3D_object_get_float(P3D_object *object) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - double result = P3D_OBJECT_GET_FLOAT(object); - RELEASE_LOCK(_api_lock); - return result; -} - -int -P3D_object_get_string(P3D_object *object, char *buffer, int buffer_size) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - int result = P3D_OBJECT_GET_STRING(object, buffer, buffer_size); - RELEASE_LOCK(_api_lock); - return result; -} - -int -P3D_object_get_repr(P3D_object *object, char *buffer, int buffer_size) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - int result = P3D_OBJECT_GET_REPR(object, buffer, buffer_size); - RELEASE_LOCK(_api_lock); - return result; -} - -P3D_object * -P3D_object_get_property(P3D_object *object, const char *property) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - P3D_object *result = P3D_OBJECT_GET_PROPERTY(object, property); - RELEASE_LOCK(_api_lock); - return result; -} - -bool -P3D_object_set_property(P3D_object *object, const char *property, - bool needs_response, P3D_object *value) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - bool result = P3D_OBJECT_SET_PROPERTY(object, property, needs_response, value); - RELEASE_LOCK(_api_lock); - return result; -} - -bool -P3D_object_has_method(P3D_object *object, const char *method_name) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - bool result = P3D_OBJECT_HAS_METHOD(object, method_name); - RELEASE_LOCK(_api_lock); - return result; -} - -P3D_object * -P3D_object_call(P3D_object *object, const char *method_name, - bool needs_response, - P3D_object *params[], int num_params) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - P3D_object *result = P3D_OBJECT_CALL(object, method_name, needs_response, - params, num_params); - RELEASE_LOCK(_api_lock); - return result; -} - -P3D_object * -P3D_object_eval(P3D_object *object, const char *expression) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - P3D_object *result = P3D_OBJECT_EVAL(object, expression); - RELEASE_LOCK(_api_lock); - return result; -} - - -void -P3D_object_incref(P3D_object *object) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - if (object != nullptr) { - ACQUIRE_LOCK(_api_lock); - P3D_OBJECT_INCREF(object); - RELEASE_LOCK(_api_lock); - } -} - -void -P3D_object_decref(P3D_object *object) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - if (object != nullptr) { - ACQUIRE_LOCK(_api_lock); - P3D_OBJECT_DECREF(object); - RELEASE_LOCK(_api_lock); - } -} - -P3D_class_definition * -P3D_make_class_definition() { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3D_class_definition *result = inst_mgr->make_class_definition(); - - RELEASE_LOCK(_api_lock); - return result; -} - -P3D_object * -P3D_new_undefined_object() { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3D_object *result = inst_mgr->new_undefined_object(); - - RELEASE_LOCK(_api_lock); - return result; -} - -P3D_object * -P3D_new_none_object() { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3D_object *result = inst_mgr->new_none_object(); - - RELEASE_LOCK(_api_lock); - return result; -} - -P3D_object * -P3D_new_bool_object(bool value) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3D_object *result = inst_mgr->new_bool_object(value); - - RELEASE_LOCK(_api_lock); - return result; -} - -P3D_object * -P3D_new_int_object(int value) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - - P3D_object *result = new P3DIntObject(value); - - RELEASE_LOCK(_api_lock); - return result; -} - -P3D_object * -P3D_new_float_object(double value) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - - P3D_object *result = new P3DFloatObject(value); - - RELEASE_LOCK(_api_lock); - return result; -} - -P3D_object * -P3D_new_string_object(const char *str, int length) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - - P3D_object *result = new P3DStringObject(std::string(str, length)); - - RELEASE_LOCK(_api_lock); - return result; -} - -P3D_object * -P3D_instance_get_panda_script_object(P3D_instance *instance) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3DInstance *inst = inst_mgr->validate_instance(instance); - P3D_object *result = nullptr; - if (inst != nullptr) { - result = inst->get_panda_script_object(); - } - - RELEASE_LOCK(_api_lock); - return result; -} - -void -P3D_instance_set_browser_script_object(P3D_instance *instance, - P3D_object *object) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3DInstance *inst = inst_mgr->validate_instance(instance); - if (inst != nullptr) { - inst->set_browser_script_object(object); - } - - RELEASE_LOCK(_api_lock); -} - - -P3D_request * -P3D_instance_get_request(P3D_instance *instance) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3DInstance *inst = inst_mgr->validate_instance(instance); - P3D_request *result = nullptr; - if (inst != nullptr) { - result = inst->get_request(); - } - - RELEASE_LOCK(_api_lock); - return result; -} - -P3D_instance * -P3D_check_request(double timeout) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3D_instance *inst = inst_mgr->check_request(); - - if (inst != nullptr || timeout <= 0.0) { - RELEASE_LOCK(_api_lock); - return inst; - } - -#ifdef _WIN32 - int stop_tick = int(GetTickCount() + timeout * 1000.0); -#else - struct timeval stop_time; - gettimeofday(&stop_time, nullptr); - - int seconds = (int)floor(timeout); - stop_time.tv_sec += seconds; - stop_time.tv_usec += (int)((timeout - seconds) * 1000.0); - if (stop_time.tv_usec > 1000) { - stop_time.tv_usec -= 1000; - ++stop_time.tv_sec; - } -#endif - - // Now we have to block until a request is available. - RELEASE_LOCK(_api_lock); - inst_mgr->wait_request(timeout); - ACQUIRE_LOCK(_api_lock); - inst = inst_mgr->check_request(); - - while (inst == nullptr && inst_mgr->get_num_instances() != 0) { -#ifdef _WIN32 - int remaining_ticks = stop_tick - GetTickCount(); - if (remaining_ticks <= 0) { - break; - } - timeout = remaining_ticks * 0.001; -#else - struct timeval now; - gettimeofday(&now, nullptr); - - struct timeval remaining; - remaining.tv_sec = stop_time.tv_sec - now.tv_sec; - remaining.tv_usec = stop_time.tv_usec - now.tv_usec; - - if (remaining.tv_usec < 0) { - remaining.tv_usec += 1000; - --remaining.tv_sec; - } - if (remaining.tv_sec < 0) { - break; - } - timeout = remaining.tv_sec + remaining.tv_usec * 0.001; -#endif - - RELEASE_LOCK(_api_lock); - inst_mgr->wait_request(timeout); - ACQUIRE_LOCK(_api_lock); - inst = inst_mgr->check_request(); - } - - RELEASE_LOCK(_api_lock); - return inst; -} - -void -P3D_request_finish(P3D_request *request, bool handled) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - if (request != nullptr) { - P3DInstance::finish_request(request, handled); - } - RELEASE_LOCK(_api_lock); -} - -bool -P3D_instance_feed_url_stream(P3D_instance *instance, int unique_id, - P3D_result_code result_code, - int http_status_code, - size_t total_expected_data, - const void *this_data, - size_t this_data_size) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3DInstance *inst = inst_mgr->validate_instance(instance); - bool result = false; - if (inst != nullptr) { - result = inst-> - feed_url_stream(unique_id, result_code, http_status_code, - total_expected_data, - (const unsigned char *)this_data, this_data_size); - } - - RELEASE_LOCK(_api_lock); - return result; -} - -bool -P3D_instance_handle_event(P3D_instance *instance, - const P3D_event_data *event) { - assert(P3DInstanceManager::get_global_ptr()->is_initialized()); - ACQUIRE_LOCK(_api_lock); - - P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - P3DInstance *inst = inst_mgr->validate_instance(instance); - bool result = false; - if (inst != nullptr) { - result = inst->handle_event(*event); - } - - RELEASE_LOCK(_api_lock); - return result; -} diff --git a/direct/src/plugin/p3d_plugin.h b/direct/src/plugin/p3d_plugin.h deleted file mode 100644 index 1d7866e05c..0000000000 --- a/direct/src/plugin/p3d_plugin.h +++ /dev/null @@ -1,1127 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3d_plugin.h - * @author drose - * @date 2009-05-28 - */ - -#ifndef P3D_PLUGIN_H -#define P3D_PLUGIN_H - -/* This file defines the C-level API to Panda's core plugin API. This - API is intended to provide basic functionality for loading and - running Panda's .p3d files, particularly within a browser. - - This core API is intended to be loaded and run within a browser, as - a standalone DLL. It will in turn be responsible for fetching and - installing the appropriate version of Panda and Python, as well as - any required supporting libraries. - - Note that this code defines only the interface between the actual - browser plugin and the Panda code. It contains no code to directly - interface with any browser. The actual plugin itself will be a - separate piece of code, written in ActiveX or NPAPI or whatever API - is required for a given browser; and this code will be designed to - download and link with this DLL. - - The browser or launching application will be referred to as the - "host" in this documentation. The host should load this core API - DLL only once, but may then use it to create multiple simultaneous - different instances of Panda windows. - - Filenames passed through this interface are in native OS-specific - form, e.g. with a leading drive letter and backslashes, not in - Panda's Unix-like form (except on Unix-based OSes, of course). -*/ - -#include - -#ifdef _WIN32 -#include - -#ifdef BUILDING_P3D_PLUGIN -#define EXPCL_P3D_PLUGIN __declspec(dllexport) -#else -#define EXPCL_P3D_PLUGIN __declspec(dllimport) -#endif - -#else /* _WIN32 */ -#if defined(BUILDING_P3D_PLUGIN) && defined(__GNUC__) -#define EXPCL_P3D_PLUGIN __attribute__((visibility("default"))) -#else -#define EXPCL_P3D_PLUGIN -#endif - -#endif /* _WIN32 */ - -#ifdef __APPLE__ -#include -#endif /* __APPLE__ */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* In the following function prototypes, all functions are declared - initially as typedefs only, and then the actual function references - are finally declared at the end of this file, but only if - P3D_PLUGIN_PROTOTYPES is defined. This is intended to allow - including this file without building an implicit reference to the - functions themselves, allowing the core API library to be loaded - via an explicit LoadLibrary() or equivalent call. */ - - -/* This symbol serves to validate that runtime and compile-time - libraries match. It should be passed to P3D_initialize() - (below). This number will be incremented whenever there are changes - to any of the interface specifications defined in this header - file. */ -#define P3D_API_VERSION 17 - -/************************ GLOBAL FUNCTIONS **************************/ - -/* The following interfaces are global to the core API space, as - opposed to being specific to a particular instance. */ - -/* This is passed for verify_contents, below. */ -typedef enum { - P3D_VC_none, - P3D_VC_normal, - P3D_VC_force, - P3D_VC_never, -} P3D_verify_contents; - -/* This function should be called immediately after the core API is - loaded. You should pass P3D_API_VERSION as the first parameter, so - the DLL can verify that it has been built with the same version of - the API as the host. - - The contents_filename, if not NULL or empty, names a contents.xml - file that has already been downloaded and verified from the server. - If this is NULL, a new file will be downloaded as needed. - - If host_url is not NULL or empty, it specifies the root URL of - the download server that provided the contents_filename. - - If verify_contents is P3D_VC_none, then the server will not be - contacted unless the current contents.xml cannot be read at all. - If it is P3D_VC_normal, the server will be contacted whenever the - contents.xml has expired. If it is P3D_VC_force, each server will - be contacted initially in all cases, and subseqeuntly only whenever - contents.xml has expired for that server. The opposite of - P3D_VC_force is P3D_VC_never, which forces the plugin never to - contact the server and not to verify the contents at all. This - option should only be used if the host directory is prepopulated. - Normally, a web plugin should set this to P3D_VC_normal. - - If platform is not NULL or empty, it specifies the current platform - string; otherwise, the compiled-in default is used. This should - generally be left at NULL. - - If log_directory is not NULL or empty, it specifies the directory - into which all log files will be written; otherwise, the - compiled-in default will be used, or the system temp directory if - no default is compiled in. - - If log_basename is not NULL or empty, it specifies the filename in - log_directory to which the core API's logfile output will be - written. Otherwise, the compiled-in default is used; if there is - no compiled-in default, no logfile output will be generated by the - core API. Note that the individual instances also have their own - log_basename values. If log_history is greater than zero, the - most recent log_history (count) logs generated (per log_basename) - will be retained on disk, each named uniquely by appending a - timestamp to the log_basename before file creation. - - Next, trusted_environment should be set true to indicate that the - environment and p3d file are already trusted. If this is set, the - p3d file will be run without checking its signature. Normally, a - browser plugin should set this false. - - Furthermore, console_environment should be set true to indicate that - we are running within a text-based console, and expect to preserve - the current working directory, and also see standard output, or false - to indicate that we are running within a GUI environment, and - expect none of these. Normally, a browser plugin should set this - false. - - Finally, root_dir and host_dir can be set to override the default - root and package directories. Normally, you don't need to set them. - - This function returns true if the core API is valid and uses a - compatible API, false otherwise. If it returns false, the host - should not call any more functions in this API, and should - immediately unload the DLL and (if possible) download a new one. */ -typedef bool -P3D_initialize_func(int api_version, const char *contents_filename, - const char *host_url, P3D_verify_contents verify_contents, - const char *platform, - const char *log_directory, const char *log_basename, - bool trusted_environment, bool console_environment, - const char *root_dir, const char *host_dir, - const char *start_dir); - -/* This function should be called to unload the core API. It will - release all internally-allocated memory and return the core API to - its initial state. */ -typedef void -P3D_finalize_func(); - -/* This function establishes the version of the calling plugin, for - reporting to JavaScript and the like. */ -typedef void -P3D_set_plugin_version_func(int major, int minor, int sequence, - bool official, const char *distributor, - const char *coreapi_host_url, - const char *coreapi_timestamp, - const char *coreapi_set_ver); - -/* This function defines a "super mirror" URL: a special URL that is - consulted first whenever downloading any package referenced by a - p3d file. This setting is global, and affects all package - downloads across all instances. The main purpose of this is to - facilitate local distribution of the Panda3D runtime build, to - allow applications to ship themselves totally self-contained. If - you install the appropriate Panda3D package files into a directory - on disk, and set the "super mirror" to a file:// URL that - references that directory, then users will be able to run your p3d - file without necessarily having an internet connection. - - This normally should be set only by the panda3d standalone runtime - executable, not by a web plugin. */ -typedef void -P3D_set_super_mirror_func(const char *super_mirror_url); - -/********************** INSTANCE MANAGEMENT **************************/ - -/* The following interfaces define the API to manage individual - Panda3D instances. Each instance can display a separate 3-D - graphics window simultaneously on the host or on the desktop. The - instances operate generally independently of each other. */ - -/* This structure defines the handle to a single instance. The host - may access any members appearing here. */ -typedef struct { - /* true if the host should call P3D_instance_get_request().*/ - bool _request_pending; - - /* an opaque pointer the host may use to store private data that the - core API does not interpret. This pointer can be directly set, or - it can be initialized in the P3D_new_instance() call. */ - void *_user_data; - - /* Additional opaque data may be stored here. */ -} P3D_instance; - -/* This enum and set of structures abstract out the various window - handle types for the different platforms. */ - -typedef enum { - P3D_WHT_none = 0, - P3D_WHT_win_hwnd, - P3D_WHT_osx_port, - P3D_WHT_x11_window, - P3D_WHT_osx_cgcontext, -} P3D_window_handle_type; - -typedef struct { -#ifdef _WIN32 - HWND _hwnd; -#endif -} P3D_window_handle_win_hwnd; - - /* As provided by Mozilla, by default. Not compatible with Snow - Leopard. */ -typedef struct { -#if defined(__APPLE__) - GrafPtr _port; -#endif -} P3D_window_handle_osx_port; - - /* A CoreGraphics handle, as used by NPAPI with - NPDrawingModelCoreGraphics in effect. */ -typedef struct { -#if defined(__APPLE__) - CGContextRef _context; - WindowRef _window; -#endif -} P3D_window_handle_osx_cgcontext; - -typedef struct { -#if defined(HAVE_X11) - unsigned long _xwindow; - void *_xdisplay; -#endif -} P3D_window_handle_x11_window; - -typedef struct { - P3D_window_handle_type _window_handle_type; - union { - P3D_window_handle_win_hwnd _win_hwnd; - P3D_window_handle_osx_port _osx_port; - P3D_window_handle_x11_window _x11_window; - P3D_window_handle_osx_cgcontext _osx_cgcontext; - } _handle; -} P3D_window_handle; - -/* This enum lists the different kinds of window types that may be - requested for the instance. These define the way that the instance - will create its main Panda3D window. The instance will treat this - as a request only; it is always free to create whatever kind of - window it likes. */ -typedef enum { - /* Embedded: the Panda window is embedded within the host window. - This is the normal kind of window for an object embedded within a - browser page. Pass a valid window handle in for parent_window, - and valid coordinates on the parent window for win_x, win_y, - win_width, win_height. */ - P3D_WT_embedded, - - /* Toplevel: the Panda window is a toplevel window on the user's - desktop. Pass valid desktop coordinates in for win_x, win_y, - win_width, and win_height. If all of these are zero, the core - API will create a window wherever it sees fit. */ - P3D_WT_toplevel, - - /* Fullscreen: the Panda window is a fullscreen window, completely - overlaying the entire screen and changing the desktop resolution. - Pass a valid desktop size in for win_width and win_height (win_x - and win_y are ignored). If win_width and win_height are zero, - the core API will create a fullscreen window of its own preferred - size. */ - P3D_WT_fullscreen, - - /* Hidden: there is no window at all for the instance. */ - P3D_WT_hidden, - -} P3D_window_type; - - -/* This function pointer is passed to P3D_new_instance(), below. The - host must pass in a pointer to a valid function in the host's - address space, or NULL. If not NULL, this function will be called - asynchronously by the core API when it needs to make a request from - the host. After this notification has been received, the host - should call P3D_instance_get_request() (at its convenience) to - retrieve the actual Panda request. If the host passes NULL for - this function pointer, asynchronous notifications will not be - provided, and the host must be responsible for calling - P3D_instance_get_request() from time to time. */ - -/* Note that, unlike the other func typedefs in this header file, this - declaration is not naming a function within the core API itself. - Instead, it is a typedef for a function pointer that must be - supplied by the host. */ - -typedef void -P3D_request_ready_func(P3D_instance *instance); - -/* This structure is used to represent a single keyword/value pair - that appears within the embed syntax on the HTML page. An array of - these values is passed to the P3D instance to represent all of the - additional keywords that may appear within this syntax; it is up to - the Panda instance to interpret these additional keywords - correctly. */ -typedef struct { - const char *_keyword; - const char *_value; -} P3D_token; - -/* This function creates a new Panda3D instance. - - For tokens, pass an array of P3D_token elements (above), which - correspond to the user-supplied keyword/value pairs that may appear - in the embed token within the HTML syntax; the host is responsible - for allocating this array, and for deallocating it after this call - (the core API will make its own copy of the array). The tokens are - passed to the application, who is free to decide how to interpret - them; they have no meaning at the system level. - - The argc/argv parameters are intended for when the plugin is - invoked from the command line; they should be filled a standard - C-style argc/argv parameter list, corresponding to the command-line - parameters passed to the application. They may be 0 and NULL when - the plugin is invoked from the web. As above, this array and its - string data will be copied into the core API's own internal - storage, and need not persist after this call. - - The user_data pointer is any arbitrary pointer value; it will be - copied into the _user_data member of the new P3D_instance object. - This pointer is intended for the host to use to store private data - associated with each instance; the core API will not do anything with - this data. - */ - -typedef P3D_instance * -P3D_new_instance_func(P3D_request_ready_func *func, - const P3D_token tokens[], size_t num_tokens, - int argc, const char *argv[], - void *user_data); - -/* This function should be called at some point after - P3D_new_instance(); it actually starts the instance running. - Before this call, the instance will be in an indeterminate state. - - If is_local is true, then p3d_filename contains the name of a local - p3d file on disk. If false, then p3d_filename contains a URL that - should be downloaded to retrieve the p3d file. Also see - P3D_instance_start_stream(), below. - - p3d_offset is the offset within p3d_filename at which the p3d data - actually begins. It is normally 0 for an ordinary p3d file, but it - may be nonzero to indicate a p3d file embedded within another file - (such as is created by pdeploy). - - The return value is true on success, false on failure. */ -typedef bool -P3D_instance_start_func(P3D_instance *instance, bool is_local, - const char *p3d_filename, int p3d_offset); - -/* This function is an alternative to P3D_instance_start(); it - indicates an intention to feed the p3d file data to the instance as - a stream. The instance should return a unique integer ID for this - stream, as if the instance had requested the stream via a get_url - request (below). The plugin will then send the p3d file data to - the instance via a series of calls to - P3D_instance_feed_url_stream(), using the unique ID returned by - this function. When the stream has been transmitted successfully, - the instance will automatically start. - - The p3d_url string passed to this function is informational only. - The instance will not explicitly request this URL. */ -typedef int -P3D_instance_start_stream_func(P3D_instance *instance, const char *p3d_url); - -/* Call this function to interrupt a particular instance and stop it - from rendering, for instance when the user navigates away from the - page containing it. After calling this function, you should not - reference the P3D_instance pointer again. */ -typedef void -P3D_instance_finish_func(P3D_instance *instance); - -/* Call this function after creating an instance in order to set its - window size and placement. You must call this at least once in - order to actually manifest the instance onscreen. This may also be - called to reposition a window after its initial placement (e.g. if - the browser window has changed width and needs reformatting). */ -typedef void -P3D_instance_setup_window_func(P3D_instance *instance, - P3D_window_type window_type, - int win_x, int win_y, - int win_width, int win_height, - const P3D_window_handle *parent_window); - - -/********************** SCRIPTING SUPPORT **************************/ - -/* The following interfaces are provided to support controlling the - Panda instance via JavaScript or related interfaces on the browser. */ - -/* We require an "object" that contains some number of possible - different interfaces. An "object" might be a simple primitive like - an int, float, or string; or it might be a class object with - methods and properties. Instances of P3D_object are passed around - as parameters into and return values from functions. - - To implement a P3D_object, we need to first define a class - definition, which is a table of methods. Most classes are defined - internally by the core API, but the host must define at least one - class type as well, which provides callbacks into host-provided - objects. - - These function types define the methods available on a class. - These are function type declarations only; they do not correspond - to named functions within the core API DLL (but see the named - function pointers, further below). Instead, the function - pointers themselves are stored within the P3D_class_definition - structure. */ - -/* A forward declaration of P3D_object. */ -typedef struct _P3D_object P3D_object; - -/* A list of fundamental object types. */ -typedef enum { - P3D_OT_undefined, - P3D_OT_none, - P3D_OT_bool, - P3D_OT_int, - P3D_OT_float, - P3D_OT_string, - P3D_OT_object, -} P3D_object_type; - -/* Methods and functions that return a P3D_object return it with its - reference count already incremented by one for the benefit of the - caller, leaving the caller the owner of the implicit reference - count. This is referred to as returning a "new reference", using - the Python naming convention. Similarly, methods that receive a - P3D_object as a parameter will generally *not* adjust that object's - reference count (except to increment it the object is stored - internally), leaving the caller still the owner of the original - reference. Thus, it is the caller's responsibility to call - P3D_OBJECT_DECREF() on any P3D_objects it has received but no - longer wishes to keep. */ - -/* This method is called internally to deallocate the object and all - of its internal structures. Do not call it directly; call - P3D_OBJECT_DECREF() instead. */ -typedef void -P3D_object_finish_method(P3D_object *object); - -/* Returns the fundamental type of the object. This should be treated - as a hint to suggest how the object can most accurately be - represented; it does not limit the actual interfaces available to - an object. For instance, you may call P3D_OBJECT_GET_PROPERTY() - even if the object's type is not "object". */ -typedef P3D_object_type -P3D_object_get_type_method(P3D_object *object); - -/* Each of the following methods returns the object's value expressed - as the corresponding type. If the object is not precisely that - type, a coercion is performed. */ - -/* Return the object as a bool. */ -typedef bool -P3D_object_get_bool_method(P3D_object *object); - -/* Return the object as an integer. */ -typedef int -P3D_object_get_int_method(P3D_object *object); - -/* Return the object as a floating-point number. */ -typedef double -P3D_object_get_float_method(P3D_object *object); - -/* Get the object as a string. This method copies the string into the - provided buffer, and returns the actual length of the internal - string (not counting any terminating null character). If the - return value is larger than buffer_size, the string has been - truncated. If it is equal, there is no null character written to - the buffer (like strncpy). You may call this method first with - buffer = NULL and buffer_size = 0 to return just the required size - of the buffer. Note that P3D_object string data is internally - encoded using utf-8, by convention. */ -typedef int -P3D_object_get_string_method(P3D_object *object, - char *buffer, int buffer_size); - -/* As above, but instead of the literal object data, returns a - user-friendly reprensentation of the object as a string. For - instance, a string object returns the string itself to - P3D_OBJECT_GET_STRING(), but returns the string with quotation - marks and escape characters from P3D_OBJECT_GET_REPR(). - Mechanically, this function works the same way as get_string(). */ -typedef int -P3D_object_get_repr_method(P3D_object *object, - char *buffer, int buffer_size); - -/* Looks up a property on the object by name, i.e. a data member or a - method. The return value is a new-reference P3D_object if the - property exists, or NULL if it does not. */ -typedef P3D_object * -P3D_object_get_property_method(P3D_object *object, const char *property); - -/* Changes the value at the indicated property. The new value is - assigned to the indicating property, and its reference count is - correspondingly incremented. Any existing object previously - assigned to the corresponding property is replaced, and its - reference count decremented. If the value pointer is NULL, the - property is removed altogether. If needs_response is true, this - method returns true on success, false on failure. If - needs_response is false, the return value is always true regardless - of success or failure.*/ -typedef bool -P3D_object_set_property_method(P3D_object *object, const char *property, - bool needs_response, P3D_object *value); - -/* Returns true if the indicated method name exists on the object, - false otherwise. In the Python case, this actually returns true if - the object has the indicated property, and that property represents - a callable object. If method_name is empty or NULL, returns true - if the object itself is callable. */ -typedef bool -P3D_object_has_method_method(P3D_object *object, const char *method_name); - -/* Invokes a named method on the object. If method_name is empty or - NULL, invokes the object itself as a function. You must pass an - array of P3D_objects as the list of parameters, and ownership of - these objects' reference counts is not transferred with the call - (you must still DECREF these objects afterwards). - - If needs_response is true, the return value is a new-reference - P3D_object on success, or NULL on failure. If needs_response is - false, the return value is always NULL, and there is no way to - determine success or failure. */ -typedef P3D_object * -P3D_object_call_method(P3D_object *object, const char *method_name, - bool needs_response, - P3D_object *params[], int num_params); - -/* Evaluates an arbitrary JavaScript expression in the context of the - object. Python objects do not support this method. - - The return value is a new-reference P3D_object on success, or NULL - on failure. */ -typedef P3D_object * -P3D_object_eval_method(P3D_object *object, const char *expression); - -/* This defines the class structure that implements all of the above - methods. */ -typedef struct _P3D_class_definition { - P3D_object_finish_method *_finish; - - P3D_object_get_type_method *_get_type; - P3D_object_get_bool_method *_get_bool; - P3D_object_get_int_method *_get_int; - P3D_object_get_float_method *_get_float; - P3D_object_get_string_method *_get_string; - P3D_object_get_repr_method *_get_repr; - - P3D_object_get_property_method *_get_property; - P3D_object_set_property_method *_set_property; - - P3D_object_has_method_method *_has_method; - P3D_object_call_method *_call; - P3D_object_eval_method *_eval; - -} P3D_class_definition; - -/* And this structure defines the actual instances of P3D_object. */ -struct _P3D_object { - const P3D_class_definition *_class; - int _ref_count; - - /* Additional opaque data may be stored here. */ -}; - -/* These macros are defined for the convenience of invoking any of the - above method functions on an object. - - CAUTION! None of these macros are thread-safe; you may use them - only in a single-threaded application (or when only a single thread - of the application makes any calls into this API). For thread-safe - variants, see the similarly-named function calls below. */ - -#define P3D_OBJECT_GET_TYPE(object) ((object)->_class->_get_type((object))) -#define P3D_OBJECT_GET_BOOL(object) ((object)->_class->_get_bool((object))) -#define P3D_OBJECT_GET_INT(object) ((object)->_class->_get_int((object))) -#define P3D_OBJECT_GET_FLOAT(object) ((object)->_class->_get_float((object))) -#define P3D_OBJECT_GET_STRING(object, buffer, buffer_size) ((object)->_class->_get_string((object), (buffer), (buffer_size))) -#define P3D_OBJECT_GET_REPR(object, buffer, buffer_size) ((object)->_class->_get_repr((object), (buffer), (buffer_size))) - -#define P3D_OBJECT_GET_PROPERTY(object, property) ((object)->_class->_get_property((object), (property))) -#define P3D_OBJECT_SET_PROPERTY(object, property, needs_response, value) ((object)->_class->_set_property((object), (property), (needs_response), (value))) - -#define P3D_OBJECT_HAS_METHOD(object, method_name) ((object)->_class->_has_method((object), (method_name))) -#define P3D_OBJECT_CALL(object, method_name, needs_response, params, num_params) ((object)->_class->_call((object), (method_name), (needs_response), (params), (num_params))) -#define P3D_OBJECT_EVAL(object, expression) ((object)->_class->_eval((object), (expression))) - -/* These macros are provided to manipulate the reference count of the - indicated object. As above, these macros are NOT thread-safe. If - you need a thread-safe reference count adjustment, see the - similarly-named function calls below. - - Following Python's convention, XDECREF is provided to decrement the - reference count for a pointer that might be NULL (it does nothing - in the case of a NULL pointer). */ - -#define P3D_OBJECT_INCREF(object) (++(object)->_ref_count) -#define P3D_OBJECT_DECREF(object) { if (--(object)->_ref_count <= 0) { (object)->_class->_finish((object)); } } -#define P3D_OBJECT_XDECREF(object) { if ((object) != nullptr) { P3D_OBJECT_DECREF(object); } } - -/* End of method pointer definitions. The following function types - are once again meant to define actual function pointers to be found - within the core API DLL. */ - -/* Use these functions for thread-safe variants of the above macros. */ -typedef P3D_object_type -P3D_object_get_type_func(P3D_object *object); -typedef bool -P3D_object_get_bool_func(P3D_object *object); -typedef int -P3D_object_get_int_func(P3D_object *object); -typedef double -P3D_object_get_float_func(P3D_object *object); -typedef int -P3D_object_get_string_func(P3D_object *object, char *buffer, int buffer_size); -typedef int -P3D_object_get_repr_func(P3D_object *object, char *buffer, int buffer_size); -typedef P3D_object * -P3D_object_get_property_func(P3D_object *object, const char *property); -typedef bool -P3D_object_set_property_func(P3D_object *object, const char *property, - bool needs_response, P3D_object *value); -typedef bool -P3D_object_has_method_func(P3D_object *object, const char *method_name); -typedef P3D_object * -P3D_object_call_func(P3D_object *object, const char *method_name, - bool needs_response, - P3D_object *params[], int num_params); -typedef P3D_object * -P3D_object_eval_func(P3D_object *object, const char *expression); - -/* A NULL pointer passed into either incref or decref is safe and will - be quietly ignored. */ -typedef void -P3D_object_incref_func(P3D_object *object); -typedef void -P3D_object_decref_func(P3D_object *object); - - -/* Returns a new P3D_class_definition object, filled with generic - function pointers that have reasonable default behavior for all - methods. The host should use this function to get a clean - P3D_class_definition object before calling - P3D_instance_set_browser_script_object() (see below). Note that - this pointer will automatically be freed when P3D_finalize() is - called. */ -typedef P3D_class_definition * -P3D_make_class_definition_func(); - -/* Returns a new-reference P3D_object of type "undefined". This - corresponds to the undefined or void type on JavaScript. It is - similar to Python's None, but has a subtly different shade of - meaning; we map it to an explicit Undefined instance in - AppRunner.py. */ -typedef P3D_object * -P3D_new_undefined_object_func(); - -/* Returns a new-reference P3D_object of type none. This value has no - particular value and corresponds to Python's None type or - JavaScript's null type. */ -typedef P3D_object * -P3D_new_none_object_func(); - -/* Returns a new-reference P3D_object of type bool. */ -typedef P3D_object * -P3D_new_bool_object_func(bool value); - -/* Returns a new-reference P3D_object of type int. */ -typedef P3D_object * -P3D_new_int_object_func(int value); - -/* Returns a new-reference P3D_object of type float. */ -typedef P3D_object * -P3D_new_float_object_func(double value); - -/* Returns a new-reference P3D_object of type string. The supplied - string should be already encoded in utf-8. It is copied into the - object and stored internally. */ -typedef P3D_object * -P3D_new_string_object_func(const char *string, int length); - -/* Returns a borrowed-reference pointer--*not* a new reference--to the - top-level scriptable object of the instance. Scripts running on - the host may use this object to communicate with the instance, by - using the above methods to set or query properties, and/or call - methods, on the instance. The caller should increment the - reference count when storing this object. */ -typedef P3D_object * -P3D_instance_get_panda_script_object_func(P3D_instance *instance); - -/* The inverse functionality: this supplies an object pointer to the - instance to allow the Panda instance to control the browser. In - order to enable browser scriptability, the host must call this - method shortly after creating the instance, preferably before - calling P3D_instance_start(). - - The object parameter must have been created by the host. It will - have a custom P3D_class_definition pointer, which also must have - been created by the host. The best way to create an appropriate - class definition is call P3D_make_class_definition(), and then - replace the function pointers for at least _finish, _get_property, - _set_property, _has_method, and _call. Set these pointers to the - host's own functions that make the appropriate changes in the DOM, - or invoke the appropriate JavaScript functions. - - If this function is never called, the instance will not be able to - make outcalls to the DOM or to JavaScript, but scripts may still be - able to control the instance via P3D_instance_get_panda_script_object(), - above. - - Note that the object's constructor should initialize its reference - count to 1. The instance will increment the reference count as a - result of this call; the caller is responsible for calling DECREF - on the object after this call to remove its own reference. */ -typedef void -P3D_instance_set_browser_script_object_func(P3D_instance *instance, - P3D_object *object); - - -/********************** REQUEST HANDLING **************************/ - -/* The core API may occasionally have an asynchronous request to pass - up to the host. The following structures implement this interface. - The design is intended to support single-threaded as well as - multi-threaded implementations in the host; there is only the one - callback function, P3D_request_ready (above), which may be called - asynchronously by the core API. The host should be careful that - this callback function is protected from mutual access. The - callback function implementation may be as simple as setting a flag - that the host will later check within its main processing loop. - - Once P3D_request_ready() has been received, the host should call - P3D_instance_get_request() to query the nature of the request. - This call may be made synchronously, i.e. within the host's main - processing loop. After each request is serviced, the host should - release the request via P3D_request_finish() and then call - P3D_instance_get_request() again until that function returns NULL. - - The requests themselves are implemented via a hierarchy of structs. - Each request is stored in a different kind of struct, allowing the - different requests to store a variety of data. An enumerated value - indicates the particular request type retrieved. */ - -/* This represents the type of a request returned by - P3D_instance_get_request. More types may be added later. */ -typedef enum { - P3D_RT_stop, - P3D_RT_get_url, - P3D_RT_notify, - P3D_RT_refresh, - P3D_RT_callback, - P3D_RT_forget_package -} P3D_request_type; - -/* Structures corresponding to the request types in the above enum. */ - -/* A stop request. The instance would like to stop itself. No - additional data is required. The host should respond by calling - P3D_instance_finish(). */ -typedef struct { -} P3D_request_stop; - -/* A get_url request. The core API would like to retrieve data for a - particular URL. The core API is responsible for supplying a valid - URL string, and a unique integer ID. The unique ID is needed to - feed the results of the URL back to the core API. If possible, the - host should be prepared to handle multiple get_url requests in - parallel, but it is allowed to handle them all one at a time if - necessary. As data comes in from the url, the host should call - P3D_instance_feed_url_stream(). -*/ -typedef struct { - const char *_url; - int _unique_id; -} P3D_request_get_url; - -/* A general notification. This is just a message of some event - having occurred within the Panda3D instance. The core API will - automatically trigger a JavaScript callback based on this event. - It may be safely ignored by the application. -*/ -typedef struct { - const char *_message; -} P3D_request_notify; - -/* A refresh request. The instance would like to get a repaint event - on its own window. Only relevant for windowless plugins, e.g. on - OSX. */ -typedef struct { -} P3D_request_refresh; - -/* A callback request. The instance wants to yield control - temporarily back to JavaScript, to allow JavaScript to maintain - interactivity during a long computation, and expects to get control - again some short while later (when the callback request is pulled - off the queue and the request is handled). The data within this - structure is used internally by the core API and shouldn't be - interpreted by the caller. */ -typedef void P3D_callback_func(void *); -typedef struct { - P3D_callback_func *_func; - void *_data; -} P3D_request_callback; - -/* A forget-package request. This is called when a Python application - wishes to uninstall a specific package (for instance, to clean up - disk space). It is assumed that the application will be - responsible for deleting the actual files of the package; this is - just an instruction to the core API to remove the indicated package - from the in-memory cache. This is handled internally, and - shouldn't be interpreted by the caller. */ -typedef struct { - const char *_host_url; - const char *_package_name; - const char *_package_version; -} P3D_request_forget_package; - -/* This is the overall structure that represents a single request. It - is returned by P3D_instance_get_request(). */ -typedef struct { - P3D_instance *_instance; - P3D_request_type _request_type; - union { - P3D_request_stop _stop; - P3D_request_get_url _get_url; - P3D_request_notify _notify; - P3D_request_refresh _refresh; - P3D_request_callback _callback; - P3D_request_forget_package _forget_package; - } _request; -} P3D_request; - -/* After a call to P3D_request_ready(), or from time to time in - general, the host should call this function to see if there are any - pending requests from the core API. The function will return a - freshly-allocated request if there is a request ready, or NULL if - there are no requests. After a receipt of P3D_request_ready(), - the host should call this function repeatedly until it returns NULL - (there might be multiple requests for a single receipt of - P3D_request_ready()). Each request should be processed, then - released via P3D_request_finish(). */ -typedef P3D_request * -P3D_instance_get_request_func(P3D_instance *instance); - -/* This method may also be used to test whether a request is ready. - If any open instance has a pending request, this function will - return a pointer to one of them (which you may then pass to - P3D_instance_get_request_func). If no instances have a pending - request, this function will return NULL. This function will not - return until at least timeout seconds have elapsed, or a request is - available, whichever comes first. - - Note that, due to race conditions, it is possible for this function - to return a P3D_instance that does not in fact have any requests - pending (another thread may have checked the request first). You - should always verify that the return value of - P3D_instance_get_request() is not NULL. */ -typedef P3D_instance * -P3D_check_request_func(double timeout); - -/* A request retrieved by P3D_instance_get_request() should eventually - be passed here, after it has been handled, to deallocate its - resources and prevent a memory leak. The 'handled' flag should be - passed true if the host has handled the request, or false if it has - ignored it (e.g. because it does not implement support for this - particular request type). After calling this function, you should - not reference the P3D_request pointer again. */ -typedef void -P3D_request_finish_func(P3D_request *request, bool handled); - -/* This code is passed to P3D_instance_feed_url_stream, below, as data - is retrieved from the URL. */ -typedef enum { - /* in progress: the query is still in progress, and another call - will be made in the future. */ - P3D_RC_in_progress, - - /* done: the query is done, and all data has been retrieved without - error. This call represents the last of the data. */ - P3D_RC_done, - - /* generic_error: some error other than an HTTP error has occurred, - for instance, lack of connection to the server, or malformed URL. - No more data will be forthcoming. */ - P3D_RC_generic_error, - - /* An HTTP error has occurred, for instance 404. The particular - status code will be supplied in the http_status_code parameter. - There may or may not be data associated with this error as well. - However, no more data will be delivered after this call. */ - P3D_RC_http_error, - - /* The download was interrupted because we're about to shut down the - instance. The instance should not attempt to restart a new - download in response to this. */ - P3D_RC_shutdown - -} P3D_result_code; - -/* This function is used by the host to handle a get_url request, - above. As it retrieves data from the URL, it should call this - function from time to time to feed that data to the core API. - - instance and unique_id are from the original get_url() request. - - result_code and http_status_code indicates the current status of - the request, as described above; the call will be made again in the - future if its result_code is P3D_RC_in_progress. - - total_expected_data represents the host's best guess at the total - amount of data that will be retrieved. It is acceptable if this - guess doesn't match the actual data received at all. Set it to 0 - if the host has no idea. This value may change from one call to - the next. - - this_data and this_data_size describe the most recent block of data - retrieved from the URL. Each chunk of data passed to this function - is appended together by the core API to define the total set of - data retrieved from the URL. For a particular call to - feed_url_stream, this may contain no data at all - (e.g. this_data_size may be 0). - - The return value of this function is true if there are no problems - and the download should continue, false if there was an error - accepting the data and the host should abort. If this function - returns false on a P3D_RC_in_progress, there is no need to call - the function again with any future updates. - */ -typedef bool -P3D_instance_feed_url_stream_func(P3D_instance *instance, int unique_id, - P3D_result_code result_code, - int http_status_code, - size_t total_expected_data, - const void *this_data, - size_t this_data_size); - -/* This enum and set of structures abstract out the event pointer data - types for the different platforms, as passed to - P3D_instance_handle_event(), below. */ - -typedef enum { - P3D_ET_none = 0, - P3D_ET_osx_event_record, - P3D_ET_osx_cocoa, -} P3D_event_type; - -typedef struct { -#if defined(__APPLE__) - EventRecord *_event; -#endif -} P3D_event_osx_event_record; - -// This enum reimplements NPCocoaEventTyped, used below. -typedef enum { - P3DCocoaEventDrawRect = 1, - P3DCocoaEventMouseDown, - P3DCocoaEventMouseUp, - P3DCocoaEventMouseMoved, - P3DCocoaEventMouseEntered, - P3DCocoaEventMouseExited, - P3DCocoaEventMouseDragged, - P3DCocoaEventKeyDown, - P3DCocoaEventKeyUp, - P3DCocoaEventFlagsChanged, - P3DCocoaEventFocusChanged, - P3DCocoaEventWindowFocusChanged, - P3DCocoaEventScrollWheel, - P3DCocoaEventTextInput -} P3DCocoaEventType; - -// This structure reimplements NPCocoaEvent, to pass the complex cocoa event -// structures as generated by NPAPI. -typedef struct { - P3DCocoaEventType type; - unsigned int version; - union { - struct { - unsigned int modifierFlags; - double pluginX; - double pluginY; - int buttonNumber; - int clickCount; - double deltaX; - double deltaY; - double deltaZ; - } mouse; - struct { - unsigned int modifierFlags; - const wchar_t *characters; - const wchar_t *charactersIgnoringModifiers; - bool isARepeat; - unsigned short keyCode; - } key; - struct { -#ifdef __APPLE__ - CGContextRef context; -#endif // __APPLE__ - double x; - double y; - double width; - double height; - } draw; - struct { - bool hasFocus; - } focus; - struct { - const wchar_t *text; - } text; - } data; -} P3DCocoaEvent; - -typedef struct { - P3DCocoaEvent _event; -} P3D_event_osx_cocoa; - -typedef struct { - P3D_event_type _event_type; - union { - P3D_event_osx_event_record _osx_event_record; - P3D_event_osx_cocoa _osx_cocoa; - } _event; -} P3D_event_data; - -/* Use this function to supply a new os-specific window event to the - plugin. This is presently used only on OSX, where the window - events are needed for proper plugin handling. On Windows and X11, - window events are handled natively by the plugin. - - The return value is true if the handler has processed the event, - false if it has been ignored. */ -typedef bool -P3D_instance_handle_event_func(P3D_instance *instance, - const P3D_event_data *event); - -#ifdef P3D_FUNCTION_PROTOTYPES - -/* Define all of the actual prototypes for the above functions. */ -EXPCL_P3D_PLUGIN P3D_initialize_func P3D_initialize; -EXPCL_P3D_PLUGIN P3D_finalize_func P3D_finalize; -EXPCL_P3D_PLUGIN P3D_set_plugin_version_func P3D_set_plugin_version; -EXPCL_P3D_PLUGIN P3D_set_super_mirror_func P3D_set_super_mirror; - -EXPCL_P3D_PLUGIN P3D_new_instance_func P3D_new_instance; -EXPCL_P3D_PLUGIN P3D_instance_start_func P3D_instance_start; -EXPCL_P3D_PLUGIN P3D_instance_start_stream_func P3D_instance_start_stream; -EXPCL_P3D_PLUGIN P3D_instance_finish_func P3D_instance_finish; -EXPCL_P3D_PLUGIN P3D_instance_setup_window_func P3D_instance_setup_window; - -EXPCL_P3D_PLUGIN P3D_object_get_type_func P3D_object_get_type; -EXPCL_P3D_PLUGIN P3D_object_get_bool_func P3D_object_get_bool; -EXPCL_P3D_PLUGIN P3D_object_get_int_func P3D_object_get_int; -EXPCL_P3D_PLUGIN P3D_object_get_float_func P3D_object_get_float; -EXPCL_P3D_PLUGIN P3D_object_get_string_func P3D_object_get_string; -EXPCL_P3D_PLUGIN P3D_object_get_repr_func P3D_object_get_repr; -EXPCL_P3D_PLUGIN P3D_object_get_property_func P3D_object_get_property; -EXPCL_P3D_PLUGIN P3D_object_set_property_func P3D_object_set_property; -EXPCL_P3D_PLUGIN P3D_object_has_method_func P3D_object_has_method; -EXPCL_P3D_PLUGIN P3D_object_call_func P3D_object_call; -EXPCL_P3D_PLUGIN P3D_object_eval_func P3D_object_eval; -EXPCL_P3D_PLUGIN P3D_object_incref_func P3D_object_incref; -EXPCL_P3D_PLUGIN P3D_object_decref_func P3D_object_decref; - -EXPCL_P3D_PLUGIN P3D_make_class_definition_func P3D_make_class_definition; -EXPCL_P3D_PLUGIN P3D_new_undefined_object_func P3D_new_undefined_object; -EXPCL_P3D_PLUGIN P3D_new_none_object_func P3D_new_none_object; -EXPCL_P3D_PLUGIN P3D_new_bool_object_func P3D_new_bool_object; -EXPCL_P3D_PLUGIN P3D_new_int_object_func P3D_new_int_object; -EXPCL_P3D_PLUGIN P3D_new_float_object_func P3D_new_float_object; -EXPCL_P3D_PLUGIN P3D_new_string_object_func P3D_new_string_object; -EXPCL_P3D_PLUGIN P3D_instance_get_panda_script_object_func P3D_instance_get_panda_script_object; -EXPCL_P3D_PLUGIN P3D_instance_set_browser_script_object_func P3D_instance_set_browser_script_object; - -EXPCL_P3D_PLUGIN P3D_instance_get_request_func P3D_instance_get_request; -EXPCL_P3D_PLUGIN P3D_check_request_func P3D_check_request; -EXPCL_P3D_PLUGIN P3D_request_finish_func P3D_request_finish; -EXPCL_P3D_PLUGIN P3D_instance_feed_url_stream_func P3D_instance_feed_url_stream; -EXPCL_P3D_PLUGIN P3D_instance_handle_event_func P3D_instance_handle_event; - -#endif /* P3D_FUNCTION_PROTOTYPES */ - -// The default max_age, if none is specified in a particular contents.xml, is -// 5 seconds. This gives us enough time to start a few packages downloading, -// without re-querying the host for a new contents.xml at each operation. -#define P3D_CONTENTS_DEFAULT_MAX_AGE 5 - -#ifdef __cplusplus -}; /* end of extern "C" */ -#endif - -#endif /* P3D_PLUGIN_H */ diff --git a/direct/src/plugin/p3d_plugin_common.h b/direct/src/plugin/p3d_plugin_common.h deleted file mode 100644 index 6ddd0e057c..0000000000 --- a/direct/src/plugin/p3d_plugin_common.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3d_plugin_common.h - * @author drose - * @date 2009-05-29 - */ - -#ifndef P3D_PLUGIN_COMMON -#define P3D_PLUGIN_COMMON - -// This header file is included by all C++ files in this directory that -// contribute to p3d_plugin; it provides some common symbol declarations. - -#define P3D_FUNCTION_PROTOTYPES -// #define BUILDING_P3D_PLUGIN -#define TIXML_USE_STL - -// It's a good idea to pick up this header file, even though we don't actually -// link with dtool. This header file defines useful system-wide config -// settings. -#include "dtool_config.h" - -#include "p3d_plugin.h" -#include "p3d_lock.h" - -#include -#include -#include -#include - -// Appears in p3dInstanceManager.cxx. -extern std::ostream *nout_stream; -#define nout (*nout_stream) - -// Appears in p3d_plugin.cxx. -extern LOCK _api_lock; - -// A convenience function for formatting a generic P3D_object to an ostream. -inline std::ostream & -operator << (std::ostream &out, P3D_object &value) { - int size = P3D_OBJECT_GET_REPR(&value, nullptr, 0); - char *buffer = new char[size]; - P3D_OBJECT_GET_REPR(&value, buffer, size); - out.write(buffer, size); - delete[] buffer; - - return out; -} - -#endif diff --git a/direct/src/plugin/p3d_plugin_composite1.cxx b/direct/src/plugin/p3d_plugin_composite1.cxx deleted file mode 100644 index d49fadc3c2..0000000000 --- a/direct/src/plugin/p3d_plugin_composite1.cxx +++ /dev/null @@ -1,33 +0,0 @@ -#include "p3d_plugin.cxx" -#include "p3dAuthSession.cxx" -#include "p3dBoolObject.cxx" -#include "p3dConcreteSequence.cxx" -#include "p3dConcreteStruct.cxx" -#include "p3dConditionVar.cxx" -#include "p3dDownload.cxx" -#include "p3dFileDownload.cxx" -#include "p3dFileParams.cxx" -#include "p3dFloatObject.cxx" -#include "p3dHost.cxx" -#include "p3dInstance.cxx" -#include "p3dInstanceManager.cxx" -#include "p3dIntObject.cxx" -#include "p3dMultifileReader.cxx" -#include "p3dNoneObject.cxx" -#include "p3dObject.cxx" -#include "p3dOsxSplashWindow.cxx" -#include "p3dPackage.cxx" -#include "p3dPatchfileReader.cxx" -#include "p3dPatchFinder.cxx" -#include "p3dPythonObject.cxx" -#include "p3dReferenceCount.cxx" -#include "p3dSession.cxx" -#include "p3dSplashWindow.cxx" -#include "p3dStringObject.cxx" -#include "p3dTemporaryFile.cxx" -#include "p3dMainObject.cxx" -#include "p3dUndefinedObject.cxx" -#include "p3dWinSplashWindow.cxx" -#include "p3dX11SplashWindow.cxx" -#include "p3dWindowParams.cxx" -#include "xml_helpers.cxx" diff --git a/direct/src/plugin/p3dcert.plist b/direct/src/plugin/p3dcert.plist deleted file mode 100644 index d536f638df..0000000000 --- a/direct/src/plugin/p3dcert.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleDisplayName - P3DCert - CFBundleExecutable - p3dcert - CFBundleIdentifier - org.panda3d.runtime.p3dcert - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - P3DCert - CFBundlePackageType - APPL - CFBundleShortVersionString - 0.9.3 - CFBundleSignature - ???? - CFBundleVersion - 0.9.3 - LSUIElement - 1 - LSHasLocalizedDisplayName - - NSAppleScriptEnabled - - NSPrincipalClass - NSApplication - - diff --git a/direct/src/plugin/p3dpython.plist b/direct/src/plugin/p3dpython.plist deleted file mode 100644 index d86cc2d0ca..0000000000 --- a/direct/src/plugin/p3dpython.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleDisplayName - P3DPython - CFBundleExecutable - p3dpython - CFBundleIdentifier - org.panda3d.runtime.p3dpython - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - P3DPython - CFBundlePackageType - APPL - CFBundleShortVersionString - 0.9.3 - CFBundleSignature - ???? - CFBundleVersion - 0.9.3 - LSUIElement - 1 - LSHasLocalizedDisplayName - - NSAppleScriptEnabled - - NSPrincipalClass - NSApplication - - diff --git a/direct/src/plugin/p3dpython_composite1.cxx b/direct/src/plugin/p3dpython_composite1.cxx deleted file mode 100644 index 819289ffec..0000000000 --- a/direct/src/plugin/p3dpython_composite1.cxx +++ /dev/null @@ -1,6 +0,0 @@ -#include "binaryXml.cxx" -#include "handleStream.cxx" -#include "handleStreamBuf.cxx" -#include "p3dCInstance.cxx" -#include "p3dPythonRun.cxx" -#include "run_p3dpython.cxx" diff --git a/direct/src/plugin/parse_color.cxx b/direct/src/plugin/parse_color.cxx deleted file mode 100644 index 4a5f12b587..0000000000 --- a/direct/src/plugin/parse_color.cxx +++ /dev/null @@ -1,73 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parse_color.cxx - * @author drose - * @date 2011-08-25 - */ - -#include "parse_color.h" -#include - -static bool parse_hexdigit(int &result, char digit); - -/** - * Parses a HTML color spec of the form #rgb or #rrggbb. Returns true on - * success, false on failure. On success, fills r, g, b with the color values - * in the range 0..255. On failure, r, g, b are undefined. - */ -bool -parse_color(int &r, int &g, int &b, const std::string &color) { - if (color.empty() || color[0] != '#') { - return false; - } - if (color.length() == 4) { - if (!parse_hexdigit(r, color[1]) || - !parse_hexdigit(g, color[2]) || - !parse_hexdigit(b, color[3])) { - return false; - } - r *= 0x11; - g *= 0x11; - b *= 0x11; - return true; - } - if (color.length() == 7) { - int rh, rl, gh, gl, bh, bl; - if (!parse_hexdigit(rh, color[1]) || - !parse_hexdigit(rl, color[2]) || - !parse_hexdigit(gh, color[3]) || - !parse_hexdigit(gl, color[4]) || - !parse_hexdigit(bh, color[5]) || - !parse_hexdigit(bl, color[6])) { - return false; - } - r = (rh << 4) | rl; - g = (gh << 4) | gl; - b = (bh << 4) | bl; - return true; - } - - return false; -} - -/** - * Parses a single hex digit. Returns true on success, false on failure. On - * success, fills result with the parsed value, an integer in the range 0..15. - */ -bool -parse_hexdigit(int &result, char digit) { - if (isdigit(digit)) { - result = digit - '0'; - return true; - } else if (isxdigit(digit)) { - result = tolower(digit) - 'a' + 10; - return true; - } - return false; -} diff --git a/direct/src/plugin/parse_color.h b/direct/src/plugin/parse_color.h deleted file mode 100644 index 794abf2055..0000000000 --- a/direct/src/plugin/parse_color.h +++ /dev/null @@ -1,21 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parse_color.h - * @author drose - * @date 2011-08-25 - */ - -#ifndef PARSE_COLOR_H -#define PARSE_COLOR_H - -#include - -bool parse_color(int &r, int &g, int &b, const std::string &color); - -#endif diff --git a/direct/src/plugin/plugin_common_composite1.cxx b/direct/src/plugin/plugin_common_composite1.cxx deleted file mode 100644 index 4686d49495..0000000000 --- a/direct/src/plugin/plugin_common_composite1.cxx +++ /dev/null @@ -1,4 +0,0 @@ -#include "load_plugin.cxx" -#include "fileSpec.cxx" -#include "find_root_dir.cxx" -#include "mkdir_complete.cxx" diff --git a/direct/src/plugin/plugin_get_x11.h b/direct/src/plugin/plugin_get_x11.h deleted file mode 100644 index 827c96fc27..0000000000 --- a/direct/src/plugin/plugin_get_x11.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file plugin_get_x11.h - * @author drose - * @date 2011-08-28 - */ - -#ifndef PLUGIN_GET_X11_H -#define PLUGIN_GET_X11_H - -#include "pandabase.h" -#include "p3d_plugin_config.h" - -#ifdef HAVE_X11 -// This header file is designed to help work around some of the namespace -// spamming that X11 causes, by renaming the symbols that X11 declares that -// are known to conflict with other library names (like Apple's Core Graphics, -// for instance). - -// In order for this to work, everyone who uses X11 within Panda should -// include this file instead of including the X11 headers directly. - -#include "pre_x11_include.h" - -#include -#include - -#include "post_x11_include.h" - -#endif // HAVE_X11 - -#endif diff --git a/direct/src/plugin/run_p3dpython.cxx b/direct/src/plugin/run_p3dpython.cxx deleted file mode 100644 index 1a0432a2d4..0000000000 --- a/direct/src/plugin/run_p3dpython.cxx +++ /dev/null @@ -1,33 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file run_p3dpython.cxx - * @author drose - * @date 2009-08-29 - */ - -#include "p3dPythonRun.h" -#include "run_p3dpython.h" - -/** - * This externally-visible function is the main entry point to this DLL, and - * it starts the whole thing running. Returns the exit status, which will be - * 0 on success, 1 or otherwise on failure. - */ -int -run_p3dpython(const char *program_name, const char *archive_file, - FHandle input_handle, FHandle output_handle, - const char *log_pathname, bool interactive_console) { - P3DPythonRun::_global_ptr = - new P3DPythonRun(program_name, archive_file, input_handle, output_handle, - log_pathname, interactive_console); - int result = P3DPythonRun::_global_ptr->run_python(); - delete P3DPythonRun::_global_ptr; - P3DPythonRun::_global_ptr = nullptr; - return result; -} diff --git a/direct/src/plugin/run_p3dpython.h b/direct/src/plugin/run_p3dpython.h deleted file mode 100644 index 8c1a6c2b69..0000000000 --- a/direct/src/plugin/run_p3dpython.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file run_p3dpython.h - * @author drose - * @date 2009-08-29 - */ - -#ifndef RUN_P3DPYTHON_H -#define RUN_P3DPYTHON_H - -// This header file defines the prototype for run_p3dpython(), the main entry -// point to this DLL. - -#include "fhandle.h" - -#ifdef _WIN32 -#define EXPCL_P3DPYTHON __declspec(dllexport) -#else -#define EXPCL_P3DPYTHON -#endif - -typedef int -run_p3dpython_func(const char *program_name, const char *archive_file, - FHandle input_handle, FHandle output_handle, - const char *log_pathname, bool interactive_console); - -extern "C" EXPCL_P3DPYTHON int -run_p3dpython(const char *program_name, const char *archive_file, - FHandle input_handle, FHandle output_handle, - const char *log_pathname, bool interactive_console); - -#endif diff --git a/direct/src/plugin/stb_image.h b/direct/src/plugin/stb_image.h deleted file mode 100644 index c3945c2e25..0000000000 --- a/direct/src/plugin/stb_image.h +++ /dev/null @@ -1,6326 +0,0 @@ -/* stb_image - v2.02 - public domain image loader - http://nothings.org/stb_image.h - no warranty implied; use at your own risk - - Do this: - #define STB_IMAGE_IMPLEMENTATION - before you include this file in *one* C or C++ file to create the implementation. - - // i.e. it should look like this: - #include ... - #include ... - #include ... - #define STB_IMAGE_IMPLEMENTATION - #include "stb_image.h" - - You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. - And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free - - - QUICK NOTES: - Primarily of interest to game developers and other people who can - avoid problematic images and only need the trivial interface - - JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) - PNG 1/2/4/8-bit-per-channel (16 bpc not supported) - - TGA (not sure what subset, if a subset) - BMP non-1bpp, non-RLE - PSD (composited view only, no extra channels) - - GIF (*comp always reports as 4-channel) - HDR (radiance rgbE format) - PIC (Softimage PIC) - PNM (PPM and PGM binary only) - - - decode from memory or through FILE (define STBI_NO_STDIO to remove code) - - decode from arbitrary I/O callbacks - - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) - - Full documentation under "DOCUMENTATION" below. - - - Revision 2.00 release notes: - - - Progressive JPEG is now supported. - - - PPM and PGM binary formats are now supported, thanks to Ken Miller. - - - x86 platforms now make use of SSE2 SIMD instructions for - JPEG decoding, and ARM platforms can use NEON SIMD if requested. - This work was done by Fabian "ryg" Giesen. SSE2 is used by - default, but NEON must be enabled explicitly; see docs. - - With other JPEG optimizations included in this version, we see - 2x speedup on a JPEG on an x86 machine, and a 1.5x speedup - on a JPEG on an ARM machine, relative to previous versions of this - library. The same results will not obtain for all JPGs and for all - x86/ARM machines. (Note that progressive JPEGs are significantly - slower to decode than regular JPEGs.) This doesn't mean that this - is the fastest JPEG decoder in the land; rather, it brings it - closer to parity with standard libraries. If you want the fastest - decode, look elsewhere. (See "Philosophy" section of docs below.) - - See final bullet items below for more info on SIMD. - - - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing - the memory allocator. Unlike other STBI libraries, these macros don't - support a context parameter, so if you need to pass a context in to - the allocator, you'll have to store it in a global or a thread-local - variable. - - - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and - STBI_NO_LINEAR. - STBI_NO_HDR: suppress implementation of .hdr reader format - STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API - - - You can suppress implementation of any of the decoders to reduce - your code footprint by #defining one or more of the following - symbols before creating the implementation. - - STBI_NO_JPEG - STBI_NO_PNG - STBI_NO_BMP - STBI_NO_PSD - STBI_NO_TGA - STBI_NO_GIF - STBI_NO_HDR - STBI_NO_PIC - STBI_NO_PNM (.ppm and .pgm) - - - You can request *only* certain decoders and suppress all other ones - (this will be more forward-compatible, as addition of new decoders - doesn't require you to disable them explicitly): - - STBI_ONLY_JPEG - STBI_ONLY_PNG - STBI_ONLY_BMP - STBI_ONLY_PSD - STBI_ONLY_TGA - STBI_ONLY_GIF - STBI_ONLY_HDR - STBI_ONLY_PIC - STBI_ONLY_PNM (.ppm and .pgm) - - Note that you can define multiples of these, and you will get all - of them ("only x" and "only y" is interpreted to mean "only x&y"). - - - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still - want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB - - - Compilation of all SIMD code can be suppressed with - #define STBI_NO_SIMD - It should not be necessary to disable SIMD unless you have issues - compiling (e.g. using an x86 compiler which doesn't support SSE - intrinsics or that doesn't support the method used to detect - SSE2 support at run-time), and even those can be reported as - bugs so I can refine the built-in compile-time checking to be - smarter. - - - The old STBI_SIMD system which allowed installing a user-defined - IDCT etc. has been removed. If you need this, don't upgrade. My - assumption is that almost nobody was doing this, and those who - were will find the built-in SIMD more satisfactory anyway. - - - RGB values computed for JPEG images are slightly different from - previous versions of stb_image. (This is due to using less - integer precision in SIMD.) The C code has been adjusted so - that the same RGB values will be computed regardless of whether - SIMD support is available, so your app should always produce - consistent results. But these results are slightly different from - previous versions. (Specifically, about 3% of available YCbCr values - will compute different RGB results from pre-1.49 versions by +-1; - most of the deviating values are one smaller in the G channel.) - - - If you must produce consistent results with previous versions of - stb_image, #define STBI_JPEG_OLD and you will get the same results - you used to; however, you will not get the SIMD speedups for - the YCbCr-to-RGB conversion step (although you should still see - significant JPEG speedup from the other changes). - - Please note that STBI_JPEG_OLD is a temporary feature; it will be - removed in future versions of the library. It is only intended for - near-term back-compatibility use. - - - Latest revision history: - 2.02 (2015-01-19) fix incorrect assert, fix warning - 2.01 (2015-01-17) fix various warnings - 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG - 2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD - progressive JPEG - PGM/PPM support - STBI_MALLOC,STBI_REALLOC,STBI_FREE - STBI_NO_*, STBI_ONLY_* - GIF bugfix - 1.48 (2014-12-14) fix incorrectly-named assert() - 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) - optimize PNG - fix bug in interlaced PNG with user-specified channel count - 1.46 (2014-08-26) fix broken tRNS chunk in non-paletted PNG - 1.45 (2014-08-16) workaround MSVC-ARM internal compiler error by wrapping malloc - - See end of file for full revision history. - - - ============================ Contributors ========================= - - Image formats Bug fixes & warning fixes - Sean Barrett (jpeg, png, bmp) Marc LeBlanc - Nicolas Schulz (hdr, psd) Christpher Lloyd - Jonathan Dummer (tga) Dave Moore - Jean-Marc Lienher (gif) Won Chun - Tom Seddon (pic) the Horde3D community - Thatcher Ulrich (psd) Janez Zemva - Ken Miller (pgm, ppm) Jonathan Blow - Laurent Gomila - Aruelien Pocheville - Extensions, features Ryamond Barbiero - Jetro Lauha (stbi_info) David Woo - Martin "SpartanJ" Golini (stbi_info) Martin Golini - James "moose2000" Brown (iPhone PNG) Roy Eltham - Ben "Disch" Wenger (io callbacks) Luke Graham - Omar Cornut (1/2/4-bit PNG) Thomas Ruf - John Bartholomew - Ken Hamada - Optimizations & bugfixes Cort Stratton - Fabian "ryg" Giesen Blazej Dariusz Roszkowski - Arseny Kapoulkine Thibault Reuille - Paul Du Bois - Guillaume George - If your name should be here but Jerry Jansson - isn't, let Sean know. Hayaki Saito - Johan Duparc - Ronny Chevalier - Michal Cichon - Tero Hanninen - Sergio Gonzalez - Cass Everitt - Engin Manap - -License: - This software is in the public domain. Where that dedication is not - recognized, you are granted a perpetual, irrevocable license to copy - and modify this file however you want. - -*/ - -#ifndef STBI_INCLUDE_STB_IMAGE_H -#define STBI_INCLUDE_STB_IMAGE_H - -// DOCUMENTATION -// -// Limitations: -// - no 16-bit-per-channel PNG -// - no 12-bit-per-channel JPEG -// - no JPEGs with arithmetic coding -// - no 1-bit BMP -// - GIF always returns *comp=4 -// -// Basic usage (see HDR discussion below for HDR usage): -// int x,y,n; -// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); -// // ... process data if not NULL ... -// // ... x = width, y = height, n = # 8-bit components per pixel ... -// // ... replace '0' with '1'..'4' to force that many components per pixel -// // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) -// -// Standard parameters: -// int *x -- outputs image width in pixels -// int *y -- outputs image height in pixels -// int *comp -- outputs # of image components in image file -// int req_comp -- if non-zero, # of image components requested in result -// -// The return value from an image loader is an 'unsigned char *' which points -// to the pixel data, or NULL on an allocation failure or if the image is -// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, -// with each pixel consisting of N interleaved 8-bit components; the first -// pixel pointed to is top-left-most in the image. There is no padding between -// image scanlines or between pixels, regardless of format. The number of -// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. -// If req_comp is non-zero, *comp has the number of components that _would_ -// have been output otherwise. E.g. if you set req_comp to 4, you will always -// get RGBA output, but you can check *comp to see if it's trivially opaque -// because e.g. there were only 3 channels in the source image. -// -// An output image with N components has the following components interleaved -// in this order in each pixel: -// -// N=#comp components -// 1 grey -// 2 grey, alpha -// 3 red, green, blue -// 4 red, green, blue, alpha -// -// If image loading fails for any reason, the return value will be NULL, -// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() -// can be queried for an extremely brief, end-user unfriendly explanation -// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid -// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly -// more user-friendly ones. -// -// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. -// -// =========================================================================== -// -// Philosophy -// -// stb libraries are designed with the following priorities: -// -// 1. easy to use -// 2. easy to maintain -// 3. good performance -// -// Sometimes I let "good performance" creep up in priority over "easy to maintain", -// and for best performance I may provide less-easy-to-use APIs that give higher -// performance, in addition to the easy to use ones. Nevertheless, it's important -// to keep in mind that from the standpoint of you, a client of this library, -// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all. -// -// Some secondary priorities arise directly from the first two, some of which -// make more explicit reasons why performance can't be emphasized. -// -// - Portable ("ease of use") -// - Small footprint ("easy to maintain") -// - No dependencies ("ease of use") -// -// =========================================================================== -// -// I/O callbacks -// -// I/O callbacks allow you to read from arbitrary sources, like packaged -// files or some other source. Data read from callbacks are processed -// through a small internal buffer (currently 128 bytes) to try to reduce -// overhead. -// -// The three functions you must define are "read" (reads some bytes of data), -// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). -// -// =========================================================================== -// -// SIMD support -// -// The JPEG decoder will try to automatically use SIMD kernels on x86 when -// supported by the compiler. For ARM Neon support, you must explicitly -// request it. -// -// (The old do-it-yourself SIMD API is no longer supported in the current -// code.) -// -// On x86, SSE2 will automatically be used when available based on a run-time -// test; if not, the generic C versions are used as a fall-back. On ARM targets, -// the typical path is to have separate builds for NEON and non-NEON devices -// (at least this is true for iOS and Android). Therefore, the NEON support is -// toggled by a build flag: define STBI_NEON to get NEON loops. -// -// The output of the JPEG decoder is slightly different from versions where -// SIMD support was introduced (that is, for versions before 1.49). The -// difference is only +-1 in the 8-bit RGB channels, and only on a small -// fraction of pixels. You can force the pre-1.49 behavior by defining -// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path -// and hence cost some performance. -// -// If for some reason you do not want to use any of SIMD code, or if -// you have issues compiling it, you can disable it entirely by -// defining STBI_NO_SIMD. -// -// =========================================================================== -// -// HDR image support (disable by defining STBI_NO_HDR) -// -// stb_image now supports loading HDR images in general, and currently -// the Radiance .HDR file format, although the support is provided -// generically. You can still load any file through the existing interface; -// if you attempt to load an HDR file, it will be automatically remapped to -// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; -// both of these constants can be reconfigured through this interface: -// -// stbi_hdr_to_ldr_gamma(2.2f); -// stbi_hdr_to_ldr_scale(1.0f); -// -// (note, do not use _inverse_ constants; stbi_image will invert them -// appropriately). -// -// Additionally, there is a new, parallel interface for loading files as -// (linear) floats to preserve the full dynamic range: -// -// float *data = stbi_loadf(filename, &x, &y, &n, 0); -// -// If you load LDR images through this interface, those images will -// be promoted to floating point values, run through the inverse of -// constants corresponding to the above: -// -// stbi_ldr_to_hdr_scale(1.0f); -// stbi_ldr_to_hdr_gamma(2.2f); -// -// Finally, given a filename (or an open file or memory block--see header -// file for details) containing image data, you can query for the "most -// appropriate" interface to use (that is, whether the image is HDR or -// not), using: -// -// stbi_is_hdr(char *filename); -// -// =========================================================================== -// -// iPhone PNG support: -// -// By default we convert iphone-formatted PNGs back to RGB, even though -// they are internally encoded differently. You can disable this conversion -// by by calling stbi_convert_iphone_png_to_rgb(0), in which case -// you will always just get the native iphone "format" through (which -// is BGR stored in RGB). -// -// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per -// pixel to remove any premultiplied alpha *only* if the image file explicitly -// says there's premultiplied data (currently only happens in iPhone images, -// and only if iPhone convert-to-rgb processing is on). -// - - -#ifndef STBI_NO_STDIO -#include -#endif // STBI_NO_STDIO - -#define STBI_VERSION 1 - -enum -{ - STBI_default = 0, // only used for req_comp - - STBI_grey = 1, - STBI_grey_alpha = 2, - STBI_rgb = 3, - STBI_rgb_alpha = 4 -}; - -typedef unsigned char stbi_uc; - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef STB_IMAGE_STATIC -#define STBIDEF static -#else -#define STBIDEF extern -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// PRIMARY API - works on images of any type -// - -// -// load image by filename, open file, or memory buffer -// - -typedef struct -{ - int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read - void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative - int (*eof) (void *user); // returns nonzero if we are at end of file/data -} stbi_io_callbacks; - -STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); -STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp); -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp); - -#ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -// for stbi_load_from_file, file pointer is left pointing immediately after image -#endif - -#ifndef STBI_NO_LINEAR - STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); - STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); - STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); - - #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); - #endif -#endif - -#ifndef STBI_NO_HDR - STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); - STBIDEF void stbi_hdr_to_ldr_scale(float scale); -#endif - -#ifndef STBI_NO_LINEAR - STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); - STBIDEF void stbi_ldr_to_hdr_scale(float scale); -#endif // STBI_NO_HDR - -// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); -#ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename); -STBIDEF int stbi_is_hdr_from_file(FILE *f); -#endif // STBI_NO_STDIO - - -// get a VERY brief reason for failure -// NOT THREADSAFE -STBIDEF const char *stbi_failure_reason (void); - -// free the loaded image -- this is just free() -STBIDEF void stbi_image_free (void *retval_from_stbi_load); - -// get image dimensions & components without fully decoding -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); - -#endif - - - -// for image formats that explicitly notate that they have premultiplied alpha, -// we just return the colors as stored in the file. set this flag to force -// unpremultiplication. results are undefined if the unpremultiply overflow. -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); - -// indicate whether we should process iphone images back to canonical format, -// or just pass them through "as-is" -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); - - -// ZLIB client - used by PNG, available for other purposes - -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); -STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - -STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - - -#ifdef __cplusplus -} -#endif - -// -// -//// end header file ///////////////////////////////////////////////////// -#endif // STBI_INCLUDE_STB_IMAGE_H - -#ifdef STB_IMAGE_IMPLEMENTATION - -#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ - || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ - || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ - || defined(STBI_ONLY_ZLIB) - #ifndef STBI_ONLY_JPEG - #define STBI_NO_JPEG - #endif - #ifndef STBI_ONLY_PNG - #define STBI_NO_PNG - #endif - #ifndef STBI_ONLY_BMP - #define STBI_NO_BMP - #endif - #ifndef STBI_ONLY_PSD - #define STBI_NO_PSD - #endif - #ifndef STBI_ONLY_TGA - #define STBI_NO_TGA - #endif - #ifndef STBI_ONLY_GIF - #define STBI_NO_GIF - #endif - #ifndef STBI_ONLY_HDR - #define STBI_NO_HDR - #endif - #ifndef STBI_ONLY_PIC - #define STBI_NO_PIC - #endif - #ifndef STBI_ONLY_PNM - #define STBI_NO_PNM - #endif -#endif - -#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) -#define STBI_NO_ZLIB -#endif - - -#include -#include // ptrdiff_t on osx -#include -#include - -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -#include // ldexp -#endif - -#ifndef STBI_NO_STDIO -#include -#endif - -#ifndef STBI_ASSERT -#include -#define STBI_ASSERT(x) assert(x) -#endif - - -#ifndef _MSC_VER - #ifdef __cplusplus - #define stbi_inline inline - #else - #define stbi_inline - #endif -#else - #define stbi_inline __forceinline -#endif - - -#ifdef _MSC_VER -typedef unsigned short stbi__uint16; -typedef signed short stbi__int16; -typedef unsigned int stbi__uint32; -typedef signed int stbi__int32; -#else -#include -typedef uint16_t stbi__uint16; -typedef int16_t stbi__int16; -typedef uint32_t stbi__uint32; -typedef int32_t stbi__int32; -#endif - -// should produce compiler error if size is wrong -typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; - -#ifdef _MSC_VER -#define STBI_NOTUSED(v) (void)(v) -#else -#define STBI_NOTUSED(v) (void)sizeof(v) -#endif - -#ifdef _MSC_VER -#define STBI_HAS_LROTL -#endif - -#ifdef STBI_HAS_LROTL - #define stbi_lrot(x,y) _lrotl(x,y) -#else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) -#endif - -#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC) -// ok -#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) -// ok -#else -#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC." -#endif - -#ifndef STBI_MALLOC -#define STBI_MALLOC(sz) malloc(sz) -#define STBI_REALLOC(p,sz) realloc(p,sz) -#define STBI_FREE(p) free(p) -#endif - -#if defined(__GNUC__) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) -// gcc doesn't support sse2 intrinsics unless you compile with -msse2, -// (but compiling with -msse2 allows the compiler to use SSE2 everywhere; -// this is just broken and gcc are jerks for not fixing it properly -// http://www.virtualdub.org/blog/pivot/entry.php?id=363 ) -#define STBI_NO_SIMD -#endif - -#if !defined(STBI_NO_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)) -#define STBI_SSE2 -#include - -#ifdef _MSC_VER - -#if _MSC_VER >= 1400 // not VC6 -#include // __cpuid -static int stbi__cpuid3(void) -{ - int info[4]; - __cpuid(info,1); - return info[3]; -} -#else -static int stbi__cpuid3(void) -{ - int res; - __asm { - mov eax,1 - cpuid - mov res,edx - } - return res; -} -#endif - -#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name - -static int stbi__sse2_available() -{ - int info3 = stbi__cpuid3(); - return ((info3 >> 26) & 1) != 0; -} -#else // assume GCC-style if not VC++ -#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) - -static int stbi__sse2_available() -{ -#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later - // GCC 4.8+ has a nice way to do this - return __builtin_cpu_supports("sse2"); -#else - // portable way to do this, preferably without using GCC inline ASM? - // just bail for now. - return 0; -#endif -} -#endif -#endif - -// ARM NEON -#if defined(STBI_NO_SIMD) && defined(STBI_NEON) -#undef STBI_NEON -#endif - -#ifdef STBI_NEON -#include -// assume GCC or Clang on ARM targets -#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) -#endif - -#ifndef STBI_SIMD_ALIGN -#define STBI_SIMD_ALIGN(type, name) type name -#endif - -/////////////////////////////////////////////// -// -// stbi__context struct and start_xxx functions - -// stbi__context structure is our basic context used by all images, so it -// contains all the IO context, plus some basic image information -typedef struct -{ - stbi__uint32 img_x, img_y; - int img_n, img_out_n; - - stbi_io_callbacks io; - void *io_user_data; - - int read_from_callbacks; - int buflen; - stbi_uc buffer_start[128]; - - stbi_uc *img_buffer, *img_buffer_end; - stbi_uc *img_buffer_original; -} stbi__context; - - -static void stbi__refill_buffer(stbi__context *s); - -// initialize a memory-decode context -static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) -{ - s->io.read = NULL; - s->read_from_callbacks = 0; - s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; - s->img_buffer_end = (stbi_uc *) buffer+len; -} - -// initialize a callback-based context -static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) -{ - s->io = *c; - s->io_user_data = user; - s->buflen = sizeof(s->buffer_start); - s->read_from_callbacks = 1; - s->img_buffer_original = s->buffer_start; - stbi__refill_buffer(s); -} - -#ifndef STBI_NO_STDIO - -static int stbi__stdio_read(void *user, char *data, int size) -{ - return (int) fread(data,1,size,(FILE*) user); -} - -static void stbi__stdio_skip(void *user, int n) -{ - fseek((FILE*) user, n, SEEK_CUR); -} - -static int stbi__stdio_eof(void *user) -{ - return feof((FILE*) user); -} - -static stbi_io_callbacks stbi__stdio_callbacks = -{ - stbi__stdio_read, - stbi__stdio_skip, - stbi__stdio_eof, -}; - -static void stbi__start_file(stbi__context *s, FILE *f) -{ - stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); -} - -//static void stop_file(stbi__context *s) { } - -#endif // !STBI_NO_STDIO - -static void stbi__rewind(stbi__context *s) -{ - // conceptually rewind SHOULD rewind to the beginning of the stream, - // but we just rewind to the beginning of the initial buffer, because - // we only use it after doing 'test', which only ever looks at at most 92 bytes - s->img_buffer = s->img_buffer_original; -} - -#ifndef STBI_NO_JPEG -static int stbi__jpeg_test(stbi__context *s); -static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PNG -static int stbi__png_test(stbi__context *s); -static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_BMP -static int stbi__bmp_test(stbi__context *s); -static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_TGA -static int stbi__tga_test(stbi__context *s); -static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s); -static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_HDR -static int stbi__hdr_test(stbi__context *s); -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PIC -static int stbi__pic_test(stbi__context *s); -static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_GIF -static int stbi__gif_test(stbi__context *s); -static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -#ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s); -static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); -#endif - -// this is not threadsafe -static const char *stbi__g_failure_reason; - -STBIDEF const char *stbi_failure_reason(void) -{ - return stbi__g_failure_reason; -} - -static int stbi__err(const char *str) -{ - stbi__g_failure_reason = str; - return 0; -} - -static void *stbi__malloc(size_t size) -{ - return STBI_MALLOC(size); -} - -// stbi__err - error -// stbi__errpf - error returning pointer to float -// stbi__errpuc - error returning pointer to unsigned char - -#ifdef STBI_NO_FAILURE_STRINGS - #define stbi__err(x,y) 0 -#elif defined(STBI_FAILURE_USERMSG) - #define stbi__err(x,y) stbi__err(y) -#else - #define stbi__err(x,y) stbi__err(x) -#endif - -#define stbi__errpf(x,y) ((float *) (stbi__err(x,y)?NULL:NULL)) -#define stbi__errpuc(x,y) ((unsigned char *) (stbi__err(x,y)?NULL:NULL)) - -STBIDEF void stbi_image_free(void *retval_from_stbi_load) -{ - STBI_FREE(retval_from_stbi_load); -} - -#ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); -#endif - -#ifndef STBI_NO_HDR -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); -#endif - -static unsigned char *stbi_load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_PNG - if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_BMP - if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_GIF - if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_PSD - if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_PIC - if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp); - #endif - #ifndef STBI_NO_PNM - if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp); - #endif - - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - float *hdr = stbi__hdr_load(s, x,y,comp,req_comp); - return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); - } - #endif - - #ifndef STBI_NO_TGA - // test tga last because it's a crappy test! - if (stbi__tga_test(s)) - return stbi__tga_load(s,x,y,comp,req_comp); - #endif - - return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); -} - -#ifndef STBI_NO_STDIO - -static FILE *stbi__fopen(char const *filename, char const *mode) -{ - FILE *f; -#if defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != fopen_s(&f, filename, mode)) - f=0; -#else - f = fopen(filename, mode); -#endif - return f; -} - - -STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - unsigned char *result; - if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi_load_main(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; -} -#endif //!STBI_NO_STDIO - -STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi_load_main(&s,x,y,comp,req_comp); -} - -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi_load_main(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_LINEAR -static float *stbi_loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) - return stbi__hdr_load(s,x,y,comp,req_comp); - #endif - data = stbi_load_main(s, x, y, comp, req_comp); - if (data) - return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); - return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); -} - -STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi_loadf_main(&s,x,y,comp,req_comp); -} - -STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi_loadf_main(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_STDIO -STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - float *result; - FILE *f = stbi__fopen(filename, "rb"); - if (!f) return stbi__errpf("can't fopen", "Unable to open file"); - result = stbi_loadf_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; -} - -STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_file(&s,f); - return stbi_loadf_main(&s,x,y,comp,req_comp); -} -#endif // !STBI_NO_STDIO - -#endif // !STBI_NO_LINEAR - -// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is -// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always -// reports false! - -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(buffer); - STBI_NOTUSED(len); - return 0; - #endif -} - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result=0; - if (f) { - result = stbi_is_hdr_from_file(f); - fclose(f); - } - return result; -} - -STBIDEF int stbi_is_hdr_from_file(FILE *f) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_file(&s,f); - return stbi__hdr_test(&s); - #else - return 0; - #endif -} -#endif // !STBI_NO_STDIO - -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__hdr_test(&s); - #else - return 0; - #endif -} - -static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; -static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; - -#ifndef STBI_NO_LINEAR -STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } -STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } -#endif - -STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } -STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } - - -////////////////////////////////////////////////////////////////////////////// -// -// Common code used by all image loaders -// - -enum -{ - STBI__SCAN_load=0, - STBI__SCAN_type, - STBI__SCAN_header -}; - -static void stbi__refill_buffer(stbi__context *s) -{ - int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); - if (n == 0) { - // at end of file, treat same as if from memory, but need to handle case - // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file - s->read_from_callbacks = 0; - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start+1; - *s->img_buffer = 0; - } else { - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start + n; - } -} - -stbi_inline static stbi_uc stbi__get8(stbi__context *s) -{ - if (s->img_buffer < s->img_buffer_end) - return *s->img_buffer++; - if (s->read_from_callbacks) { - stbi__refill_buffer(s); - return *s->img_buffer++; - } - return 0; -} - -stbi_inline static int stbi__at_eof(stbi__context *s) -{ - if (s->io.read) { - if (!(s->io.eof)(s->io_user_data)) return 0; - // if feof() is true, check if buffer = end - // special case: we've only got the special 0 character at the end - if (s->read_from_callbacks == 0) return 1; - } - - return s->img_buffer >= s->img_buffer_end; -} - -static void stbi__skip(stbi__context *s, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - s->img_buffer = s->img_buffer_end; - (s->io.skip)(s->io_user_data, n - blen); - return; - } - } - s->img_buffer += n; -} - -static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - int res, count; - - memcpy(buffer, s->img_buffer, blen); - - count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); - res = (count == (n-blen)); - s->img_buffer = s->img_buffer_end; - return res; - } - } - - if (s->img_buffer+n <= s->img_buffer_end) { - memcpy(buffer, s->img_buffer, n); - s->img_buffer += n; - return 1; - } else - return 0; -} - -static int stbi__get16be(stbi__context *s) -{ - int z = stbi__get8(s); - return (z << 8) + stbi__get8(s); -} - -static stbi__uint32 stbi__get32be(stbi__context *s) -{ - stbi__uint32 z = stbi__get16be(s); - return (z << 16) + stbi__get16be(s); -} - -static int stbi__get16le(stbi__context *s) -{ - int z = stbi__get8(s); - return z + (stbi__get8(s) << 8); -} - -static stbi__uint32 stbi__get32le(stbi__context *s) -{ - stbi__uint32 z = stbi__get16le(s); - return z + (stbi__get16le(s) << 16); -} - -#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings - - -////////////////////////////////////////////////////////////////////////////// -// -// generic converter from built-in img_n to req_comp -// individual types do this automatically as much as possible (e.g. jpeg -// does all cases internally since it needs to colorspace convert anyway, -// and it never has alpha, so very few cases ). png can automatically -// interleave an alpha=255 channel, but falls back to this for other cases -// -// assume data buffer is malloced, so malloc a new one and free that one -// only failure mode is malloc failing - -static stbi_uc stbi__compute_y(int r, int g, int b) -{ - return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); -} - -static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - unsigned char *good; - - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - - good = (unsigned char *) stbi__malloc(req_comp * x * y); - if (good == NULL) { - STBI_FREE(data); - return stbi__errpuc("outofmem", "Out of memory"); - } - - for (j=0; j < (int) y; ++j) { - unsigned char *src = data + j * x * img_n ; - unsigned char *dest = good + j * x * req_comp; - - #define COMBO(a,b) ((a)*8+(b)) - #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (COMBO(img_n, req_comp)) { - CASE(1,2) dest[0]=src[0], dest[1]=255; break; - CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; - CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; - CASE(2,1) dest[0]=src[0]; break; - CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; - CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; - CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; - CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; - CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break; - CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; - CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; - CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; - default: STBI_ASSERT(0); - } - #undef CASE - } - - STBI_FREE(data); - return good; -} - -#ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) -{ - int i,k,n; - float *output = (float *) stbi__malloc(x * y * comp * sizeof(float)); - if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); - } - if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; - } - STBI_FREE(data); - return output; -} -#endif - -#ifndef STBI_NO_HDR -#define stbi__float2int(x) ((int) (x)) -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) -{ - int i,k,n; - stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp); - if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - if (k < comp) { - float z = data[i*comp+k] * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - } - STBI_FREE(data); - return output; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// "baseline" JPEG/JFIF decoder -// -// simple implementation -// - doesn't support delayed output of y-dimension -// - simple interface (only one output format: 8-bit interleaved RGB) -// - doesn't try to recover corrupt jpegs -// - doesn't allow partial loading, loading multiple at once -// - still fast on x86 (copying globals into locals doesn't help x86) -// - allocates lots of intermediate memory (full size of all components) -// - non-interleaved case requires this anyway -// - allows good upsampling (see next) -// high-quality -// - upsampled channels are bilinearly interpolated, even across blocks -// - quality integer IDCT derived from IJG's 'slow' -// performance -// - fast huffman; reasonable integer IDCT -// - some SIMD kernels for common paths on targets with SSE2/NEON -// - uses a lot of intermediate memory, could cache poorly - -#ifndef STBI_NO_JPEG - -// huffman decoding acceleration -#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache - -typedef struct -{ - stbi_uc fast[1 << FAST_BITS]; - // weirdly, repacking this into AoS is a 10% speed loss, instead of a win - stbi__uint16 code[256]; - stbi_uc values[256]; - stbi_uc size[257]; - unsigned int maxcode[18]; - int delta[17]; // old 'firstsymbol' - old 'firstcode' -} stbi__huffman; - -typedef struct -{ - stbi__context *s; - stbi__huffman huff_dc[4]; - stbi__huffman huff_ac[4]; - stbi_uc dequant[4][64]; - stbi__int16 fast_ac[4][1 << FAST_BITS]; - -// sizes for components, interleaved MCUs - int img_h_max, img_v_max; - int img_mcu_x, img_mcu_y; - int img_mcu_w, img_mcu_h; - -// definition of jpeg image component - struct - { - int id; - int h,v; - int tq; - int hd,ha; - int dc_pred; - - int x,y,w2,h2; - stbi_uc *data; - void *raw_data, *raw_coeff; - stbi_uc *linebuf; - short *coeff; // progressive only - int coeff_w, coeff_h; // number of 8x8 coefficient blocks - } img_comp[4]; - - stbi__uint32 code_buffer; // jpeg entropy-coded buffer - int code_bits; // number of valid bits - unsigned char marker; // marker seen while filling entropy buffer - int nomore; // flag if we saw a marker so must stop - - int progressive; - int spec_start; - int spec_end; - int succ_high; - int succ_low; - int eob_run; - - int scan_n, order[4]; - int restart_interval, todo; - -// kernels - void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); - void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); - stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); -} stbi__jpeg; - -static int stbi__build_huffman(stbi__huffman *h, int *count) -{ - int i,j,k=0,code; - // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) - h->size[k++] = (stbi_uc) (i+1); - h->size[k] = 0; - - // compute actual symbols (from jpeg spec) - code = 0; - k = 0; - for(j=1; j <= 16; ++j) { - // compute delta to add to code to compute symbol id - h->delta[j] = k - code; - if (h->size[k] == j) { - while (h->size[k] == j) - h->code[k++] = (stbi__uint16) (code++); - if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); - } - // compute largest code + 1 for this size, preshifted as needed later - h->maxcode[j] = code << (16-j); - code <<= 1; - } - h->maxcode[j] = 0xffffffff; - - // build non-spec acceleration table; 255 is flag for not-accelerated - memset(h->fast, 255, 1 << FAST_BITS); - for (i=0; i < k; ++i) { - int s = h->size[i]; - if (s <= FAST_BITS) { - int c = h->code[i] << (FAST_BITS-s); - int m = 1 << (FAST_BITS-s); - for (j=0; j < m; ++j) { - h->fast[c+j] = (stbi_uc) i; - } - } - } - return 1; -} - -// build a table that decodes both magnitude and value of small ACs in -// one go. -static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) -{ - int i; - for (i=0; i < (1 << FAST_BITS); ++i) { - stbi_uc fast = h->fast[i]; - fast_ac[i] = 0; - if (fast < 255) { - int rs = h->values[fast]; - int run = (rs >> 4) & 15; - int magbits = rs & 15; - int len = h->size[fast]; - - if (magbits && len + magbits <= FAST_BITS) { - // magnitude code followed by receive_extend code - int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); - int m = 1 << (magbits - 1); - if (k < m) k += (-1 << magbits) + 1; - // if the result is small enough, we can fit it in fast_ac table - if (k >= -128 && k <= 127) - fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); - } - } - } -} - -static void stbi__grow_buffer_unsafe(stbi__jpeg *j) -{ - do { - int b = j->nomore ? 0 : stbi__get8(j->s); - if (b == 0xff) { - int c = stbi__get8(j->s); - if (c != 0) { - j->marker = (unsigned char) c; - j->nomore = 1; - return; - } - } - j->code_buffer |= b << (24 - j->code_bits); - j->code_bits += 8; - } while (j->code_bits <= 24); -} - -// (1 << n) - 1 -static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; - -// decode a jpeg huffman value from the bitstream -stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) -{ - unsigned int temp; - int c,k; - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - - // look at the top FAST_BITS and determine what symbol ID it is, - // if the code is <= FAST_BITS - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - k = h->fast[c]; - if (k < 255) { - int s = h->size[k]; - if (s > j->code_bits) - return -1; - j->code_buffer <<= s; - j->code_bits -= s; - return h->values[k]; - } - - // naive test is to shift the code_buffer down so k bits are - // valid, then test against maxcode. To speed this up, we've - // preshifted maxcode left so that it has (16-k) 0s at the - // end; in other words, regardless of the number of bits, it - // wants to be compared against something shifted to have 16; - // that way we don't need to shift inside the loop. - temp = j->code_buffer >> 16; - for (k=FAST_BITS+1 ; ; ++k) - if (temp < h->maxcode[k]) - break; - if (k == 17) { - // error! code not found - j->code_bits -= 16; - return -1; - } - - if (k > j->code_bits) - return -1; - - // convert the huffman code to the symbol id - c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; - STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); - - // convert the id to a symbol - j->code_bits -= k; - j->code_buffer <<= k; - return h->values[c]; -} - -// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); - - sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k + (stbi__jbias[n] & ~sgn); -} - -// get some unsigned bits -stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) -{ - unsigned int k; - if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k; -} - -stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) -{ - unsigned int k; - if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); - k = j->code_buffer; - j->code_buffer <<= 1; - --j->code_bits; - return k & 0x80000000; -} - -// given a value that's at position X in the zigzag stream, -// where does it appear in the 8x8 matrix coded as row-major? -static stbi_uc stbi__jpeg_dezigzag[64+15] = -{ - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - // let corrupt input sample past end - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63 -}; - -// decode one 64-entry block-- -static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant) -{ - int diff,dc,k; - int t; - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - - // 0 all the ac values now so we can do it 32-bits at a time - memset(data,0,64*sizeof(data[0])); - - diff = t ? stbi__extend_receive(j, t) : 0; - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc * dequant[0]); - - // decode AC components, see JPEG spec - k = 1; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * dequant[zig]); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (rs != 0xf0) break; // end block - k += 16; - } else { - k += r; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); - } - } - } while (k < 64); - return 1; -} - -static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) -{ - int diff,dc; - int t; - if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - - if (j->succ_high == 0) { - // first scan for DC coefficient, must be first - memset(data,0,64*sizeof(data[0])); // 0 all the ac values now - t = stbi__jpeg_huff_decode(j, hdc); - diff = t ? stbi__extend_receive(j, t) : 0; - - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc << j->succ_low); - } else { - // refinement scan for DC coefficient - if (stbi__jpeg_get_bit(j)) - data[0] += (short) (1 << j->succ_low); - } - return 1; -} - -// @OPTIMIZE: store non-zigzagged during the decode passes, -// and only de-zigzag when dequantizing -static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) -{ - int k; - if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - - if (j->succ_high == 0) { - int shift = j->succ_low; - - if (j->eob_run) { - --j->eob_run; - return 1; - } - - k = j->spec_start; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) << shift); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r); - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - --j->eob_run; - break; - } - k += 16; - } else { - k += r; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) << shift); - } - } - } while (k <= j->spec_end); - } else { - // refinement scan for these AC coefficients - - short bit = (short) (1 << j->succ_low); - - if (j->eob_run) { - --j->eob_run; - for (k = j->spec_start; k <= j->spec_end; ++k) { - short *p = &data[stbi__jpeg_dezigzag[k]]; - if (*p != 0) - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } - } else { - k = j->spec_start; - do { - int r,s; - int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r) - 1; - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - r = 64; // force end of block - } else - r = 16; // r=15 is the code for 16 0s - } else { - if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); - // sign bit - if (stbi__jpeg_get_bit(j)) - s = bit; - else - s = -bit; - } - - // advance by r - while (k <= j->spec_end) { - short *p = &data[stbi__jpeg_dezigzag[k]]; - if (*p != 0) { - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - ++k; - } else { - if (r == 0) { - if (s) - data[stbi__jpeg_dezigzag[k++]] = (short) s; - break; - } - --r; - ++k; - } - } - } while (k <= j->spec_end); - } - } - return 1; -} - -// take a -128..127 value and stbi__clamp it and convert to 0..255 -stbi_inline static stbi_uc stbi__clamp(int x) -{ - // trick to use a single test to catch both cases - if ((unsigned int) x > 255) { - if (x < 0) return 0; - if (x > 255) return 255; - } - return (stbi_uc) x; -} - -#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) -#define stbi__fsh(x) ((x) << 12) - -// derived from jidctint -- DCT_ISLOW -#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ - int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ - p2 = s2; \ - p3 = s6; \ - p1 = (p2+p3) * stbi__f2f(0.5411961f); \ - t2 = p1 + p3*stbi__f2f(-1.847759065f); \ - t3 = p1 + p2*stbi__f2f( 0.765366865f); \ - p2 = s0; \ - p3 = s4; \ - t0 = stbi__fsh(p2+p3); \ - t1 = stbi__fsh(p2-p3); \ - x0 = t0+t3; \ - x3 = t0-t3; \ - x1 = t1+t2; \ - x2 = t1-t2; \ - t0 = s7; \ - t1 = s5; \ - t2 = s3; \ - t3 = s1; \ - p3 = t0+t2; \ - p4 = t1+t3; \ - p1 = t0+t3; \ - p2 = t1+t2; \ - p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ - t0 = t0*stbi__f2f( 0.298631336f); \ - t1 = t1*stbi__f2f( 2.053119869f); \ - t2 = t2*stbi__f2f( 3.072711026f); \ - t3 = t3*stbi__f2f( 1.501321110f); \ - p1 = p5 + p1*stbi__f2f(-0.899976223f); \ - p2 = p5 + p2*stbi__f2f(-2.562915447f); \ - p3 = p3*stbi__f2f(-1.961570560f); \ - p4 = p4*stbi__f2f(-0.390180644f); \ - t3 += p1+p4; \ - t2 += p2+p3; \ - t1 += p2+p4; \ - t0 += p1+p3; - -static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) -{ - int i,val[64],*v=val; - stbi_uc *o; - short *d = data; - - // columns - for (i=0; i < 8; ++i,++d, ++v) { - // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing - if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 - && d[40]==0 && d[48]==0 && d[56]==0) { - // no shortcut 0 seconds - // (1|2|3|4|5|6|7)==0 0 seconds - // all separate -0.047 seconds - // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds - int dcterm = d[0] << 2; - v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; - } else { - STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) - // constants scaled things up by 1<<12; let's bring them back - // down, but keep 2 extra bits of precision - x0 += 512; x1 += 512; x2 += 512; x3 += 512; - v[ 0] = (x0+t3) >> 10; - v[56] = (x0-t3) >> 10; - v[ 8] = (x1+t2) >> 10; - v[48] = (x1-t2) >> 10; - v[16] = (x2+t1) >> 10; - v[40] = (x2-t1) >> 10; - v[24] = (x3+t0) >> 10; - v[32] = (x3-t0) >> 10; - } - } - - for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { - // no fast case since the first 1D IDCT spread components out - STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) - // constants scaled things up by 1<<12, plus we had 1<<2 from first - // loop, plus horizontal and vertical each scale by sqrt(8) so together - // we've got an extra 1<<3, so 1<<17 total we need to remove. - // so we want to round that, which means adding 0.5 * 1<<17, - // aka 65536. Also, we'll end up with -128 to 127 that we want - // to encode as 0..255 by adding 128, so we'll add that before the shift - x0 += 65536 + (128<<17); - x1 += 65536 + (128<<17); - x2 += 65536 + (128<<17); - x3 += 65536 + (128<<17); - // tried computing the shifts into temps, or'ing the temps to see - // if any were out of range, but that was slower - o[0] = stbi__clamp((x0+t3) >> 17); - o[7] = stbi__clamp((x0-t3) >> 17); - o[1] = stbi__clamp((x1+t2) >> 17); - o[6] = stbi__clamp((x1-t2) >> 17); - o[2] = stbi__clamp((x2+t1) >> 17); - o[5] = stbi__clamp((x2-t1) >> 17); - o[3] = stbi__clamp((x3+t0) >> 17); - o[4] = stbi__clamp((x3-t0) >> 17); - } -} - -#ifdef STBI_SSE2 -// sse2 integer IDCT. not the fastest possible implementation but it -// produces bit-identical results to the generic C version so it's -// fully "transparent". -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - // This is constructed to match our regular (generic) integer IDCT exactly. - __m128i row0, row1, row2, row3, row4, row5, row6, row7; - __m128i tmp; - - // dot product constant: even elems=x, odd elems=y - #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) - - // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) - // out(1) = c1[even]*x + c1[odd]*y - #define dct_rot(out0,out1, x,y,c0,c1) \ - __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ - __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ - __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ - __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ - __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ - __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) - - // out = in << 12 (in 16-bit, out 32-bit) - #define dct_widen(out, in) \ - __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ - __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) - - // wide add - #define dct_wadd(out, a, b) \ - __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_add_epi32(a##_h, b##_h) - - // wide sub - #define dct_wsub(out, a, b) \ - __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) - - // butterfly a/b, add bias, then shift by "s" and pack - #define dct_bfly32o(out0, out1, a,b,bias,s) \ - { \ - __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ - __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ - dct_wadd(sum, abiased, b); \ - dct_wsub(dif, abiased, b); \ - out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ - out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ - } - - // 8-bit interleave step (for transposes) - #define dct_interleave8(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi8(a, b); \ - b = _mm_unpackhi_epi8(tmp, b) - - // 16-bit interleave step (for transposes) - #define dct_interleave16(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi16(a, b); \ - b = _mm_unpackhi_epi16(tmp, b) - - #define dct_pass(bias,shift) \ - { \ - /* even part */ \ - dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ - __m128i sum04 = _mm_add_epi16(row0, row4); \ - __m128i dif04 = _mm_sub_epi16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ - dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ - __m128i sum17 = _mm_add_epi16(row1, row7); \ - __m128i sum35 = _mm_add_epi16(row3, row5); \ - dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ - dct_wadd(x4, y0o, y4o); \ - dct_wadd(x5, y1o, y5o); \ - dct_wadd(x6, y2o, y5o); \ - dct_wadd(x7, y3o, y4o); \ - dct_bfly32o(row0,row7, x0,x7,bias,shift); \ - dct_bfly32o(row1,row6, x1,x6,bias,shift); \ - dct_bfly32o(row2,row5, x2,x5,bias,shift); \ - dct_bfly32o(row3,row4, x3,x4,bias,shift); \ - } - - __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); - __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); - __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); - __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); - __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); - __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); - __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); - __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); - - // rounding biases in column/row passes, see stbi__idct_block for explanation. - __m128i bias_0 = _mm_set1_epi32(512); - __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); - - // load - row0 = _mm_load_si128((const __m128i *) (data + 0*8)); - row1 = _mm_load_si128((const __m128i *) (data + 1*8)); - row2 = _mm_load_si128((const __m128i *) (data + 2*8)); - row3 = _mm_load_si128((const __m128i *) (data + 3*8)); - row4 = _mm_load_si128((const __m128i *) (data + 4*8)); - row5 = _mm_load_si128((const __m128i *) (data + 5*8)); - row6 = _mm_load_si128((const __m128i *) (data + 6*8)); - row7 = _mm_load_si128((const __m128i *) (data + 7*8)); - - // column pass - dct_pass(bias_0, 10); - - { - // 16bit 8x8 transpose pass 1 - dct_interleave16(row0, row4); - dct_interleave16(row1, row5); - dct_interleave16(row2, row6); - dct_interleave16(row3, row7); - - // transpose pass 2 - dct_interleave16(row0, row2); - dct_interleave16(row1, row3); - dct_interleave16(row4, row6); - dct_interleave16(row5, row7); - - // transpose pass 3 - dct_interleave16(row0, row1); - dct_interleave16(row2, row3); - dct_interleave16(row4, row5); - dct_interleave16(row6, row7); - } - - // row pass - dct_pass(bias_1, 17); - - { - // pack - __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 - __m128i p1 = _mm_packus_epi16(row2, row3); - __m128i p2 = _mm_packus_epi16(row4, row5); - __m128i p3 = _mm_packus_epi16(row6, row7); - - // 8bit 8x8 transpose pass 1 - dct_interleave8(p0, p2); // a0e0a1e1... - dct_interleave8(p1, p3); // c0g0c1g1... - - // transpose pass 2 - dct_interleave8(p0, p1); // a0c0e0g0... - dct_interleave8(p2, p3); // b0d0f0h0... - - // transpose pass 3 - dct_interleave8(p0, p2); // a0b0c0d0... - dct_interleave8(p1, p3); // a4b4c4d4... - - // store - _mm_storel_epi64((__m128i *) out, p0); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p2); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p1); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p3); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); - } - -#undef dct_const -#undef dct_rot -#undef dct_widen -#undef dct_wadd -#undef dct_wsub -#undef dct_bfly32o -#undef dct_interleave8 -#undef dct_interleave16 -#undef dct_pass -} - -#endif // STBI_SSE2 - -#ifdef STBI_NEON - -// NEON integer IDCT. should produce bit-identical -// results to the generic C version. -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; - - int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); - int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); - int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); - int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); - int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); - int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); - int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); - int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); - int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); - int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); - int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); - int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); - -#define dct_long_mul(out, inq, coeff) \ - int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) - -#define dct_long_mac(out, acc, inq, coeff) \ - int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) - -#define dct_widen(out, inq) \ - int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ - int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) - -// wide add -#define dct_wadd(out, a, b) \ - int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vaddq_s32(a##_h, b##_h) - -// wide sub -#define dct_wsub(out, a, b) \ - int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vsubq_s32(a##_h, b##_h) - -// butterfly a/b, then shift using "shiftop" by "s" and pack -#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ - { \ - dct_wadd(sum, a, b); \ - dct_wsub(dif, a, b); \ - out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ - out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ - } - -#define dct_pass(shiftop, shift) \ - { \ - /* even part */ \ - int16x8_t sum26 = vaddq_s16(row2, row6); \ - dct_long_mul(p1e, sum26, rot0_0); \ - dct_long_mac(t2e, p1e, row6, rot0_1); \ - dct_long_mac(t3e, p1e, row2, rot0_2); \ - int16x8_t sum04 = vaddq_s16(row0, row4); \ - int16x8_t dif04 = vsubq_s16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - int16x8_t sum15 = vaddq_s16(row1, row5); \ - int16x8_t sum17 = vaddq_s16(row1, row7); \ - int16x8_t sum35 = vaddq_s16(row3, row5); \ - int16x8_t sum37 = vaddq_s16(row3, row7); \ - int16x8_t sumodd = vaddq_s16(sum17, sum35); \ - dct_long_mul(p5o, sumodd, rot1_0); \ - dct_long_mac(p1o, p5o, sum17, rot1_1); \ - dct_long_mac(p2o, p5o, sum35, rot1_2); \ - dct_long_mul(p3o, sum37, rot2_0); \ - dct_long_mul(p4o, sum15, rot2_1); \ - dct_wadd(sump13o, p1o, p3o); \ - dct_wadd(sump24o, p2o, p4o); \ - dct_wadd(sump23o, p2o, p3o); \ - dct_wadd(sump14o, p1o, p4o); \ - dct_long_mac(x4, sump13o, row7, rot3_0); \ - dct_long_mac(x5, sump24o, row5, rot3_1); \ - dct_long_mac(x6, sump23o, row3, rot3_2); \ - dct_long_mac(x7, sump14o, row1, rot3_3); \ - dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ - dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ - dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ - dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ - } - - // load - row0 = vld1q_s16(data + 0*8); - row1 = vld1q_s16(data + 1*8); - row2 = vld1q_s16(data + 2*8); - row3 = vld1q_s16(data + 3*8); - row4 = vld1q_s16(data + 4*8); - row5 = vld1q_s16(data + 5*8); - row6 = vld1q_s16(data + 6*8); - row7 = vld1q_s16(data + 7*8); - - // add DC bias - row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); - - // column pass - dct_pass(vrshrn_n_s32, 10); - - // 16bit 8x8 transpose - { -// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. -// whether compilers actually get this is another story, sadly. -#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } -#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } - - // pass 1 - dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 - dct_trn16(row2, row3); - dct_trn16(row4, row5); - dct_trn16(row6, row7); - - // pass 2 - dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 - dct_trn32(row1, row3); - dct_trn32(row4, row6); - dct_trn32(row5, row7); - - // pass 3 - dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 - dct_trn64(row1, row5); - dct_trn64(row2, row6); - dct_trn64(row3, row7); - -#undef dct_trn16 -#undef dct_trn32 -#undef dct_trn64 - } - - // row pass - // vrshrn_n_s32 only supports shifts up to 16, we need - // 17. so do a non-rounding shift of 16 first then follow - // up with a rounding shift by 1. - dct_pass(vshrn_n_s32, 16); - - { - // pack and round - uint8x8_t p0 = vqrshrun_n_s16(row0, 1); - uint8x8_t p1 = vqrshrun_n_s16(row1, 1); - uint8x8_t p2 = vqrshrun_n_s16(row2, 1); - uint8x8_t p3 = vqrshrun_n_s16(row3, 1); - uint8x8_t p4 = vqrshrun_n_s16(row4, 1); - uint8x8_t p5 = vqrshrun_n_s16(row5, 1); - uint8x8_t p6 = vqrshrun_n_s16(row6, 1); - uint8x8_t p7 = vqrshrun_n_s16(row7, 1); - - // again, these can translate into one instruction, but often don't. -#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } -#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } - - // sadly can't use interleaved stores here since we only write - // 8 bytes to each scan line! - - // 8x8 8-bit transpose pass 1 - dct_trn8_8(p0, p1); - dct_trn8_8(p2, p3); - dct_trn8_8(p4, p5); - dct_trn8_8(p6, p7); - - // pass 2 - dct_trn8_16(p0, p2); - dct_trn8_16(p1, p3); - dct_trn8_16(p4, p6); - dct_trn8_16(p5, p7); - - // pass 3 - dct_trn8_32(p0, p4); - dct_trn8_32(p1, p5); - dct_trn8_32(p2, p6); - dct_trn8_32(p3, p7); - - // store - vst1_u8(out, p0); out += out_stride; - vst1_u8(out, p1); out += out_stride; - vst1_u8(out, p2); out += out_stride; - vst1_u8(out, p3); out += out_stride; - vst1_u8(out, p4); out += out_stride; - vst1_u8(out, p5); out += out_stride; - vst1_u8(out, p6); out += out_stride; - vst1_u8(out, p7); - -#undef dct_trn8_8 -#undef dct_trn8_16 -#undef dct_trn8_32 - } - -#undef dct_long_mul -#undef dct_long_mac -#undef dct_widen -#undef dct_wadd -#undef dct_wsub -#undef dct_bfly32o -#undef dct_pass -} - -#endif // STBI_NEON - -#define STBI__MARKER_none 0xff -// if there's a pending marker from the entropy stream, return that -// otherwise, fetch from the stream and get a marker. if there's no -// marker, return 0xff, which is never a valid marker value -static stbi_uc stbi__get_marker(stbi__jpeg *j) -{ - stbi_uc x; - if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } - x = stbi__get8(j->s); - if (x != 0xff) return STBI__MARKER_none; - while (x == 0xff) - x = stbi__get8(j->s); - return x; -} - -// in each scan, we'll have scan_n components, and the order -// of the components is specified by order[] -#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) - -// after a restart interval, stbi__jpeg_reset the entropy decoder and -// the dc prediction -static void stbi__jpeg_reset(stbi__jpeg *j) -{ - j->code_bits = 0; - j->code_buffer = 0; - j->nomore = 0; - j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; - j->marker = STBI__MARKER_none; - j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; - j->eob_run = 0; - // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, - // since we don't even allow 1<<30 pixels -} - -static int stbi__parse_entropy_coded_data(stbi__jpeg *z) -{ - stbi__jpeg_reset(z); - if (!z->progressive) { - if (z->scan_n == 1) { - int i,j; - STBI_SIMD_ALIGN(short, data[64]); - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - STBI_SIMD_ALIGN(short, data[64]); - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x)*8; - int y2 = (j*z->img_comp[n].v + y)*8; - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } else { - if (z->scan_n == 1) { - int i,j; - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - if (z->spec_start == 0) { - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } else { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) - return 0; - } - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x); - int y2 = (j*z->img_comp[n].v + y); - short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } -} - -static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) -{ - int i; - for (i=0; i < 64; ++i) - data[i] *= dequant[i]; -} - -static void stbi__jpeg_finish(stbi__jpeg *z) -{ - if (z->progressive) { - // dequantize and idct the data - int i,j,n; - for (n=0; n < z->s->img_n; ++n) { - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - } - } - } - } -} - -static int stbi__process_marker(stbi__jpeg *z, int m) -{ - int L; - switch (m) { - case STBI__MARKER_none: // no marker found - return stbi__err("expected marker","Corrupt JPEG"); - - case 0xDD: // DRI - specify restart interval - if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); - z->restart_interval = stbi__get16be(z->s); - return 1; - - case 0xDB: // DQT - define quantization table - L = stbi__get16be(z->s)-2; - while (L > 0) { - int q = stbi__get8(z->s); - int p = q >> 4; - int t = q & 15,i; - if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG"); - if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); - for (i=0; i < 64; ++i) - z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s); - L -= 65; - } - return L==0; - - case 0xC4: // DHT - define huffman table - L = stbi__get16be(z->s)-2; - while (L > 0) { - stbi_uc *v; - int sizes[16],i,n=0; - int q = stbi__get8(z->s); - int tc = q >> 4; - int th = q & 15; - if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); - for (i=0; i < 16; ++i) { - sizes[i] = stbi__get8(z->s); - n += sizes[i]; - } - L -= 17; - if (tc == 0) { - if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; - v = z->huff_dc[th].values; - } else { - if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; - v = z->huff_ac[th].values; - } - for (i=0; i < n; ++i) - v[i] = stbi__get8(z->s); - if (tc != 0) - stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); - L -= n; - } - return L==0; - } - // check for comment block or APP blocks - if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - stbi__skip(z->s, stbi__get16be(z->s)-2); - return 1; - } - return 0; -} - -// after we see SOS -static int stbi__process_scan_header(stbi__jpeg *z) -{ - int i; - int Ls = stbi__get16be(z->s); - z->scan_n = stbi__get8(z->s); - if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); - if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); - for (i=0; i < z->scan_n; ++i) { - int id = stbi__get8(z->s), which; - int q = stbi__get8(z->s); - for (which = 0; which < z->s->img_n; ++which) - if (z->img_comp[which].id == id) - break; - if (which == z->s->img_n) return 0; // no match - z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); - z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); - z->order[i] = which; - } - - { - int aa; - z->spec_start = stbi__get8(z->s); - z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 - aa = stbi__get8(z->s); - z->succ_high = (aa >> 4); - z->succ_low = (aa & 15); - if (z->progressive) { - if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) - return stbi__err("bad SOS", "Corrupt JPEG"); - } else { - if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); - if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); - z->spec_end = 63; - } - } - - return 1; -} - -static int stbi__process_frame_header(stbi__jpeg *z, int scan) -{ - stbi__context *s = z->s; - int Lf,p,i,q, h_max=1,v_max=1,c; - Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG - p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline - s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG - s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires - c = stbi__get8(s); - if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG"); // JFIF requires - s->img_n = c; - for (i=0; i < c; ++i) { - z->img_comp[i].data = NULL; - z->img_comp[i].linebuf = NULL; - } - - if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); - - for (i=0; i < s->img_n; ++i) { - z->img_comp[i].id = stbi__get8(s); - if (z->img_comp[i].id != i+1) // JFIF requires - if (z->img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! - return stbi__err("bad component ID","Corrupt JPEG"); - q = stbi__get8(s); - z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); - z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); - z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); - } - - if (scan != STBI__SCAN_load) return 1; - - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - - for (i=0; i < s->img_n; ++i) { - if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; - if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; - } - - // compute interleaved mcu info - z->img_h_max = h_max; - z->img_v_max = v_max; - z->img_mcu_w = h_max * 8; - z->img_mcu_h = v_max * 8; - z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; - z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; - - for (i=0; i < s->img_n; ++i) { - // number of effective pixels (e.g. for non-interleaved MCU) - z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; - z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; - // to simplify generation, we'll allocate enough memory to decode - // the bogus oversized data from using interleaved MCUs and their - // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't - // discard the extra data until colorspace conversion - z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; - z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; - z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); - - if (z->img_comp[i].raw_data == NULL) { - for(--i; i >= 0; --i) { - STBI_FREE(z->img_comp[i].raw_data); - z->img_comp[i].data = NULL; - } - return stbi__err("outofmem", "Out of memory"); - } - // align blocks for idct using mmx/sse - z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); - z->img_comp[i].linebuf = NULL; - if (z->progressive) { - z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3; - z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3; - z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15); - z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); - } else { - z->img_comp[i].coeff = 0; - z->img_comp[i].raw_coeff = 0; - } - } - - return 1; -} - -// use comparisons since in some cases we handle more than one case (e.g. SOF) -#define stbi__DNL(x) ((x) == 0xdc) -#define stbi__SOI(x) ((x) == 0xd8) -#define stbi__EOI(x) ((x) == 0xd9) -#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) -#define stbi__SOS(x) ((x) == 0xda) - -#define stbi__SOF_progressive(x) ((x) == 0xc2) - -static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) -{ - int m; - z->marker = STBI__MARKER_none; // initialize cached marker to empty - m = stbi__get_marker(z); - if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); - if (scan == STBI__SCAN_type) return 1; - m = stbi__get_marker(z); - while (!stbi__SOF(m)) { - if (!stbi__process_marker(z,m)) return 0; - m = stbi__get_marker(z); - while (m == STBI__MARKER_none) { - // some files have extra padding after their blocks, so ok, we'll scan - if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); - m = stbi__get_marker(z); - } - } - z->progressive = stbi__SOF_progressive(m); - if (!stbi__process_frame_header(z, scan)) return 0; - return 1; -} - -// decode image to YCbCr format -static int stbi__decode_jpeg_image(stbi__jpeg *j) -{ - int m; - j->restart_interval = 0; - if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; - m = stbi__get_marker(j); - while (!stbi__EOI(m)) { - if (stbi__SOS(m)) { - if (!stbi__process_scan_header(j)) return 0; - if (!stbi__parse_entropy_coded_data(j)) return 0; - if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } else if (x != 0) { - return stbi__err("junk before marker", "Corrupt JPEG"); - } - } - // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 - } - } else { - if (!stbi__process_marker(j, m)) return 0; - } - m = stbi__get_marker(j); - } - if (j->progressive) - stbi__jpeg_finish(j); - return 1; -} - -// static jfif-centered resampling (across block boundaries) - -typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, - int w, int hs); - -#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) - -static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - STBI_NOTUSED(out); - STBI_NOTUSED(in_far); - STBI_NOTUSED(w); - STBI_NOTUSED(hs); - return in_near; -} - -static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples vertically for every one in input - int i; - STBI_NOTUSED(hs); - for (i=0; i < w; ++i) - out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); - return out; -} - -static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples horizontally for every one in input - int i; - stbi_uc *input = in_near; - - if (w == 1) { - // if only one sample, can't do any interpolation - out[0] = out[1] = input[0]; - return out; - } - - out[0] = input[0]; - out[1] = stbi__div4(input[0]*3 + input[1] + 2); - for (i=1; i < w-1; ++i) { - int n = 3*input[i]+2; - out[i*2+0] = stbi__div4(n+input[i-1]); - out[i*2+1] = stbi__div4(n+input[i+1]); - } - out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); - out[i*2+1] = input[w-1]; - - STBI_NOTUSED(in_far); - STBI_NOTUSED(hs); - - return out; -} - -#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) - -static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i,t0,t1; - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - out[0] = stbi__div4(t1+2); - for (i=1; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); - - STBI_NOTUSED(hs); - - return out; -} - -#if defined(STBI_SSE2) || defined(STBI_NEON) -static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i=0,t0,t1; - - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } - - t1 = 3*in_near[0] + in_far[0]; - // process groups of 8 pixels for as long as we can. - // note we can't handle the last pixel in a row in this loop - // because we need to handle the filter boundary conditions. - for (; i < ((w-1) & ~7); i += 8) { -#if defined(STBI_SSE2) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - __m128i zero = _mm_setzero_si128(); - __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); - __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); - __m128i farw = _mm_unpacklo_epi8(farb, zero); - __m128i nearw = _mm_unpacklo_epi8(nearb, zero); - __m128i diff = _mm_sub_epi16(farw, nearw); - __m128i nears = _mm_slli_epi16(nearw, 2); - __m128i curr = _mm_add_epi16(nears, diff); // current row - - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - __m128i prv0 = _mm_slli_si128(curr, 2); - __m128i nxt0 = _mm_srli_si128(curr, 2); - __m128i prev = _mm_insert_epi16(prv0, t1, 0); - __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); - - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - __m128i bias = _mm_set1_epi16(8); - __m128i curs = _mm_slli_epi16(curr, 2); - __m128i prvd = _mm_sub_epi16(prev, curr); - __m128i nxtd = _mm_sub_epi16(next, curr); - __m128i curb = _mm_add_epi16(curs, bias); - __m128i even = _mm_add_epi16(prvd, curb); - __m128i odd = _mm_add_epi16(nxtd, curb); - - // interleave even and odd pixels, then undo scaling. - __m128i int0 = _mm_unpacklo_epi16(even, odd); - __m128i int1 = _mm_unpackhi_epi16(even, odd); - __m128i de0 = _mm_srli_epi16(int0, 4); - __m128i de1 = _mm_srli_epi16(int1, 4); - - // pack and write output - __m128i outv = _mm_packus_epi16(de0, de1); - _mm_storeu_si128((__m128i *) (out + i*2), outv); -#elif defined(STBI_NEON) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - uint8x8_t farb = vld1_u8(in_far + i); - uint8x8_t nearb = vld1_u8(in_near + i); - int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); - int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); - int16x8_t curr = vaddq_s16(nears, diff); // current row - - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - int16x8_t prv0 = vextq_s16(curr, curr, 7); - int16x8_t nxt0 = vextq_s16(curr, curr, 1); - int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); - int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); - - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - int16x8_t curs = vshlq_n_s16(curr, 2); - int16x8_t prvd = vsubq_s16(prev, curr); - int16x8_t nxtd = vsubq_s16(next, curr); - int16x8_t even = vaddq_s16(curs, prvd); - int16x8_t odd = vaddq_s16(curs, nxtd); - - // undo scaling and round, then store with even/odd phases interleaved - uint8x8x2_t o; - o.val[0] = vqrshrun_n_s16(even, 4); - o.val[1] = vqrshrun_n_s16(odd, 4); - vst2_u8(out + i*2, o); -#endif - - // "previous" value for next iter - t1 = 3*in_near[i+7] + in_far[i+7]; - } - - t0 = t1; - t1 = 3*in_near[i] + in_far[i]; - out[i*2] = stbi__div16(3*t1 + t0 + 8); - - for (++i; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); - - STBI_NOTUSED(hs); - - return out; -} -#endif - -static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // resample with nearest-neighbor - int i,j; - STBI_NOTUSED(in_far); - for (i=0; i < w; ++i) - for (j=0; j < hs; ++j) - out[i*hs+j] = in_near[i]; - return out; -} - -#ifdef STBI_JPEG_OLD -// this is the same YCbCr-to-RGB calculation that stb_image has used -// historically before the algorithm changes in 1.49 -#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 16) + 32768; // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr*float2fixed(1.40200f); - g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); - b = y_fixed + cb*float2fixed(1.77200f); - r >>= 16; - g >>= 16; - b >>= 16; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} -#else -// this is a reduced-precision calculation of YCbCr-to-RGB introduced -// to make sure the code produces the same results in both SIMD and scalar -#define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* float2fixed(1.40200f); - g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} -#endif - -#if defined(STBI_SSE2) || defined(STBI_NEON) -static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) -{ - int i = 0; - -#ifdef STBI_SSE2 - // step == 3 is pretty ugly on the final interleave, and i'm not convinced - // it's useful in practice (you wouldn't use it for textures, for example). - // so just accelerate step == 4 case. - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - __m128i signflip = _mm_set1_epi8(-0x80); - __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); - __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); - __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); - __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); - __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); - __m128i xw = _mm_set1_epi16(255); // alpha channel - - for (; i+7 < count; i += 8) { - // load - __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); - __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); - __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); - __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 - __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 - - // unpack to short (and left-shift cr, cb by 8) - __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); - __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); - __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); - - // color transform - __m128i yws = _mm_srli_epi16(yw, 4); - __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); - __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); - __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); - __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); - __m128i rws = _mm_add_epi16(cr0, yws); - __m128i gwt = _mm_add_epi16(cb0, yws); - __m128i bws = _mm_add_epi16(yws, cb1); - __m128i gws = _mm_add_epi16(gwt, cr1); - - // descale - __m128i rw = _mm_srai_epi16(rws, 4); - __m128i bw = _mm_srai_epi16(bws, 4); - __m128i gw = _mm_srai_epi16(gws, 4); - - // back to byte, set up for transpose - __m128i brb = _mm_packus_epi16(rw, bw); - __m128i gxb = _mm_packus_epi16(gw, xw); - - // transpose to interleave channels - __m128i t0 = _mm_unpacklo_epi8(brb, gxb); - __m128i t1 = _mm_unpackhi_epi8(brb, gxb); - __m128i o0 = _mm_unpacklo_epi16(t0, t1); - __m128i o1 = _mm_unpackhi_epi16(t0, t1); - - // store - _mm_storeu_si128((__m128i *) (out + 0), o0); - _mm_storeu_si128((__m128i *) (out + 16), o1); - out += 32; - } - } -#endif - -#ifdef STBI_NEON - // in this version, step=3 support would be easy to add. but is there demand? - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - uint8x8_t signflip = vdup_n_u8(0x80); - int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); - int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); - int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); - int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); - - for (; i+7 < count; i += 8) { - // load - uint8x8_t y_bytes = vld1_u8(y + i); - uint8x8_t cr_bytes = vld1_u8(pcr + i); - uint8x8_t cb_bytes = vld1_u8(pcb + i); - int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); - int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); - - // expand to s16 - int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); - int16x8_t crw = vshll_n_s8(cr_biased, 7); - int16x8_t cbw = vshll_n_s8(cb_biased, 7); - - // color transform - int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); - int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); - int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); - int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); - int16x8_t rws = vaddq_s16(yws, cr0); - int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); - int16x8_t bws = vaddq_s16(yws, cb1); - - // undo scaling, round, convert to byte - uint8x8x4_t o; - o.val[0] = vqrshrun_n_s16(rws, 4); - o.val[1] = vqrshrun_n_s16(gws, 4); - o.val[2] = vqrshrun_n_s16(bws, 4); - o.val[3] = vdup_n_u8(255); - - // store, interleaving r/g/b/a - vst4_u8(out, o); - out += 8*4; - } - } -#endif - - for (; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* float2fixed(1.40200f); - g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } -} -#endif - -// set up the kernels -static void stbi__setup_jpeg(stbi__jpeg *j) -{ - j->idct_block_kernel = stbi__idct_block; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; - -#ifdef STBI_SSE2 - if (stbi__sse2_available()) { - j->idct_block_kernel = stbi__idct_simd; - #ifndef STBI_JPEG_OLD - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - #endif - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; - } -#endif - -#ifdef STBI_NEON - j->idct_block_kernel = stbi__idct_simd; - #ifndef STBI_JPEG_OLD - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - #endif - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; -#endif -} - -// clean up the temporary component buffers -static void stbi__cleanup_jpeg(stbi__jpeg *j) -{ - int i; - for (i=0; i < j->s->img_n; ++i) { - if (j->img_comp[i].raw_data) { - STBI_FREE(j->img_comp[i].raw_data); - j->img_comp[i].raw_data = NULL; - j->img_comp[i].data = NULL; - } - if (j->img_comp[i].raw_coeff) { - STBI_FREE(j->img_comp[i].raw_coeff); - j->img_comp[i].raw_coeff = 0; - j->img_comp[i].coeff = 0; - } - if (j->img_comp[i].linebuf) { - STBI_FREE(j->img_comp[i].linebuf); - j->img_comp[i].linebuf = NULL; - } - } -} - -typedef struct -{ - resample_row_func resample; - stbi_uc *line0,*line1; - int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion - int ystep; // how far through vertical expansion we are - int ypos; // which pre-expansion row we're on -} stbi__resample; - -static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) -{ - int n, decode_n; - z->s->img_n = 0; // make stbi__cleanup_jpeg safe - - // validate req_comp - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - - // load a jpeg image from whichever source, but leave in YCbCr format - if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } - - // determine actual number of components to generate - n = req_comp ? req_comp : z->s->img_n; - - if (z->s->img_n == 3 && n < 3) - decode_n = 1; - else - decode_n = z->s->img_n; - - // resample and color-convert - { - int k; - unsigned int i,j; - stbi_uc *output; - stbi_uc *coutput[4]; - - stbi__resample res_comp[4]; - - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - - // allocate line buffer big enough for upsampling off the edges - // with upsample factor of 4 - z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); - if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - r->hs = z->img_h_max / z->img_comp[k].h; - r->vs = z->img_v_max / z->img_comp[k].v; - r->ystep = r->vs >> 1; - r->w_lores = (z->s->img_x + r->hs-1) / r->hs; - r->ypos = 0; - r->line0 = r->line1 = z->img_comp[k].data; - - if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; - else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; - else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; - else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; - else r->resample = stbi__resample_row_generic; - } - - // can't error after this so, this is safe - output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1); - if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - // now go ahead and resample - for (j=0; j < z->s->img_y; ++j) { - stbi_uc *out = output + n * z->s->img_x * j; - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - int y_bot = r->ystep >= (r->vs >> 1); - coutput[k] = r->resample(z->img_comp[k].linebuf, - y_bot ? r->line1 : r->line0, - y_bot ? r->line0 : r->line1, - r->w_lores, r->hs); - if (++r->ystep >= r->vs) { - r->ystep = 0; - r->line0 = r->line1; - if (++r->ypos < z->img_comp[k].y) - r->line1 += z->img_comp[k].w2; - } - } - if (n >= 3) { - stbi_uc *y = coutput[0]; - if (z->s->img_n == 3) { - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } else - for (i=0; i < z->s->img_x; ++i) { - out[0] = out[1] = out[2] = y[i]; - out[3] = 255; // not used if n==3 - out += n; - } - } else { - stbi_uc *y = coutput[0]; - if (n == 1) - for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; - else - for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; - } - } - stbi__cleanup_jpeg(z); - *out_x = z->s->img_x; - *out_y = z->s->img_y; - if (comp) *comp = z->s->img_n; // report original components, not output - return output; - } -} - -static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__jpeg j; - j.s = s; - stbi__setup_jpeg(&j); - return load_jpeg_image(&j, x,y,comp,req_comp); -} - -static int stbi__jpeg_test(stbi__context *s) -{ - int r; - stbi__jpeg j; - j.s = s; - stbi__setup_jpeg(&j); - r = stbi__decode_jpeg_header(&j, STBI__SCAN_type); - stbi__rewind(s); - return r; -} - -static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) -{ - if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { - stbi__rewind( j->s ); - return 0; - } - if (x) *x = j->s->img_x; - if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n; - return 1; -} - -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__jpeg j; - j.s = s; - return stbi__jpeg_info_raw(&j, x, y, comp); -} -#endif - -// public domain zlib decode v0.2 Sean Barrett 2006-11-18 -// simple implementation -// - all input must be provided in an upfront buffer -// - all output is written to a single output buffer (can malloc/realloc) -// performance -// - fast huffman - -#ifndef STBI_NO_ZLIB - -// fast-way is faster to check than jpeg huffman, but slow way is slower -#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables -#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) - -// zlib-style huffman encoding -// (jpegs packs from left, zlib from right, so can't share code) -typedef struct -{ - stbi__uint16 fast[1 << STBI__ZFAST_BITS]; - stbi__uint16 firstcode[16]; - int maxcode[17]; - stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; -} stbi__zhuffman; - -stbi_inline static int stbi__bitreverse16(int n) -{ - n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); - n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); - n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); - n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); - return n; -} - -stbi_inline static int stbi__bit_reverse(int v, int bits) -{ - STBI_ASSERT(bits <= 16); - // to bit reverse n bits, reverse 16 and shift - // e.g. 11 bits, bit reverse and shift away 5 - return stbi__bitreverse16(v) >> (16-bits); -} - -static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) -{ - int i,k=0; - int code, next_code[16], sizes[17]; - - // DEFLATE spec for generating codes - memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 0, sizeof(z->fast)); - for (i=0; i < num; ++i) - ++sizes[sizelist[i]]; - sizes[0] = 0; - for (i=1; i < 16; ++i) - STBI_ASSERT(sizes[i] <= (1 << i)); - code = 0; - for (i=1; i < 16; ++i) { - next_code[i] = code; - z->firstcode[i] = (stbi__uint16) code; - z->firstsymbol[i] = (stbi__uint16) k; - code = (code + sizes[i]); - if (sizes[i]) - if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt JPEG"); - z->maxcode[i] = code << (16-i); // preshift for inner loop - code <<= 1; - k += sizes[i]; - } - z->maxcode[16] = 0x10000; // sentinel - for (i=0; i < num; ++i) { - int s = sizelist[i]; - if (s) { - int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); - z->size [c] = (stbi_uc ) s; - z->value[c] = (stbi__uint16) i; - if (s <= STBI__ZFAST_BITS) { - int k = stbi__bit_reverse(next_code[s],s); - while (k < (1 << STBI__ZFAST_BITS)) { - z->fast[k] = fastv; - k += (1 << s); - } - } - ++next_code[s]; - } - } - return 1; -} - -// zlib-from-memory implementation for PNG reading -// because PNG allows splitting the zlib stream arbitrarily, -// and it's annoying structurally to have PNG call ZLIB call PNG, -// we require PNG read all the IDATs and combine them into a single -// memory buffer - -typedef struct -{ - stbi_uc *zbuffer, *zbuffer_end; - int num_bits; - stbi__uint32 code_buffer; - - char *zout; - char *zout_start; - char *zout_end; - int z_expandable; - - stbi__zhuffman z_length, z_distance; -} stbi__zbuf; - -stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) -{ - if (z->zbuffer >= z->zbuffer_end) return 0; - return *z->zbuffer++; -} - -static void stbi__fill_bits(stbi__zbuf *z) -{ - do { - STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); - z->code_buffer |= stbi__zget8(z) << z->num_bits; - z->num_bits += 8; - } while (z->num_bits <= 24); -} - -stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) -{ - unsigned int k; - if (z->num_bits < n) stbi__fill_bits(z); - k = z->code_buffer & ((1 << n) - 1); - z->code_buffer >>= n; - z->num_bits -= n; - return k; -} - -static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s,k; - // not resolved by fast table, so compute it the slow way - // use jpeg approach, which requires MSbits at top - k = stbi__bit_reverse(a->code_buffer, 16); - for (s=STBI__ZFAST_BITS+1; ; ++s) - if (k < z->maxcode[s]) - break; - if (s == 16) return -1; // invalid code! - // code size is s, so: - b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - STBI_ASSERT(z->size[b] == s); - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; -} - -stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s; - if (a->num_bits < 16) stbi__fill_bits(a); - b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; - if (b) { - s = b >> 9; - a->code_buffer >>= s; - a->num_bits -= s; - return b & 511; - } - return stbi__zhuffman_decode_slowpath(a, z); -} - -static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes -{ - char *q; - int cur, limit; - z->zout = zout; - if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (int) (z->zout - z->zout_start); - limit = (int) (z->zout_end - z->zout_start); - while (cur + n > limit) - limit *= 2; - q = (char *) STBI_REALLOC(z->zout_start, limit); - if (q == NULL) return stbi__err("outofmem", "Out of memory"); - z->zout_start = q; - z->zout = q + cur; - z->zout_end = q + limit; - return 1; -} - -static int stbi__zlength_base[31] = { - 3,4,5,6,7,8,9,10,11,13, - 15,17,19,23,27,31,35,43,51,59, - 67,83,99,115,131,163,195,227,258,0,0 }; - -static int stbi__zlength_extra[31]= -{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - -static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, -257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - -static int stbi__zdist_extra[32] = -{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -static int stbi__parse_huffman_block(stbi__zbuf *a) -{ - char *zout = a->zout; - for(;;) { - int z = stbi__zhuffman_decode(a, &a->z_length); - if (z < 256) { - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes - if (zout >= a->zout_end) { - if (!stbi__zexpand(a, zout, 1)) return 0; - zout = a->zout; - } - *zout++ = (char) z; - } else { - stbi_uc *p; - int len,dist; - if (z == 256) { - a->zout = zout; - return 1; - } - z -= 257; - len = stbi__zlength_base[z]; - if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); - z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); - dist = stbi__zdist_base[z]; - if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (zout + len > a->zout_end) { - if (!stbi__zexpand(a, zout, len)) return 0; - zout = a->zout; - } - p = (stbi_uc *) (zout - dist); - if (dist == 1) { // run of one byte; common in images. - stbi_uc v = *p; - do *zout++ = v; while (--len); - } else { - do *zout++ = *p++; while (--len); - } - } - } -} - -static int stbi__compute_huffman_codes(stbi__zbuf *a) -{ - static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - stbi__zhuffman z_codelength; - stbi_uc lencodes[286+32+137];//padding for maximum single op - stbi_uc codelength_sizes[19]; - int i,n; - - int hlit = stbi__zreceive(a,5) + 257; - int hdist = stbi__zreceive(a,5) + 1; - int hclen = stbi__zreceive(a,4) + 4; - - memset(codelength_sizes, 0, sizeof(codelength_sizes)); - for (i=0; i < hclen; ++i) { - int s = stbi__zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; - } - if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; - - n = 0; - while (n < hlit + hdist) { - int c = stbi__zhuffman_decode(a, &z_codelength); - STBI_ASSERT(c >= 0 && c < 19); - if (c < 16) - lencodes[n++] = (stbi_uc) c; - else if (c == 16) { - c = stbi__zreceive(a,2)+3; - memset(lencodes+n, lencodes[n-1], c); - n += c; - } else if (c == 17) { - c = stbi__zreceive(a,3)+3; - memset(lencodes+n, 0, c); - n += c; - } else { - STBI_ASSERT(c == 18); - c = stbi__zreceive(a,7)+11; - memset(lencodes+n, 0, c); - n += c; - } - } - if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG"); - if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; - return 1; -} - -static int stbi__parse_uncomperssed_block(stbi__zbuf *a) -{ - stbi_uc header[4]; - int len,nlen,k; - if (a->num_bits & 7) - stbi__zreceive(a, a->num_bits & 7); // discard - // drain the bit-packed data into header - k = 0; - while (a->num_bits > 0) { - header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check - a->code_buffer >>= 8; - a->num_bits -= 8; - } - STBI_ASSERT(a->num_bits == 0); - // now fill header the normal way - while (k < 4) - header[k++] = stbi__zget8(a); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); - if (a->zout + len > a->zout_end) - if (!stbi__zexpand(a, a->zout, len)) return 0; - memcpy(a->zout, a->zbuffer, len); - a->zbuffer += len; - a->zout += len; - return 1; -} - -static int stbi__parse_zlib_header(stbi__zbuf *a) -{ - int cmf = stbi__zget8(a); - int cm = cmf & 15; - /* int cinfo = cmf >> 4; */ - int flg = stbi__zget8(a); - if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec - if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png - if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png - // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; -} - -// @TODO: should statically initialize these for optimal thread safety -static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; -static void stbi__init_zdefaults(void) -{ - int i; // use <= to match clearly with spec - for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; - for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; - for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; - for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; - - for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; -} - -static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) -{ - int final, type; - if (parse_header) - if (!stbi__parse_zlib_header(a)) return 0; - a->num_bits = 0; - a->code_buffer = 0; - do { - final = stbi__zreceive(a,1); - type = stbi__zreceive(a,2); - if (type == 0) { - if (!stbi__parse_uncomperssed_block(a)) return 0; - } else if (type == 3) { - return 0; - } else { - if (type == 1) { - // use fixed code lengths - if (!stbi__zdefault_distance[31]) stbi__init_zdefaults(); - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; - } else { - if (!stbi__compute_huffman_codes(a)) return 0; - } - if (!stbi__parse_huffman_block(a)) return 0; - } - } while (!final); - return 1; -} - -static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) -{ - a->zout_start = obuf; - a->zout = obuf; - a->zout_end = obuf + olen; - a->z_expandable = exp; - - return stbi__parse_zlib(a, parse_header); -} - -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) -{ - return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); -} - -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) - return (int) (a.zout - a.zout_start); - else - return -1; -} - -STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(16384); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer+len; - if (stbi__do_zlib(&a, p, 16384, 1, 0)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } -} - -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) - return (int) (a.zout - a.zout_start); - else - return -1; -} -#endif - -// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 -// simple implementation -// - only 8-bit samples -// - no CRC checking -// - allocates lots of intermediate memory -// - avoids problem of streaming data between subsystems -// - avoids explicit window management -// performance -// - uses stb_zlib, a PD zlib implementation with fast huffman decoding - -#ifndef STBI_NO_PNG -typedef struct -{ - stbi__uint32 length; - stbi__uint32 type; -} stbi__pngchunk; - -static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) -{ - stbi__pngchunk c; - c.length = stbi__get32be(s); - c.type = stbi__get32be(s); - return c; -} - -static int stbi__check_png_header(stbi__context *s) -{ - static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; - int i; - for (i=0; i < 8; ++i) - if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); - return 1; -} - -typedef struct -{ - stbi__context *s; - stbi_uc *idata, *expanded, *out; -} stbi__png; - - -enum { - STBI__F_none=0, - STBI__F_sub=1, - STBI__F_up=2, - STBI__F_avg=3, - STBI__F_paeth=4, - // synthetic filters used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first, - STBI__F_paeth_first -}; - -static stbi_uc first_row_filter[5] = -{ - STBI__F_none, - STBI__F_sub, - STBI__F_none, - STBI__F_avg_first, - STBI__F_paeth_first -}; - -static int stbi__paeth(int a, int b, int c) -{ - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; -} - -static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; - -// create the png data from post-deflated data -static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) -{ - stbi__context *s = a->s; - stbi__uint32 i,j,stride = x*out_n; - stbi__uint32 img_len, img_width_bytes; - int k; - int img_n = s->img_n; // copy it into a local for later - - STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc(x * y * out_n); // extra bytes to write off the end into - if (!a->out) return stbi__err("outofmem", "Out of memory"); - - img_width_bytes = (((img_n * x * depth) + 7) >> 3); - img_len = (img_width_bytes + 1) * y; - if (s->img_x == x && s->img_y == y) { - if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); - } else { // interlaced: - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); - } - - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior = cur - stride; - int filter = *raw++; - int filter_bytes = img_n; - int width = x; - if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); - - if (depth < 8) { - STBI_ASSERT(img_width_bytes <= x); - cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place - filter_bytes = 1; - width = img_width_bytes; - } - - // if first row, use special filter that doesn't sample previous row - if (j == 0) filter = first_row_filter[filter]; - - // handle first byte explicitly - for (k=0; k < filter_bytes; ++k) { - switch (filter) { - case STBI__F_none : cur[k] = raw[k]; break; - case STBI__F_sub : cur[k] = raw[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = raw[k]; break; - case STBI__F_paeth_first: cur[k] = raw[k]; break; - } - } - - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; // first pixel - raw += img_n; - cur += out_n; - prior += out_n; - } else { - raw += 1; - cur += 1; - prior += 1; - } - - // this is a little gross, so that we don't switch per-pixel or per-component - if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*img_n; - #define CASE(f) \ - case f: \ - for (k=0; k < nk; ++k) - switch (filter) { - // "none" filter turns into a memcpy here; make that explicit. - case STBI__F_none: memcpy(cur, raw, nk); break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break; - CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break; - } - #undef CASE - raw += nk; - } else { - STBI_ASSERT(img_n+1 == out_n); - #define CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ - for (k=0; k < img_n; ++k) - switch (filter) { - CASE(STBI__F_none) cur[k] = raw[k]; break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); break; - CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-out_n])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break; - } - #undef CASE - } - } - - // we make a separate pass to expand bits to pixels; for performance, - // this could run two scanlines behind the above code, so it won't - // intefere with filtering but will still be in the cache. - if (depth < 8) { - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit - // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop - stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range - - // note that the final byte might overshoot and write more data than desired. - // we can allocate enough data that this never writes out of memory, but it - // could also overwrite the next scanline. can it overwrite non-empty data - // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. - // so we need to explicitly clamp the final ones - - if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); - } - if (k > 0) *cur++ = scale * ((*in >> 4) ); - } else if (depth == 2) { - for (k=x*img_n; k >= 4; k-=4, ++in) { - *cur++ = scale * ((*in >> 6) ); - *cur++ = scale * ((*in >> 4) & 0x03); - *cur++ = scale * ((*in >> 2) & 0x03); - *cur++ = scale * ((*in ) & 0x03); - } - if (k > 0) *cur++ = scale * ((*in >> 6) ); - if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); - if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); - } else if (depth == 1) { - for (k=x*img_n; k >= 8; k-=8, ++in) { - *cur++ = scale * ((*in >> 7) ); - *cur++ = scale * ((*in >> 6) & 0x01); - *cur++ = scale * ((*in >> 5) & 0x01); - *cur++ = scale * ((*in >> 4) & 0x01); - *cur++ = scale * ((*in >> 3) & 0x01); - *cur++ = scale * ((*in >> 2) & 0x01); - *cur++ = scale * ((*in >> 1) & 0x01); - *cur++ = scale * ((*in ) & 0x01); - } - if (k > 0) *cur++ = scale * ((*in >> 7) ); - if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); - if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); - if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); - if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); - if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); - if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); - } - if (img_n != out_n) { - // insert alpha = 255 - stbi_uc *cur = a->out + stride*j; - int i; - if (img_n == 1) { - for (i=x-1; i >= 0; --i) { - cur[i*2+1] = 255; - cur[i*2+0] = cur[i]; - } - } else { - STBI_ASSERT(img_n == 3); - for (i=x-1; i >= 0; --i) { - cur[i*4+3] = 255; - cur[i*4+2] = cur[i*3+2]; - cur[i*4+1] = cur[i*3+1]; - cur[i*4+0] = cur[i*3+0]; - } - } - } - } - } - - return 1; -} - -static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) -{ - stbi_uc *final; - int p; - if (!interlaced) - return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); - - // de-interlacing - final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); - for (p=0; p < 7; ++p) { - int xorig[] = { 0,4,0,2,0,1,0 }; - int yorig[] = { 0,0,4,0,2,0,1 }; - int xspc[] = { 8,8,4,4,2,2,1 }; - int yspc[] = { 8,8,8,4,4,2,2 }; - int i,j,x,y; - // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 - x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; - y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; - if (x && y) { - stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; - if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { - STBI_FREE(final); - return 0; - } - for (j=0; j < y; ++j) { - for (i=0; i < x; ++i) { - int out_y = j*yspc[p]+yorig[p]; - int out_x = i*xspc[p]+xorig[p]; - memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n, - a->out + (j*x+i)*out_n, out_n); - } - } - STBI_FREE(a->out); - image_data += img_len; - image_data_len -= img_len; - } - } - a->out = final; - - return 1; -} - -static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - // compute color-based transparency, assuming we've - // already got 255 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i=0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 255); - p += 2; - } - } else { - for (i=0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - -static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) -{ - stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - stbi_uc *p, *temp_out, *orig = a->out; - - p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); - - // between here and free(out) below, exitting would leak - temp_out = p; - - if (pal_img_n == 3) { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p += 3; - } - } else { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p[3] = palette[n+3]; - p += 4; - } - } - STBI_FREE(a->out); - a->out = temp_out; - - STBI_NOTUSED(len); - - return 1; -} - -static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; - -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; -} - -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag = flag_true_if_should_convert; -} - -static void stbi__de_iphone(stbi__png *z) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - if (s->img_out_n == 3) { // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 3; - } - } else { - STBI_ASSERT(s->img_out_n == 4); - if (stbi__unpremultiply_on_load) { - // convert bgr to rgb and unpremultiply - for (i=0; i < pixel_count; ++i) { - stbi_uc a = p[3]; - stbi_uc t = p[0]; - if (a) { - p[0] = p[2] * 255 / a; - p[1] = p[1] * 255 / a; - p[2] = t * 255 / a; - } else { - p[0] = p[2]; - p[2] = t; - } - p += 4; - } - } else { - // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 4; - } - } - } -} - -#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - -static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) -{ - stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]; - stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0, depth=0, is_iphone=0; - stbi__context *s = z->s; - - z->expanded = NULL; - z->idata = NULL; - z->out = NULL; - - if (!stbi__check_png_header(s)) return 0; - - if (scan == STBI__SCAN_type) return 1; - - for (;;) { - stbi__pngchunk c = stbi__get_chunk_header(s); - switch (c.type) { - case STBI__PNG_TYPE('C','g','B','I'): - is_iphone = 1; - stbi__skip(s, c.length); - break; - case STBI__PNG_TYPE('I','H','D','R'): { - int comp,filter; - if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); - first = 0; - if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - depth = stbi__get8(s); if (depth != 1 && depth != 2 && depth != 4 && depth != 8) return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only"); - color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); - comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); - filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); - interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); - if (!pal_img_n) { - s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; - } else { - // if paletted, then pal_n is our final components, and - // img_n is # components to decompress/filter. - s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS - } - break; - } - - case STBI__PNG_TYPE('P','L','T','E'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); - pal_len = c.length / 3; - if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); - for (i=0; i < pal_len; ++i) { - palette[i*4+0] = stbi__get8(s); - palette[i*4+1] = stbi__get8(s); - palette[i*4+2] = stbi__get8(s); - palette[i*4+3] = 255; - } - break; - } - - case STBI__PNG_TYPE('t','R','N','S'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); - if (pal_img_n) { - if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); - pal_img_n = 4; - for (i=0; i < c.length; ++i) - palette[i*4+3] = stbi__get8(s); - } else { - if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); - if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); - has_trans = 1; - for (k=0; k < s->img_n; ++k) - tc[k] = (stbi_uc) (stbi__get16be(s) & 255) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger - } - break; - } - - case STBI__PNG_TYPE('I','D','A','T'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } - if (ioff + c.length > idata_limit) { - stbi_uc *p; - if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; - while (ioff + c.length > idata_limit) - idata_limit *= 2; - p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); - z->idata = p; - } - if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); - ioff += c.length; - break; - } - - case STBI__PNG_TYPE('I','E','N','D'): { - stbi__uint32 raw_len, bpl; - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (scan != STBI__SCAN_load) return 1; - if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); - // initial guess for decoded data size to avoid unnecessary reallocs - bpl = (s->img_x * depth + 7) / 8; // bytes per line, per component - raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; - z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); - if (z->expanded == NULL) return 0; // zlib should set error - STBI_FREE(z->idata); z->idata = NULL; - if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) - s->img_out_n = s->img_n+1; - else - s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace)) return 0; - if (has_trans) - if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; - if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) - stbi__de_iphone(z); - if (pal_img_n) { - // pal_img_n == 3 or 4 - s->img_n = pal_img_n; // record the actual colors we had - s->img_out_n = pal_img_n; - if (req_comp >= 3) s->img_out_n = req_comp; - if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) - return 0; - } - STBI_FREE(z->expanded); z->expanded = NULL; - return 1; - } - - default: - // if critical, fail - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if ((c.type & (1 << 29)) == 0) { - #ifndef STBI_NO_FAILURE_STRINGS - // not threadsafe - static char invalid_chunk[] = "XXXX PNG chunk not known"; - invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); - invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); - invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); - invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); - #endif - return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); - } - stbi__skip(s, c.length); - break; - } - // end of PNG chunk, read and skip CRC - stbi__get32be(s); - } -} - -static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp) -{ - unsigned char *result=NULL; - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - result = p->out; - p->out = NULL; - if (req_comp && req_comp != p->s->img_out_n) { - result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - p->s->img_out_n = req_comp; - if (result == NULL) return result; - } - *x = p->s->img_x; - *y = p->s->img_y; - if (n) *n = p->s->img_out_n; - } - STBI_FREE(p->out); p->out = NULL; - STBI_FREE(p->expanded); p->expanded = NULL; - STBI_FREE(p->idata); p->idata = NULL; - - return result; -} - -static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__png p; - p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp); -} - -static int stbi__png_test(stbi__context *s) -{ - int r; - r = stbi__check_png_header(s); - stbi__rewind(s); - return r; -} - -static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) -{ - if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { - stbi__rewind( p->s ); - return 0; - } - if (x) *x = p->s->img_x; - if (y) *y = p->s->img_y; - if (comp) *comp = p->s->img_n; - return 1; -} - -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__png p; - p.s = s; - return stbi__png_info_raw(&p, x, y, comp); -} -#endif - -// Microsoft/Windows BMP image - -#ifndef STBI_NO_BMP -static int stbi__bmp_test_raw(stbi__context *s) -{ - int r; - int sz; - if (stbi__get8(s) != 'B') return 0; - if (stbi__get8(s) != 'M') return 0; - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - stbi__get32le(s); // discard data offset - sz = stbi__get32le(s); - r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); - return r; -} - -static int stbi__bmp_test(stbi__context *s) -{ - int r = stbi__bmp_test_raw(s); - stbi__rewind(s); - return r; -} - - -// returns 0..31 for the highest set bit -static int stbi__high_bit(unsigned int z) -{ - int n=0; - if (z == 0) return -1; - if (z >= 0x10000) n += 16, z >>= 16; - if (z >= 0x00100) n += 8, z >>= 8; - if (z >= 0x00010) n += 4, z >>= 4; - if (z >= 0x00004) n += 2, z >>= 2; - if (z >= 0x00002) n += 1, z >>= 1; - return n; -} - -static int stbi__bitcount(unsigned int a) -{ - a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 - a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits - a = (a + (a >> 8)); // max 16 per 8 bits - a = (a + (a >> 16)); // max 32 per 8 bits - return a & 0xff; -} - -static int stbi__shiftsigned(int v, int shift, int bits) -{ - int result; - int z=0; - - if (shift < 0) v <<= -shift; - else v >>= shift; - result = v; - - z = bits; - while (z < 8) { - result += v >> z; - z += bits; - } - return result; -} - -static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *out; - unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0; - stbi_uc pal[256][4]; - int psize=0,i,j,compress=0,width; - int bpp, flip_vertically, pad, target, offset, hsz; - if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - offset = stbi__get32le(s); - hsz = stbi__get32le(s); - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); - if (hsz == 12) { - s->img_x = stbi__get16le(s); - s->img_y = stbi__get16le(s); - } else { - s->img_x = stbi__get32le(s); - s->img_y = stbi__get32le(s); - } - if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); - bpp = stbi__get16le(s); - if (bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); - flip_vertically = ((int) s->img_y) > 0; - s->img_y = abs((int) s->img_y); - if (hsz == 12) { - if (bpp < 24) - psize = (offset - 14 - 24) / 3; - } else { - compress = stbi__get32le(s); - if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); - stbi__get32le(s); // discard sizeof - stbi__get32le(s); // discard hres - stbi__get32le(s); // discard vres - stbi__get32le(s); // discard colorsused - stbi__get32le(s); // discard max important - if (hsz == 40 || hsz == 56) { - if (hsz == 56) { - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - } - if (bpp == 16 || bpp == 32) { - mr = mg = mb = 0; - if (compress == 0) { - if (bpp == 32) { - mr = 0xffu << 16; - mg = 0xffu << 8; - mb = 0xffu << 0; - ma = 0xffu << 24; - fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255 - STBI_NOTUSED(fake_a); - } else { - mr = 31u << 10; - mg = 31u << 5; - mb = 31u << 0; - } - } else if (compress == 3) { - mr = stbi__get32le(s); - mg = stbi__get32le(s); - mb = stbi__get32le(s); - // not documented, but generated by photoshop and handled by mspaint - if (mr == mg && mg == mb) { - // ?!?!? - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else { - STBI_ASSERT(hsz == 108 || hsz == 124); - mr = stbi__get32le(s); - mg = stbi__get32le(s); - mb = stbi__get32le(s); - ma = stbi__get32le(s); - stbi__get32le(s); // discard color space - for (i=0; i < 12; ++i) - stbi__get32le(s); // discard color space parameters - if (hsz == 124) { - stbi__get32le(s); // discard rendering intent - stbi__get32le(s); // discard offset of profile data - stbi__get32le(s); // discard size of profile data - stbi__get32le(s); // discard reserved - } - } - if (bpp < 16) - psize = (offset - 14 - hsz) >> 2; - } - s->img_n = ma ? 4 : 3; - if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 - target = req_comp; - else - target = s->img_n; // if they want monochrome, we'll post-convert - out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - if (bpp < 16) { - int z=0; - if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } - for (i=0; i < psize; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - if (hsz != 12) stbi__get8(s); - pal[i][3] = 255; - } - stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); - if (bpp == 4) width = (s->img_x + 1) >> 1; - else if (bpp == 8) width = s->img_x; - else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } - pad = (-width)&3; - for (j=0; j < (int) s->img_y; ++j) { - for (i=0; i < (int) s->img_x; i += 2) { - int v=stbi__get8(s),v2=0; - if (bpp == 4) { - v2 = v & 15; - v >>= 4; - } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - v = (bpp == 8) ? stbi__get8(s) : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - } - stbi__skip(s, pad); - } - } else { - int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; - int z = 0; - int easy=0; - stbi__skip(s, offset - 14 - hsz); - if (bpp == 24) width = 3 * s->img_x; - else if (bpp == 16) width = 2*s->img_x; - else /* bpp = 32 and pad = 0 */ width=0; - pad = (-width) & 3; - if (bpp == 24) { - easy = 1; - } else if (bpp == 32) { - if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) - easy = 2; - } - if (!easy) { - if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } - // right shift amt to put high bit in position #7 - rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); - gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); - bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); - ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); - } - for (j=0; j < (int) s->img_y; ++j) { - if (easy) { - for (i=0; i < (int) s->img_x; ++i) { - unsigned char a; - out[z+2] = stbi__get8(s); - out[z+1] = stbi__get8(s); - out[z+0] = stbi__get8(s); - z += 3; - a = (easy == 2 ? stbi__get8(s) : 255); - if (target == 4) out[z++] = a; - } - } else { - for (i=0; i < (int) s->img_x; ++i) { - stbi__uint32 v = (stbi__uint32) (bpp == 16 ? stbi__get16le(s) : stbi__get32le(s)); - int a; - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); - a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); - if (target == 4) out[z++] = STBI__BYTECAST(a); - } - } - stbi__skip(s, pad); - } - } - if (flip_vertically) { - stbi_uc t; - for (j=0; j < (int) s->img_y>>1; ++j) { - stbi_uc *p1 = out + j *s->img_x*target; - stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; - for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i], p1[i] = p2[i], p2[i] = t; - } - } - } - - if (req_comp && req_comp != target) { - out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; - return out; -} -#endif - -// Targa Truevision - TGA -// by Jonathan Dummer -#ifndef STBI_NO_TGA -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) -{ - int tga_w, tga_h, tga_comp; - int sz; - stbi__get8(s); // discard Offset - sz = stbi__get8(s); // color type - if( sz > 1 ) { - stbi__rewind(s); - return 0; // only RGB or indexed allowed - } - sz = stbi__get8(s); // image type - // only RGB or grey allowed, +/- RLE - if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; - stbi__skip(s,9); - tga_w = stbi__get16le(s); - if( tga_w < 1 ) { - stbi__rewind(s); - return 0; // test width - } - tga_h = stbi__get16le(s); - if( tga_h < 1 ) { - stbi__rewind(s); - return 0; // test height - } - sz = stbi__get8(s); // bits per pixel - // only RGB or RGBA or grey allowed - if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { - stbi__rewind(s); - return 0; - } - tga_comp = sz; - if (x) *x = tga_w; - if (y) *y = tga_h; - if (comp) *comp = tga_comp / 8; - return 1; // seems to have passed everything -} - -static int stbi__tga_test(stbi__context *s) -{ - int res; - int sz; - stbi__get8(s); // discard Offset - sz = stbi__get8(s); // color type - if ( sz > 1 ) return 0; // only RGB or indexed allowed - sz = stbi__get8(s); // image type - if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE - stbi__get16be(s); // discard palette start - stbi__get16be(s); // discard palette length - stbi__get8(s); // discard bits per palette color entry - stbi__get16be(s); // discard x origin - stbi__get16be(s); // discard y origin - if ( stbi__get16be(s) < 1 ) return 0; // test width - if ( stbi__get16be(s) < 1 ) return 0; // test height - sz = stbi__get8(s); // bits per pixel - if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) - res = 0; - else - res = 1; - stbi__rewind(s); - return res; -} - -static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - // read in the TGA header stuff - int tga_offset = stbi__get8(s); - int tga_indexed = stbi__get8(s); - int tga_image_type = stbi__get8(s); - int tga_is_RLE = 0; - int tga_palette_start = stbi__get16le(s); - int tga_palette_len = stbi__get16le(s); - int tga_palette_bits = stbi__get8(s); - int tga_x_origin = stbi__get16le(s); - int tga_y_origin = stbi__get16le(s); - int tga_width = stbi__get16le(s); - int tga_height = stbi__get16le(s); - int tga_bits_per_pixel = stbi__get8(s); - int tga_comp = tga_bits_per_pixel / 8; - int tga_inverted = stbi__get8(s); - // image data - unsigned char *tga_data; - unsigned char *tga_palette = NULL; - int i, j; - unsigned char raw_data[4]; - int RLE_count = 0; - int RLE_repeating = 0; - int read_next_pixel = 1; - - // do a tiny bit of precessing - if ( tga_image_type >= 8 ) - { - tga_image_type -= 8; - tga_is_RLE = 1; - } - /* int tga_alpha_bits = tga_inverted & 15; */ - tga_inverted = 1 - ((tga_inverted >> 5) & 1); - - // error check - if ( //(tga_indexed) || - (tga_width < 1) || (tga_height < 1) || - (tga_image_type < 1) || (tga_image_type > 3) || - ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && - (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) - ) - { - return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA - } - - // If I'm paletted, then I'll use the number of bits from the palette - if ( tga_indexed ) - { - tga_comp = tga_palette_bits / 8; - } - - // tga info - *x = tga_width; - *y = tga_height; - if (comp) *comp = tga_comp; - - tga_data = (unsigned char*)stbi__malloc( tga_width * tga_height * tga_comp ); - if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); - - // skip to the data's starting position (offset usually = 0) - stbi__skip(s, tga_offset ); - - if ( !tga_indexed && !tga_is_RLE) { - for (i=0; i < tga_height; ++i) { - int y = tga_inverted ? tga_height -i - 1 : i; - stbi_uc *tga_row = tga_data + y*tga_width*tga_comp; - stbi__getn(s, tga_row, tga_width * tga_comp); - } - } else { - // do I need to load a palette? - if ( tga_indexed) - { - // any data to skip? (offset usually = 0) - stbi__skip(s, tga_palette_start ); - // load the palette - tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 ); - if (!tga_palette) { - STBI_FREE(tga_data); - return stbi__errpuc("outofmem", "Out of memory"); - } - if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { - STBI_FREE(tga_data); - STBI_FREE(tga_palette); - return stbi__errpuc("bad palette", "Corrupt TGA"); - } - } - // load the data - for (i=0; i < tga_width * tga_height; ++i) - { - // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? - if ( tga_is_RLE ) - { - if ( RLE_count == 0 ) - { - // yep, get the next byte as a RLE command - int RLE_cmd = stbi__get8(s); - RLE_count = 1 + (RLE_cmd & 127); - RLE_repeating = RLE_cmd >> 7; - read_next_pixel = 1; - } else if ( !RLE_repeating ) - { - read_next_pixel = 1; - } - } else - { - read_next_pixel = 1; - } - // OK, if I need to read a pixel, do it now - if ( read_next_pixel ) - { - // load however much data we did have - if ( tga_indexed ) - { - // read in 1 byte, then perform the lookup - int pal_idx = stbi__get8(s); - if ( pal_idx >= tga_palette_len ) - { - // invalid index - pal_idx = 0; - } - pal_idx *= tga_bits_per_pixel / 8; - for (j = 0; j*8 < tga_bits_per_pixel; ++j) - { - raw_data[j] = tga_palette[pal_idx+j]; - } - } else - { - // read in the data raw - for (j = 0; j*8 < tga_bits_per_pixel; ++j) - { - raw_data[j] = stbi__get8(s); - } - } - // clear the reading flag for the next pixel - read_next_pixel = 0; - } // end of reading a pixel - - // copy data - for (j = 0; j < tga_comp; ++j) - tga_data[i*tga_comp+j] = raw_data[j]; - - // in case we're in RLE mode, keep counting down - --RLE_count; - } - // do I need to invert the image? - if ( tga_inverted ) - { - for (j = 0; j*2 < tga_height; ++j) - { - int index1 = j * tga_width * tga_comp; - int index2 = (tga_height - 1 - j) * tga_width * tga_comp; - for (i = tga_width * tga_comp; i > 0; --i) - { - unsigned char temp = tga_data[index1]; - tga_data[index1] = tga_data[index2]; - tga_data[index2] = temp; - ++index1; - ++index2; - } - } - } - // clear my palette, if I had one - if ( tga_palette != NULL ) - { - STBI_FREE( tga_palette ); - } - } - - // swap RGB - if (tga_comp >= 3) - { - unsigned char* tga_pixel = tga_data; - for (i=0; i < tga_width * tga_height; ++i) - { - unsigned char temp = tga_pixel[0]; - tga_pixel[0] = tga_pixel[2]; - tga_pixel[2] = temp; - tga_pixel += tga_comp; - } - } - - // convert to target component count - if (req_comp && req_comp != tga_comp) - tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); - - // the things I do to get rid of an error message, and yet keep - // Microsoft's C compilers happy... [8^( - tga_palette_start = tga_palette_len = tga_palette_bits = - tga_x_origin = tga_y_origin = 0; - // OK, done - return tga_data; -} -#endif - -// ************************************************************************************************* -// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB - -#ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s) -{ - int r = (stbi__get32be(s) == 0x38425053); - stbi__rewind(s); - return r; -} - -static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - int pixelCount; - int channelCount, compression; - int channel, i, count, len; - int w,h; - stbi_uc *out; - - // Check identifier - if (stbi__get32be(s) != 0x38425053) // "8BPS" - return stbi__errpuc("not PSD", "Corrupt PSD image"); - - // Check file type version. - if (stbi__get16be(s) != 1) - return stbi__errpuc("wrong version", "Unsupported version of PSD image"); - - // Skip 6 reserved bytes. - stbi__skip(s, 6 ); - - // Read the number of channels (R, G, B, A, etc). - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) - return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); - - // Read the rows and columns of the image. - h = stbi__get32be(s); - w = stbi__get32be(s); - - // Make sure the depth is 8 bits. - if (stbi__get16be(s) != 8) - return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 bit"); - - // Make sure the color mode is RGB. - // Valid options are: - // 0: Bitmap - // 1: Grayscale - // 2: Indexed color - // 3: RGB color - // 4: CMYK color - // 7: Multichannel - // 8: Duotone - // 9: Lab color - if (stbi__get16be(s) != 3) - return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); - - // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) - stbi__skip(s,stbi__get32be(s) ); - - // Skip the image resources. (resolution, pen tool paths, etc) - stbi__skip(s, stbi__get32be(s) ); - - // Skip the reserved data. - stbi__skip(s, stbi__get32be(s) ); - - // Find out if the data is compressed. - // Known values: - // 0: no compression - // 1: RLE compressed - compression = stbi__get16be(s); - if (compression > 1) - return stbi__errpuc("bad compression", "PSD has an unknown compression format"); - - // Create the destination image. - out = (stbi_uc *) stbi__malloc(4 * w*h); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - pixelCount = w*h; - - // Initialize the data to zero. - //memset( out, 0, pixelCount * 4 ); - - // Finally, the image data. - if (compression) { - // RLE as used by .PSD and .TIFF - // Loop until you get the number of unpacked bytes you are expecting: - // Read the next source byte into n. - // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. - // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. - // Else if n is 128, noop. - // Endloop - - // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, - // which we're going to just skip. - stbi__skip(s, h * channelCount * 2 ); - - // Read the RLE data by channel. - for (channel = 0; channel < 4; channel++) { - stbi_uc *p; - - p = out+channel; - if (channel >= channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4; - } else { - // Read the RLE data. - count = 0; - while (count < pixelCount) { - len = stbi__get8(s); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - count += len; - while (len) { - *p = stbi__get8(s); - p += 4; - len--; - } - } else if (len > 128) { - stbi_uc val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len ^= 0x0FF; - len += 2; - val = stbi__get8(s); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } - } - } - } - } - - } else { - // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit value for each pixel in the image. - - // Read the data by channel. - for (channel = 0; channel < 4; channel++) { - stbi_uc *p; - - p = out + channel; - if (channel > channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4; - } else { - // Read the data. - for (i = 0; i < pixelCount; i++) - *p = stbi__get8(s), p += 4; - } - } - } - - if (req_comp && req_comp != 4) { - out = stbi__convert_format(out, 4, req_comp, w, h); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - - if (comp) *comp = channelCount; - *y = h; - *x = w; - - return out; -} -#endif - -// ************************************************************************************************* -// Softimage PIC loader -// by Tom Seddon -// -// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format -// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ - -#ifndef STBI_NO_PIC -static int stbi__pic_is4(stbi__context *s,const char *str) -{ - int i; - for (i=0; i<4; ++i) - if (stbi__get8(s) != (stbi_uc)str[i]) - return 0; - - return 1; -} - -static int stbi__pic_test_core(stbi__context *s) -{ - int i; - - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) - return 0; - - for(i=0;i<84;++i) - stbi__get8(s); - - if (!stbi__pic_is4(s,"PICT")) - return 0; - - return 1; -} - -typedef struct -{ - stbi_uc size,type,channel; -} stbi__pic_packet; - -static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) -{ - int mask=0x80, i; - - for (i=0; i<4; ++i, mask>>=1) { - if (channel & mask) { - if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); - dest[i]=stbi__get8(s); - } - } - - return dest; -} - -static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) -{ - int mask=0x80,i; - - for (i=0;i<4; ++i, mask>>=1) - if (channel&mask) - dest[i]=src[i]; -} - -static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) -{ - int act_comp=0,num_packets=0,y,chained; - stbi__pic_packet packets[10]; - - // this will (should...) cater for even some bizarre stuff like having data - // for the same channel in multiple packets. - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return stbi__errpuc("bad format","too many packets"); - - packet = &packets[num_packets++]; - - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - - act_comp |= packet->channel; - - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); - if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? - - for(y=0; ytype) { - default: - return stbi__errpuc("bad format","packet has bad compression type"); - - case 0: {//uncompressed - int x; - - for(x=0;xchannel,dest)) - return 0; - break; - } - - case 1://Pure RLE - { - int left=width, i; - - while (left>0) { - stbi_uc count,value[4]; - - count=stbi__get8(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); - - if (count > left) - count = (stbi_uc) left; - - if (!stbi__readval(s,packet->channel,value)) return 0; - - for(i=0; ichannel,dest,value); - left -= count; - } - } - break; - - case 2: {//Mixed RLE - int left=width; - while (left>0) { - int count = stbi__get8(s), i; - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); - - if (count >= 128) { // Repeated - stbi_uc value[4]; - int i; - - if (count==128) - count = stbi__get16be(s); - else - count -= 127; - if (count > left) - return stbi__errpuc("bad file","scanline overrun"); - - if (!stbi__readval(s,packet->channel,value)) - return 0; - - for(i=0;ichannel,dest,value); - } else { // Raw - ++count; - if (count>left) return stbi__errpuc("bad file","scanline overrun"); - - for(i=0;ichannel,dest)) - return 0; - } - left-=count; - } - break; - } - } - } - } - - return result; -} - -static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp) -{ - stbi_uc *result; - int i, x,y; - - for (i=0; i<92; ++i) - stbi__get8(s); - - x = stbi__get16be(s); - y = stbi__get16be(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); - if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode"); - - stbi__get32be(s); //skip `ratio' - stbi__get16be(s); //skip `fields' - stbi__get16be(s); //skip `pad' - - // intermediate buffer is RGBA - result = (stbi_uc *) stbi__malloc(x*y*4); - memset(result, 0xff, x*y*4); - - if (!stbi__pic_load_core(s,x,y,comp, result)) { - STBI_FREE(result); - result=0; - } - *px = x; - *py = y; - if (req_comp == 0) req_comp = *comp; - result=stbi__convert_format(result,4,req_comp,x,y); - - return result; -} - -static int stbi__pic_test(stbi__context *s) -{ - int r = stbi__pic_test_core(s); - stbi__rewind(s); - return r; -} -#endif - -// ************************************************************************************************* -// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb - -#ifndef STBI_NO_GIF -typedef struct -{ - stbi__int16 prefix; - stbi_uc first; - stbi_uc suffix; -} stbi__gif_lzw; - -typedef struct -{ - int w,h; - stbi_uc *out; // output buffer (always 4 components) - int flags, bgindex, ratio, transparent, eflags; - stbi_uc pal[256][4]; - stbi_uc lpal[256][4]; - stbi__gif_lzw codes[4096]; - stbi_uc *color_table; - int parse, step; - int lflags; - int start_x, start_y; - int max_x, max_y; - int cur_x, cur_y; - int line_size; -} stbi__gif; - -static int stbi__gif_test_raw(stbi__context *s) -{ - int sz; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; - sz = stbi__get8(s); - if (sz != '9' && sz != '7') return 0; - if (stbi__get8(s) != 'a') return 0; - return 1; -} - -static int stbi__gif_test(stbi__context *s) -{ - int r = stbi__gif_test_raw(s); - stbi__rewind(s); - return r; -} - -static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) -{ - int i; - for (i=0; i < num_entries; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - pal[i][3] = transp == i ? 0 : 255; - } -} - -static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) -{ - stbi_uc version; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') - return stbi__err("not GIF", "Corrupt GIF"); - - version = stbi__get8(s); - if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); - if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); - - stbi__g_failure_reason = ""; - g->w = stbi__get16le(s); - g->h = stbi__get16le(s); - g->flags = stbi__get8(s); - g->bgindex = stbi__get8(s); - g->ratio = stbi__get8(s); - g->transparent = -1; - - if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments - - if (is_info) return 1; - - if (g->flags & 0x80) - stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); - - return 1; -} - -static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__gif g; - if (!stbi__gif_header(s, &g, comp, 1)) { - stbi__rewind( s ); - return 0; - } - if (x) *x = g.w; - if (y) *y = g.h; - return 1; -} - -static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) -{ - stbi_uc *p, *c; - - // recurse to decode the prefixes, since the linked-list is backwards, - // and working backwards through an interleaved image would be nasty - if (g->codes[code].prefix >= 0) - stbi__out_gif_code(g, g->codes[code].prefix); - - if (g->cur_y >= g->max_y) return; - - p = &g->out[g->cur_x + g->cur_y]; - c = &g->color_table[g->codes[code].suffix * 4]; - - if (c[3] >= 128) { - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } - g->cur_x += 4; - - if (g->cur_x >= g->max_x) { - g->cur_x = g->start_x; - g->cur_y += g->step; - - while (g->cur_y >= g->max_y && g->parse > 0) { - g->step = (1 << g->parse) * g->line_size; - g->cur_y = g->start_y + (g->step >> 1); - --g->parse; - } - } -} - -static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) -{ - stbi_uc lzw_cs; - stbi__int32 len, code; - stbi__uint32 first; - stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; - stbi__gif_lzw *p; - - lzw_cs = stbi__get8(s); - clear = 1 << lzw_cs; - first = 1; - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - bits = 0; - valid_bits = 0; - for (code = 0; code < clear; code++) { - g->codes[code].prefix = -1; - g->codes[code].first = (stbi_uc) code; - g->codes[code].suffix = (stbi_uc) code; - } - - // support no starting clear code - avail = clear+2; - oldcode = -1; - - len = 0; - for(;;) { - if (valid_bits < codesize) { - if (len == 0) { - len = stbi__get8(s); // start new block - if (len == 0) - return g->out; - } - --len; - bits |= (stbi__int32) stbi__get8(s) << valid_bits; - valid_bits += 8; - } else { - stbi__int32 code = bits & codemask; - bits >>= codesize; - valid_bits -= codesize; - // @OPTIMIZE: is there some way we can accelerate the non-clear path? - if (code == clear) { // clear code - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - avail = clear + 2; - oldcode = -1; - first = 0; - } else if (code == clear + 1) { // end of stream code - stbi__skip(s, len); - while ((len = stbi__get8(s)) > 0) - stbi__skip(s,len); - return g->out; - } else if (code <= avail) { - if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); - - if (oldcode >= 0) { - p = &g->codes[avail++]; - if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); - p->prefix = (stbi__int16) oldcode; - p->first = g->codes[oldcode].first; - p->suffix = (code == avail) ? p->first : g->codes[code].first; - } else if (code == avail) - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - - stbi__out_gif_code(g, (stbi__uint16) code); - - if ((avail & codemask) == 0 && avail <= 0x0FFF) { - codesize++; - codemask = (1 << codesize) - 1; - } - - oldcode = code; - } else { - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - } - } - } -} - -static void stbi__fill_gif_background(stbi__gif *g) -{ - int i; - stbi_uc *c = g->pal[g->bgindex]; - // @OPTIMIZE: write a dword at a time - for (i = 0; i < g->w * g->h * 4; i += 4) { - stbi_uc *p = &g->out[i]; - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } -} - -// this function is designed to support animated gifs, although stb_image doesn't support it -static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) -{ - int i; - stbi_uc *old_out = 0; - - if (g->out == 0) { - if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header - g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); - stbi__fill_gif_background(g); - } else { - // animated-gif-only path - if (((g->eflags & 0x1C) >> 2) == 3) { - old_out = g->out; - g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); - memcpy(g->out, old_out, g->w*g->h*4); - } - } - - for (;;) { - switch (stbi__get8(s)) { - case 0x2C: /* Image Descriptor */ - { - stbi__int32 x, y, w, h; - stbi_uc *o; - - x = stbi__get16le(s); - y = stbi__get16le(s); - w = stbi__get16le(s); - h = stbi__get16le(s); - if (((x + w) > (g->w)) || ((y + h) > (g->h))) - return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); - - g->line_size = g->w * 4; - g->start_x = x * 4; - g->start_y = y * g->line_size; - g->max_x = g->start_x + w * 4; - g->max_y = g->start_y + h * g->line_size; - g->cur_x = g->start_x; - g->cur_y = g->start_y; - - g->lflags = stbi__get8(s); - - if (g->lflags & 0x40) { - g->step = 8 * g->line_size; // first interlaced spacing - g->parse = 3; - } else { - g->step = g->line_size; - g->parse = 0; - } - - if (g->lflags & 0x80) { - stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); - g->color_table = (stbi_uc *) g->lpal; - } else if (g->flags & 0x80) { - for (i=0; i < 256; ++i) // @OPTIMIZE: stbi__jpeg_reset only the previous transparent - g->pal[i][3] = 255; - if (g->transparent >= 0 && (g->eflags & 0x01)) - g->pal[g->transparent][3] = 0; - g->color_table = (stbi_uc *) g->pal; - } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - - o = stbi__process_gif_raster(s, g); - if (o == NULL) return NULL; - - if (req_comp && req_comp != 4) - o = stbi__convert_format(o, 4, req_comp, g->w, g->h); - return o; - } - - case 0x21: // Comment Extension. - { - int len; - if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. - len = stbi__get8(s); - if (len == 4) { - g->eflags = stbi__get8(s); - stbi__get16le(s); // delay - g->transparent = stbi__get8(s); - } else { - stbi__skip(s, len); - break; - } - } - while ((len = stbi__get8(s)) != 0) - stbi__skip(s, len); - break; - } - - case 0x3B: // gif stream termination code - return (stbi_uc *) s; // using '1' causes warning on some compilers - - default: - return stbi__errpuc("unknown code", "Corrupt GIF"); - } - } -} - -static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *u = 0; - stbi__gif g; - memset(&g, 0, sizeof(g)); - - u = stbi__gif_load_next(s, &g, comp, req_comp); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker - if (u) { - *x = g.w; - *y = g.h; - } - - return u; -} - -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) -{ - return stbi__gif_info_raw(s,x,y,comp); -} -#endif - -// ************************************************************************************************* -// Radiance RGBE HDR loader -// originally by Nicolas Schulz -#ifndef STBI_NO_HDR -static int stbi__hdr_test_core(stbi__context *s) -{ - const char *signature = "#?RADIANCE\n"; - int i; - for (i=0; signature[i]; ++i) - if (stbi__get8(s) != signature[i]) - return 0; - return 1; -} - -static int stbi__hdr_test(stbi__context* s) -{ - int r = stbi__hdr_test_core(s); - stbi__rewind(s); - return r; -} - -#define STBI__HDR_BUFLEN 1024 -static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) -{ - int len=0; - char c = '\0'; - - c = (char) stbi__get8(z); - - while (!stbi__at_eof(z) && c != '\n') { - buffer[len++] = c; - if (len == STBI__HDR_BUFLEN-1) { - // flush to end of line - while (!stbi__at_eof(z) && stbi__get8(z) != '\n') - ; - break; - } - c = (char) stbi__get8(z); - } - - buffer[len] = 0; - return buffer; -} - -static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) -{ - if ( input[3] != 0 ) { - float f1; - // Exponent - f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); - if (req_comp <= 2) - output[0] = (input[0] + input[1] + input[2]) * f1 / 3; - else { - output[0] = input[0] * f1; - output[1] = input[1] * f1; - output[2] = input[2] * f1; - } - if (req_comp == 2) output[1] = 1; - if (req_comp == 4) output[3] = 1; - } else { - switch (req_comp) { - case 4: output[3] = 1; /* fallthrough */ - case 3: output[0] = output[1] = output[2] = 0; - break; - case 2: output[1] = 1; /* fallthrough */ - case 1: output[0] = 0; - break; - } - } -} - -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int width, height; - stbi_uc *scanline; - float *hdr_data; - int len; - unsigned char count, value; - int i, j, k, c1,c2, z; - - - // Check identifier - if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) - return stbi__errpf("not HDR", "Corrupt HDR image"); - - // Parse header - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); - - // Parse width and height - // can't use sscanf() if we're not using stdio! - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - height = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - width = (int) strtol(token, NULL, 10); - - *x = width; - *y = height; - - if (comp) *comp = 3; - if (req_comp == 0) req_comp = 3; - - // Read data - hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float)); - - // Load image data - // image data is stored as some number of sca - if ( width < 8 || width >= 32768) { - // Read flat data - for (j=0; j < height; ++j) { - for (i=0; i < width; ++i) { - stbi_uc rgbe[4]; - main_decode_loop: - stbi__getn(s, rgbe, 4); - stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); - } - } - } else { - // Read RLE-encoded data - scanline = NULL; - - for (j = 0; j < height; ++j) { - c1 = stbi__get8(s); - c2 = stbi__get8(s); - len = stbi__get8(s); - if (c1 != 2 || c2 != 2 || (len & 0x80)) { - // not run-length encoded, so we have to actually use THIS data as a decoded - // pixel (note this can't be a valid pixel--one of RGB must be >= 128) - stbi_uc rgbe[4]; - rgbe[0] = (stbi_uc) c1; - rgbe[1] = (stbi_uc) c2; - rgbe[2] = (stbi_uc) len; - rgbe[3] = (stbi_uc) stbi__get8(s); - stbi__hdr_convert(hdr_data, rgbe, req_comp); - i = 1; - j = 0; - STBI_FREE(scanline); - goto main_decode_loop; // yes, this makes no sense - } - len <<= 8; - len |= stbi__get8(s); - if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4); - - for (k = 0; k < 4; ++k) { - i = 0; - while (i < width) { - count = stbi__get8(s); - if (count > 128) { - // Run - value = stbi__get8(s); - count -= 128; - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = value; - } else { - // Dump - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = stbi__get8(s); - } - } - } - for (i=0; i < width; ++i) - stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); - } - STBI_FREE(scanline); - } - - return hdr_data; -} - -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - - if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { - stbi__rewind( s ); - return 0; - } - - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } - - if (!valid) { - stbi__rewind( s ); - return 0; - } - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *y = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *x = (int) strtol(token, NULL, 10); - *comp = 3; - return 1; -} -#endif // STBI_NO_HDR - -#ifndef STBI_NO_BMP -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) -{ - int hsz; - if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') { - stbi__rewind( s ); - return 0; - } - stbi__skip(s,12); - hsz = stbi__get32le(s); - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) { - stbi__rewind( s ); - return 0; - } - if (hsz == 12) { - *x = stbi__get16le(s); - *y = stbi__get16le(s); - } else { - *x = stbi__get32le(s); - *y = stbi__get32le(s); - } - if (stbi__get16le(s) != 1) { - stbi__rewind( s ); - return 0; - } - *comp = stbi__get16le(s) / 8; - return 1; -} -#endif - -#ifndef STBI_NO_PSD -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) -{ - int channelCount; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - *y = stbi__get32be(s); - *x = stbi__get32be(s); - if (stbi__get16be(s) != 8) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 3) { - stbi__rewind( s ); - return 0; - } - *comp = 4; - return 1; -} -#endif - -#ifndef STBI_NO_PIC -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) -{ - int act_comp=0,num_packets=0,chained; - stbi__pic_packet packets[10]; - - stbi__skip(s, 92); - - *x = stbi__get16be(s); - *y = stbi__get16be(s); - if (stbi__at_eof(s)) return 0; - if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { - stbi__rewind( s ); - return 0; - } - - stbi__skip(s, 8); - - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return 0; - - packet = &packets[num_packets++]; - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - act_comp |= packet->channel; - - if (stbi__at_eof(s)) { - stbi__rewind( s ); - return 0; - } - if (packet->size != 8) { - stbi__rewind( s ); - return 0; - } - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); - - return 1; -} -#endif - -// ************************************************************************************************* -// Portable Gray Map and Portable Pixel Map loader -// by Ken Miller -// -// PGM: http://netpbm.sourceforge.net/doc/pgm.html -// PPM: http://netpbm.sourceforge.net/doc/ppm.html -// -// Known limitations: -// Does not support comments in the header section -// Does not support ASCII image data (formats P2 and P3) -// Does not support 16-bit-per-channel - -#ifndef STBI_NO_PNM - -static int stbi__pnm_test(stbi__context *s) -{ - char p, t; - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); - return 0; - } - return 1; -} - -static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi_uc *out; - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) - return 0; - *x = s->img_x; - *y = s->img_y; - *comp = s->img_n; - - out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y); - - if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - return out; -} - -static int stbi__pnm_isspace(char c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; -} - -static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) -{ - while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) - *c = (char) stbi__get8(s); -} - -static int stbi__pnm_isdigit(char c) -{ - return c >= '0' && c <= '9'; -} - -static int stbi__pnm_getinteger(stbi__context *s, char *c) -{ - int value = 0; - - while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { - value = value*10 + (*c - '0'); - *c = (char) stbi__get8(s); - } - - return value; -} - -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) -{ - int maxv; - char c, p, t; - - stbi__rewind( s ); - - // Get identifier - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); - return 0; - } - - *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm - - c = (char) stbi__get8(s); - stbi__pnm_skip_whitespace(s, &c); - - *x = stbi__pnm_getinteger(s, &c); // read width - stbi__pnm_skip_whitespace(s, &c); - - *y = stbi__pnm_getinteger(s, &c); // read height - stbi__pnm_skip_whitespace(s, &c); - - maxv = stbi__pnm_getinteger(s, &c); // read max value - - if (maxv > 255) - return stbi__err("max value > 255", "PPM image not 8-bit"); - else - return 1; -} -#endif - -static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) -{ - #ifndef STBI_NO_JPEG - if (stbi__jpeg_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PNG - if (stbi__png_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_GIF - if (stbi__gif_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_BMP - if (stbi__bmp_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PSD - if (stbi__psd_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PIC - if (stbi__pic_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_PNM - if (stbi__pnm_info(s, x, y, comp)) return 1; - #endif - - #ifndef STBI_NO_HDR - if (stbi__hdr_info(s, x, y, comp)) return 1; - #endif - - // test tga last because it's a crappy test! - #ifndef STBI_NO_TGA - if (stbi__tga_info(s, x, y, comp)) - return 1; - #endif - return stbi__err("unknown image type", "Image not of any known type, or corrupt"); -} - -#ifndef STBI_NO_STDIO -STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_info_from_file(f, x, y, comp); - fclose(f); - return result; -} - -STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__info_main(&s,x,y,comp); - fseek(f,pos,SEEK_SET); - return r; -} -#endif // !STBI_NO_STDIO - -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__info_main(&s,x,y,comp); -} - -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__info_main(&s,x,y,comp); -} - -#endif // STB_IMAGE_IMPLEMENTATION - -/* - revision history: - 2.02 (2015-01-19) fix incorrect assert, fix warning - 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 - 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG - 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) - progressive JPEG (stb) - PGM/PPM support (Ken Miller) - STBI_MALLOC,STBI_REALLOC,STBI_FREE - GIF bugfix -- seemingly never worked - STBI_NO_*, STBI_ONLY_* - 1.48 (2014-12-14) fix incorrectly-named assert() - 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) - optimize PNG (ryg) - fix bug in interlaced PNG with user-specified channel count (stb) - 1.46 (2014-08-26) - fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG - 1.45 (2014-08-16) - fix MSVC-ARM internal compiler error by wrapping malloc - 1.44 (2014-08-07) - various warning fixes from Ronny Chevalier - 1.43 (2014-07-15) - fix MSVC-only compiler problem in code changed in 1.42 - 1.42 (2014-07-09) - don't define _CRT_SECURE_NO_WARNINGS (affects user code) - fixes to stbi__cleanup_jpeg path - added STBI_ASSERT to avoid requiring assert.h - 1.41 (2014-06-25) - fix search&replace from 1.36 that messed up comments/error messages - 1.40 (2014-06-22) - fix gcc struct-initialization warning - 1.39 (2014-06-15) - fix to TGA optimization when req_comp != number of components in TGA; - fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) - add support for BMP version 5 (more ignored fields) - 1.38 (2014-06-06) - suppress MSVC warnings on integer casts truncating values - fix accidental rename of 'skip' field of I/O - 1.37 (2014-06-04) - remove duplicate typedef - 1.36 (2014-06-03) - convert to header file single-file library - if de-iphone isn't set, load iphone images color-swapped instead of returning NULL - 1.35 (2014-05-27) - various warnings - fix broken STBI_SIMD path - fix bug where stbi_load_from_file no longer left file pointer in correct place - fix broken non-easy path for 32-bit BMP (possibly never used) - TGA optimization by Arseny Kapoulkine - 1.34 (unknown) - use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case - 1.33 (2011-07-14) - make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements - 1.32 (2011-07-13) - support for "info" function for all supported filetypes (SpartanJ) - 1.31 (2011-06-20) - a few more leak fixes, bug in PNG handling (SpartanJ) - 1.30 (2011-06-11) - added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) - removed deprecated format-specific test/load functions - removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway - error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) - fix inefficiency in decoding 32-bit BMP (David Woo) - 1.29 (2010-08-16) - various warning fixes from Aurelien Pocheville - 1.28 (2010-08-01) - fix bug in GIF palette transparency (SpartanJ) - 1.27 (2010-08-01) - cast-to-stbi_uc to fix warnings - 1.26 (2010-07-24) - fix bug in file buffering for PNG reported by SpartanJ - 1.25 (2010-07-17) - refix trans_data warning (Won Chun) - 1.24 (2010-07-12) - perf improvements reading from files on platforms with lock-heavy fgetc() - minor perf improvements for jpeg - deprecated type-specific functions so we'll get feedback if they're needed - attempt to fix trans_data warning (Won Chun) - 1.23 fixed bug in iPhone support - 1.22 (2010-07-10) - removed image *writing* support - stbi_info support from Jetro Lauha - GIF support from Jean-Marc Lienher - iPhone PNG-extensions from James Brown - warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) - 1.21 fix use of 'stbi_uc' in header (reported by jon blow) - 1.20 added support for Softimage PIC, by Tom Seddon - 1.19 bug in interlaced PNG corruption check (found by ryg) - 1.18 2008-08-02 - fix a threading bug (local mutable static) - 1.17 support interlaced PNG - 1.16 major bugfix - stbi__convert_format converted one too many pixels - 1.15 initialize some fields for thread safety - 1.14 fix threadsafe conversion bug - header-file-only version (#define STBI_HEADER_FILE_ONLY before including) - 1.13 threadsafe - 1.12 const qualifiers in the API - 1.11 Support installable IDCT, colorspace conversion routines - 1.10 Fixes for 64-bit (don't use "unsigned long") - optimized upsampling by Fabian "ryg" Giesen - 1.09 Fix format-conversion for PSD code (bad global variables!) - 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz - 1.07 attempt to fix C++ warning/errors again - 1.06 attempt to fix C++ warning/errors again - 1.05 fix TGA loading to return correct *comp and use good luminance calc - 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free - 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR - 1.02 support for (subset of) HDR files, float interface for preferred access to them - 1.01 fix bug: possible bug in handling right-side up bmps... not sure - fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all - 1.00 interface to zlib that skips zlib header - 0.99 correct handling of alpha in palette - 0.98 TGA loader by lonesock; dynamically add loaders (untested) - 0.97 jpeg errors on too large a file; also catch another malloc failure - 0.96 fix detection of invalid v value - particleman@mollyrocket forum - 0.95 during header scan, seek to markers in case of padding - 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same - 0.93 handle jpegtran output; verbose errors - 0.92 read 4,8,16,24,32-bit BMP files of several formats - 0.91 output 24-bit Windows 3.0 BMP files - 0.90 fix a few more warnings; bump version number to approach 1.0 - 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd - 0.60 fix compiling as c++ - 0.59 fix warnings: merge Dave Moore's -Wall fixes - 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian - 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available - 0.56 fix bug: zlib uncompressed mode len vs. nlen - 0.55 fix bug: restart_interval not initialized to 0 - 0.54 allow NULL for 'int *comp' - 0.53 fix bug in png 3->4; speedup png decoding - 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments - 0.51 obey req_comp requests, 1-component jpegs return as 1-component, - on 'test' only check type, not whether we support this variant - 0.50 first released version -*/ diff --git a/direct/src/plugin/twirl.xcf b/direct/src/plugin/twirl.xcf deleted file mode 100644 index deff7efebf295c4f92423ec3d01f2c6fdc2da8e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 151445 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 -#include -#include - -#ifdef _WIN32 -#include -#endif // _WIN32 - -#ifdef _WIN32 -/** - * Encodes std::wstring to std::string using UTF-8. - */ -bool -wstring_to_string(std::string &result, const std::wstring &source) { - bool success = false; - int size = WideCharToMultiByte(CP_UTF8, 0, source.data(), source.length(), - nullptr, 0, nullptr, nullptr); - if (size > 0) { - char *buffer = new char[size]; - int rc = WideCharToMultiByte(CP_UTF8, 0, source.data(), source.length(), - buffer, size, nullptr, nullptr); - if (rc != 0) { - result.assign(buffer, size); - success = true; - } - delete[] buffer; - } - - return success; -} -#endif // _WIN32 - -#ifdef _WIN32 -/** - * Decodes std::string to std::wstring using UTF-8. - */ -bool -string_to_wstring(std::wstring &result, const std::string &source) { - bool success = false; - int size = MultiByteToWideChar(CP_UTF8, 0, source.data(), source.length(), - nullptr, 0); - if (size > 0) { - wchar_t *buffer = new wchar_t[size]; - int rc = MultiByteToWideChar(CP_UTF8, 0, source.data(), source.length(), - buffer, size); - if (rc != 0) { - result.assign(buffer, size); - success = true; - } - delete[] buffer; - } - - return success; -} -#endif // _WIN32 diff --git a/direct/src/plugin/wstring_encode.h b/direct/src/plugin/wstring_encode.h deleted file mode 100644 index b9641bd43d..0000000000 --- a/direct/src/plugin/wstring_encode.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file wstring_encode.h - * @author drose - * @date 2009-06-29 - */ - -#ifndef WSTRING_ENCODE_H -#define WSTRING_ENCODE_H - -#include - -// Presently, these two functions are implemented only for Windows, which is -// the only place they are needed. (Only Windows requires wstrings for -// filenames.) -#ifdef _WIN32 -bool wstring_to_string(std::string &result, const std::wstring &source); -bool string_to_wstring(std::wstring &result, const std::string &source); - -// We declare this inline so it won't conflict with the similar function -// defined in Panda's textEncoder.h. -inline std::ostream &operator << (std::ostream &out, const std::wstring &str) { - std::string result; - if (wstring_to_string(result, str)) { - out << result; - } - return out; -} - -#endif // _WIN32 - -#endif diff --git a/direct/src/plugin/xml_helpers.cxx b/direct/src/plugin/xml_helpers.cxx deleted file mode 100644 index 9a997189da..0000000000 --- a/direct/src/plugin/xml_helpers.cxx +++ /dev/null @@ -1,40 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file xml_helpers.cxx - * @author drose - * @date 2012-09-28 - */ - -#include "p3d_plugin_common.h" -#include "xml_helpers.h" - - -/** - * Examines the indicated attrib from the XML attrib and returns its true or - * false value. Returns default_value if the attrib is not present or is - * empty. - */ -bool -parse_bool_attrib(TiXmlElement *xelem, const std::string &attrib, - bool default_value) { - const char *value = xelem->Attribute(attrib.c_str()); - if (value == nullptr || *value == '\0') { - return default_value; - } - - char *endptr; - int result = strtol(value, &endptr, 10); - if (*endptr == '\0') { - // A valid integer. - return (result != 0); - } - - // An invalid integer. - return default_value; -} diff --git a/direct/src/plugin/xml_helpers.h b/direct/src/plugin/xml_helpers.h deleted file mode 100644 index d64047f55a..0000000000 --- a/direct/src/plugin/xml_helpers.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file xml_helpers.h - * @author drose - * @date 2012-09-28 - */ - -#ifndef XML_HELPERS_H -#define XML_HELPERS_H - -#include "get_tinyxml.h" - -bool parse_bool_attrib(TiXmlElement *xelem, const std::string &attrib, - bool default_value); - -#endif diff --git a/direct/src/plugin_activex/P3DActiveX.cpp b/direct/src/plugin_activex/P3DActiveX.cpp deleted file mode 100644 index 500effc38f..0000000000 --- a/direct/src/plugin_activex/P3DActiveX.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file P3DActiveX.cpp - * @author atrestman - * @date 2009-09-14 - */ - -// P3DActiveX.cpp : Implementation of CP3DActiveXApp and DLL registration. - -#include "stdafx.h" -#include "P3DActiveX.h" - -#include -#include -#include - - -#ifdef _DEBUG -#define new DEBUG_NEW -#endif - - -CP3DActiveXApp NEAR theApp; - -const GUID CDECL BASED_CODE _tlid = - { 0x22A8FC5F, 0xBC33, 0x479A, { 0x83, 0x17, 0x2B, 0xC8, 0x16, 0xB8, 0xAB, 0x8A } }; -const WORD _wVerMajor = 1; -const WORD _wVerMinor = 0; - -// CLSID_SafeItem - Necessary for safe ActiveX control - -// Id taken from IMPLEMENT_OLECREATE_EX function in xxxCtrl.cpp - - -const CATID CLSID_SafeItem = -{ 0x924b4927, 0xd3ba, 0x41ea, 0x9f, 0x7e, 0x8a, 0x89, 0x19, 0x4a, 0xb3, 0xac }; - -// HRESULT CreateComponentCategory - Used to register ActiveX control as safe - - -HRESULT CreateComponentCategory(CATID catid, WCHAR *catDescription) -{ - ICatRegister *pcr = NULL ; - HRESULT hr = S_OK ; - - hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, - NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr); - if (FAILED(hr)) - return hr; - - // Make sure the HKCR\Component Categories\{..catid...} - - // key is registered. - - CATEGORYINFO catinfo; - catinfo.catid = catid; - catinfo.lcid = 0x0409 ; // english - - size_t len; - // Make sure the provided description is not too long. - - // Only copy the first 127 characters if it is. - - // The second parameter of StringCchLength is the maximum - - // number of characters that may be read into catDescription. - - // There must be room for a NULL-terminator. The third parameter - - // contains the number of characters excluding the NULL-terminator. - - hr = StringCchLengthW(catDescription, STRSAFE_MAX_CCH, &len); - if (SUCCEEDED(hr)) - { - if (len>127) - { - len = 127; - } - } - else - { - // TODO: Write an error handler; - - } - // The second parameter of StringCchCopy is 128 because you need - - // room for a NULL-terminator. - - hr = StringCchCopyW(catinfo.szDescription, len + 1, catDescription); - // Make sure the description is null terminated. - - catinfo.szDescription[len + 1] = '\0'; - - hr = pcr->RegisterCategories(1, &catinfo); - pcr->Release(); - - return hr; -} - -// HRESULT RegisterCLSIDInCategory - - -// Register your component categories information - - -HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid) -{ -// Register your component categories information. - - ICatRegister *pcr = NULL ; - HRESULT hr = S_OK ; - hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, - NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr); - if (SUCCEEDED(hr)) - { - // Register this category as being "implemented" by the class. - - CATID rgcatid[1] ; - rgcatid[0] = catid; - hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid); - } - - if (pcr != NULL) - pcr->Release(); - - return hr; -} - -// HRESULT UnRegisterCLSIDInCategory - Remove entries from the registry - - -HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid) -{ - ICatRegister *pcr = NULL ; - HRESULT hr = S_OK ; - - hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, - NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr); - if (SUCCEEDED(hr)) - { - // Unregister this category as being "implemented" by the class. - - CATID rgcatid[1] ; - rgcatid[0] = catid; - hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid); - } - - if (pcr != NULL) - pcr->Release(); - - return hr; -} - - -// CP3DActiveXApp::InitInstance - DLL initialization - -BOOL CP3DActiveXApp::InitInstance() -{ - BOOL bInit = COleControlModule::InitInstance(); - - if (bInit) - { - // TODO: Add your own module initialization code here. - - // Seed the lame random number generator in rand(); we use it to select - // a mirror for downloading. - srand((unsigned int)time(NULL)); - } - - return bInit; -} - - - -// CP3DActiveXApp::ExitInstance - DLL termination - -int CP3DActiveXApp::ExitInstance() -{ - // TODO: Add your own module termination code here. - - return COleControlModule::ExitInstance(); -} - - - -// DllRegisterServer - Adds entries to the system registry - -STDAPI DllRegisterServer(void) -{ - HRESULT hr; // HResult used by Safety Functions - - - AFX_MANAGE_STATE(_afxModuleAddrThis); - - if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid)) - return ResultFromScode(SELFREG_E_TYPELIB); - - if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE)) - return ResultFromScode(SELFREG_E_CLASS); - - // Mark the control as safe for initializing. - - - hr = CreateComponentCategory(CATID_SafeForInitializing, - L"Controls safely initializable from persistent data!"); - if (FAILED(hr)) - return hr; - - hr = RegisterCLSIDInCategory(CLSID_SafeItem, - CATID_SafeForInitializing); - if (FAILED(hr)) - return hr; - - // Mark the control as safe for scripting. - - - hr = CreateComponentCategory(CATID_SafeForScripting, - L"Controls safely scriptable!"); - if (FAILED(hr)) - return hr; - - hr = RegisterCLSIDInCategory(CLSID_SafeItem, - CATID_SafeForScripting); - if (FAILED(hr)) - return hr; - - return NOERROR; -} - - - -// DllUnregisterServer - Removes entries from the system registry - -STDAPI DllUnregisterServer(void) -{ - HRESULT hr; // HResult used by Safety Functions - - - AFX_MANAGE_STATE(_afxModuleAddrThis); - - // Remove entries from the registry. - - hr = UnRegisterCLSIDInCategory(CLSID_SafeItem, - CATID_SafeForInitializing); - if (FAILED(hr)) - return hr; - - hr = UnRegisterCLSIDInCategory(CLSID_SafeItem, - CATID_SafeForScripting); - if (FAILED(hr)) - return hr; - - if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor)) - return ResultFromScode(SELFREG_E_TYPELIB); - - if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE)) - return ResultFromScode(SELFREG_E_CLASS); - - return NOERROR; -} diff --git a/direct/src/plugin_activex/P3DActiveX.def b/direct/src/plugin_activex/P3DActiveX.def deleted file mode 100644 index e8ca82f83a..0000000000 --- a/direct/src/plugin_activex/P3DActiveX.def +++ /dev/null @@ -1,9 +0,0 @@ -; P3DActiveX.def : Declares the module parameters. - -LIBRARY "P3DActiveX.OCX" - -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE diff --git a/direct/src/plugin_activex/P3DActiveX.h b/direct/src/plugin_activex/P3DActiveX.h deleted file mode 100644 index 1024021791..0000000000 --- a/direct/src/plugin_activex/P3DActiveX.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file P3DActiveX.h - * @author atrestman - * @date 2009-09-14 - */ - -#pragma once - -// P3DActiveX.h : main header file for P3DActiveX.DLL - -#if !defined( __AFXCTL_H__ ) -#error include 'afxctl.h' before including this file -#endif - -#include "resource.h" // main symbols - - -// CP3DActiveXApp : See P3DActiveX.cpp for implementation. - -class CP3DActiveXApp : public COleControlModule -{ -public: - BOOL InitInstance(); - int ExitInstance(); -}; - -extern const GUID CDECL _tlid; -extern const WORD _wVerMajor; -extern const WORD _wVerMinor; diff --git a/direct/src/plugin_activex/P3DActiveX.idl b/direct/src/plugin_activex/P3DActiveX.idl deleted file mode 100644 index 4406b55abe..0000000000 --- a/direct/src/plugin_activex/P3DActiveX.idl +++ /dev/null @@ -1,51 +0,0 @@ -// P3DActiveX.idl : type library source for ActiveX Control project. - -// This file will be processed by the MIDL compiler tool to -// produce the type library (P3DActiveX.tlb) that will become a resource in -// P3DActiveX.ocx. - -#include -#include - -[ uuid(22A8FC5F-BC33-479A-8317-2BC816B8AB8A), version(1.0), - helpfile("P3DActiveX.hlp"), - helpstring("P3DActiveX ActiveX Control module"), - control ] -library P3DActiveXLib -{ - importlib(STDOLE_TLB); - - // Primary dispatch interface for CP3DActiveXCtrl - - [ uuid(76904D54-0CC5-4DBB-B022-F48B1E95183B), - helpstring("Dispatch interface for P3DActiveX Control")] - dispinterface _DP3DActiveX - { - properties: - [id(1), helpstring("property main")] IDispatch*main; - methods: - }; - - // Event dispatch interface for CP3DActiveXCtrl - - [ uuid(1B2413ED-51C8-495E-B917-983C459B8FC7), - helpstring("Event interface for P3DActiveX Control") ] - dispinterface _DP3DActiveXEvents - { - properties: - // Event interface has no properties - - methods: - }; - - // Class information for CP3DActiveXCtrl - - [ uuid(924B4927-D3BA-41EA-9F7E-8A89194AB3AC), - helpstring("P3DActiveX Control"), control ] - coclass P3DActiveX - { - [default] dispinterface _DP3DActiveX; - [default, source] dispinterface _DP3DActiveXEvents; - }; - -}; diff --git a/direct/src/plugin_activex/P3DActiveX.inf b/direct/src/plugin_activex/P3DActiveX.inf deleted file mode 100644 index 3ec50e6282..0000000000 --- a/direct/src/plugin_activex/P3DActiveX.inf +++ /dev/null @@ -1,34 +0,0 @@ -[Add.Code] -P3DActiveX.ocx=P3DActiveX.ocx -P3DActiveX.inf=P3DActiveX.inf -mfc71.dll=mfc71.dll -msvcr71.dll=msvcr71.dll -msvcp71.dll=msvcp71.dll - -[P3DActiveX.ocx] -file=thiscab -clsid={924B4927-D3BA-41EA-9F7E-8A89194AB3AC} -RegisterServer=yes -FileVersion=1,0,0,0 - -[P3DActiveX.inf] -file=thiscab - -[mfc71.dll] -file=thiscab -DestDir=11 -RegisterServer=yes -FileVersion=7,10,3077,0 - -[msvcr71.dll] -file=thiscab -DestDir=11 -RegisterServer=yes -FileVersion=7,10,3052,4 - -[msvcp71.dll] -file=thiscab -DestDir=11 -RegisterServer=yes -FileVersion=7,10,3077,0 - diff --git a/direct/src/plugin_activex/P3DActiveX.sln b/direct/src/plugin_activex/P3DActiveX.sln deleted file mode 100644 index 5263bf1e8b..0000000000 --- a/direct/src/plugin_activex/P3DActiveX.sln +++ /dev/null @@ -1,21 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "P3DActiveX", "P3DActiveX.vcproj", "{74451B00-2D87-412B-9359-B5CA2C2FEC2A}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {74451B00-2D87-412B-9359-B5CA2C2FEC2A}.Debug.ActiveCfg = Debug|Win32 - {74451B00-2D87-412B-9359-B5CA2C2FEC2A}.Debug.Build.0 = Debug|Win32 - {74451B00-2D87-412B-9359-B5CA2C2FEC2A}.Release.ActiveCfg = Release|Win32 - {74451B00-2D87-412B-9359-B5CA2C2FEC2A}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal diff --git a/direct/src/plugin_activex/P3DActiveX.vcproj b/direct/src/plugin_activex/P3DActiveX.vcproj deleted file mode 100644 index ccb33b68a5..0000000000 --- a/direct/src/plugin_activex/P3DActiveX.vcproj +++ /dev/null @@ -1,275 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/direct/src/plugin_activex/P3DActiveXCtrl.bmp b/direct/src/plugin_activex/P3DActiveXCtrl.bmp deleted file mode 100644 index 3ffeb056fd30dd555c96a153a12070f902dbf036..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 238 zcmaisyA6Oa3`7r!9>!n}dP+;41W~3r$zx?ARtT3*3BvZfvmM3zaihm6+r%msF=3Vh zSJO91fC?#fld2U7IcGhTRw$)*LRnXm_z7Cj7-n?i@Cei37EzbgErz$5boPJFuk#OT CFi -#include -#include - -#include - -class CPropbagPropExchange : public CPropExchange -{ -public: - CPropbagPropExchange(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, - BOOL bLoading, BOOL bSaveAllProperties=FALSE); - ~CPropbagPropExchange(); - -// Operations - virtual BOOL ExchangeProp(LPCTSTR pszPropName, VARTYPE vtProp, - void* pvProp, const void* pvDefault = NULL); - virtual BOOL ExchangeBlobProp(LPCTSTR pszPropName, HGLOBAL* phBlob, - HGLOBAL hBlobDefault = NULL); - virtual BOOL ExchangeFontProp(LPCTSTR pszPropName, CFontHolder& font, - const FONTDESC* pFontDesc, LPFONTDISP pFontDispAmbient); - virtual BOOL ExchangePersistentProp(LPCTSTR pszPropName, - LPUNKNOWN* ppUnk, REFIID iid, LPUNKNOWN pUnkDefault); - -// Implementation - LPPROPERTYBAG m_pPropBag; - LPERRORLOG m_pErrorLog; - BOOL m_bSaveAllProperties; -}; - -#ifdef _DEBUG -#define new DEBUG_NEW -#endif - - -IMPLEMENT_DYNCREATE(CP3DActiveXCtrl, COleControl) - - - -// Message map - -BEGIN_MESSAGE_MAP(CP3DActiveXCtrl, COleControl) - ON_MESSAGE(OCM_COMMAND, OnOcmCommand) - ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties) - ON_WM_CREATE() - ON_MESSAGE(WM_PANDA_NOTIFICATION, OnPandaNotification) -END_MESSAGE_MAP() - - - -// Dispatch map - -BEGIN_DISPATCH_MAP(CP3DActiveXCtrl, COleControl) - DISP_PROPERTY_NOTIFY_ID(CP3DActiveXCtrl, "main", dispidmain, m_pPandaObject, OnmainChanged, VT_DISPATCH) -END_DISPATCH_MAP() - - - -// Event map - -BEGIN_EVENT_MAP(CP3DActiveXCtrl, COleControl) -END_EVENT_MAP() - - - -// Property pages - -// TODO: Add more property pages as needed. Remember to increase the count! -BEGIN_PROPPAGEIDS(CP3DActiveXCtrl, 1) - PROPPAGEID(CP3DActiveXPropPage::guid) -END_PROPPAGEIDS(CP3DActiveXCtrl) - - - -// Initialize class factory and guid - -IMPLEMENT_OLECREATE_EX(CP3DActiveXCtrl, "P3DACTIVEX.P3DActiveXCtrl.1", - 0x924b4927, 0xd3ba, 0x41ea, 0x9f, 0x7e, 0x8a, 0x89, 0x19, 0x4a, 0xb3, 0xac) - - - -// Type library ID and version - -IMPLEMENT_OLETYPELIB(CP3DActiveXCtrl, _tlid, _wVerMajor, _wVerMinor) - - - -// Interface IDs - -const IID BASED_CODE IID_DP3DActiveX = - { 0x76904D54, 0xCC5, 0x4DBB, { 0xB0, 0x22, 0xF4, 0x8B, 0x1E, 0x95, 0x18, 0x3B } }; -const IID BASED_CODE IID_DP3DActiveXEvents = - { 0x1B2413ED, 0x51C8, 0x495E, { 0xB9, 0x17, 0x98, 0x3C, 0x45, 0x9B, 0x8F, 0xC7 } }; - - - -// Control type information - -static const DWORD BASED_CODE _dwP3DActiveXOleMisc = - OLEMISC_ACTIVATEWHENVISIBLE | - OLEMISC_SETCLIENTSITEFIRST | - OLEMISC_INSIDEOUT | - OLEMISC_CANTLINKINSIDE | - OLEMISC_RECOMPOSEONRESIZE; - -IMPLEMENT_OLECTLTYPE(CP3DActiveXCtrl, IDS_P3DACTIVEX, _dwP3DActiveXOleMisc) - - - -// CP3DActiveXCtrl::CP3DActiveXCtrlFactory::UpdateRegistry - Adds or removes -// system registry entries for CP3DActiveXCtrl - -BOOL CP3DActiveXCtrl::CP3DActiveXCtrlFactory::UpdateRegistry(BOOL bRegister) -{ - // TODO: Verify that your control follows apartment-model threading rules. - // Refer to MFC TechNote 64 for more information. If your control does - // not conform to the apartment-model rules, then you must modify the code - // below, changing the 6th parameter from afxRegApartmentThreading to 0. - - if (bRegister) - return AfxOleRegisterControlClass( - AfxGetInstanceHandle(), - m_clsid, - m_lpszProgID, - IDS_P3DACTIVEX, - IDB_P3DACTIVEX, - afxRegApartmentThreading, - _dwP3DActiveXOleMisc, - _tlid, - _wVerMajor, - _wVerMinor); - else - return AfxOleUnregisterClass(m_clsid, m_lpszProgID); -} - - - -// CP3DActiveXCtrl::CP3DActiveXCtrl - Constructor - -CP3DActiveXCtrl::CP3DActiveXCtrl() : m_instance( *this ), m_pPandaObject( NULL ) -{ - InitializeIIDs(&IID_DP3DActiveX, &IID_DP3DActiveXEvents); - // TODO: Initialize your control's instance data here. - _state = S_init; - - // The init thread is initially not running. - _init_not_running.SetEvent(); -} - -// CP3DActiveXCtrl::~CP3DActiveXCtrl - Destructor - -CP3DActiveXCtrl::~CP3DActiveXCtrl() -{ - // TODO: Cleanup your control's instance data here. - if ( m_pPandaObject ) - { - m_pPandaObject->Release(); - } -} - - - -// CP3DActiveXCtrl::OnDraw - Drawing function - -void CP3DActiveXCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid) -{ - if (!pdc) - return; - - switch (_state) { - case S_init: - { - _state = S_loading; - // The first time we get the Draw message, we know we're sufficiently - // set up to start downloading the instance. - m_instance.read_tokens(); - get_twirl_bitmaps(); - - // Start the twirl timer going. - SetTimer(1, 100, timer_callback); - _init_time = GetTickCount(); - - // But do most of the setup in a child thread, so we don't lock up the - // browser GUI while the instance gets itself downloaded and such. - _init_not_running.ResetEvent(); // Now the init thread is running. - if (_beginthread(st_init, 0, this) == -1L) { - nout << "Couldn't start thread.\n"; - _init_not_running.SetEvent(); - _state = S_failed; - } - } - break; - - case S_loading: - // Waiting for the init thread to finish. - break; - - case S_ready: - // Now the instance has downloaded, so set it going. - { - _state = S_started; - KillTimer(1); - m_instance.Start( m_instance.GetP3DFilename( ) ); - } - break; - - case S_started: - // The instance is running, no need to draw anything. - KillTimer(1); - DoSuperclassPaint(pdc, rcBounds); - return; - - case S_failed: - // Something went wrong. Go ahead and draw the failed icon. - KillTimer(1); - break; - } - - // The instance is setting itself up. In the meantime, draw the - // background and the twirling icon. - - // Paint the background. - CBrush brBackGnd(RGB(m_instance._bgcolor_r, m_instance._bgcolor_g, m_instance._bgcolor_b)); - pdc->FillRect(rcBounds, &brBackGnd); - - DWORD now = GetTickCount(); - - // Don't draw the twirling icon until at least half a second has passed, - // so we don't distract people by drawing it unnecessarily. - if (_state == S_failed || (now - _init_time) >= 500) { - int step = (now / 100) % twirl_num_steps; - if (_state == S_failed) { - step = twirl_num_steps; - } - - // Create an in-memory DC compatible with the display DC we're using to - // paint - CDC dcMemory; - dcMemory.CreateCompatibleDC(pdc); - - // Select the bitmap into the in-memory DC - dcMemory.SelectObject(&_twirl_bitmaps[step]); - - // Find a centerpoint for the bitmap in the client area - CRect rect; - GetClientRect(&rect); - int nX = rect.left + (rect.Width() - twirl_width) / 2; - int nY = rect.top + (rect.Height() - twirl_height) / 2; - - // Copy the bits from the in-memory DC into the on-screen DC to actually - // do the painting. Use the centerpoint we computed for the target - // offset. - pdc->BitBlt(nX, nY, twirl_width, twirl_height, &dcMemory, - 0, 0, SRCCOPY); - } -} - -void CP3DActiveXCtrl::OnClose( DWORD dwSaveOption ) -{ - m_instance.Stop(); - - // Make sure the init thread has finished. - if (_state == S_loading) { - nout << "Waiting for thread stop\n" << flush; - ::WaitForSingleObject( _init_not_running.m_hObject, INFINITE ); - nout << "Done waiting for thread stop\n" << flush; - } - - COleControl::OnClose( dwSaveOption ); -} - - -// CP3DActiveXCtrl::DoPropExchange - Persistence support - -void CP3DActiveXCtrl::DoPropExchange(CPropExchange* pPX) -{ - ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor)); - COleControl::DoPropExchange(pPX); - - // TODO: Call PX_ functions for each persistent custom property. - - ExchangeProperties( pPX ); -} - - - -// CP3DActiveXCtrl::GetControlFlags - Flags to customize MFC's implementation -// of ActiveX controls. -DWORD CP3DActiveXCtrl::GetControlFlags() -{ - DWORD dwFlags = COleControl::GetControlFlags(); - - - // The control will not be redrawn when making the transition between the - // active and inactivate state. - dwFlags |= noFlickerActivate; - return dwFlags; -} - - - -// CP3DActiveXCtrl::OnResetState - Reset control to default state - -void CP3DActiveXCtrl::OnResetState() -{ - COleControl::OnResetState(); // Resets defaults found in DoPropExchange - - // TODO: Reset any other control state here. -} - - - -// CP3DActiveXCtrl::PreCreateWindow - Modify parameters for CreateWindowEx - -BOOL CP3DActiveXCtrl::PreCreateWindow(CREATESTRUCT& cs) -{ - cs.lpszClass = _T("STATIC"); - return COleControl::PreCreateWindow(cs); -} - - - -// CP3DActiveXCtrl::IsSubclassedControl - This is a subclassed control - -BOOL CP3DActiveXCtrl::IsSubclassedControl() -{ - return TRUE; -} - - - -// CP3DActiveXCtrl::OnOcmCommand - Handle command messages - -LRESULT CP3DActiveXCtrl::OnOcmCommand(WPARAM wParam, LPARAM lParam) -{ -#ifdef _WIN32 - WORD wNotifyCode = HIWORD(wParam); -#else - WORD wNotifyCode = HIWORD(lParam); -#endif - - // TODO: Switch on wNotifyCode here. - - return 0; -} - -// CP3DActiveXCtrl message handlers - -int CP3DActiveXCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (COleControl::OnCreate(lpCreateStruct) == -1) - return -1; - - // TODO: Add your specialized creation code here - - int error(0); - m_spClientSite = GetClientSite(); - if ( !m_spClientSite ) - { - return ( error = -1 ); - } - CComPtr pOleContainer; - HRESULT hr = m_spClientSite->GetContainer( &pOleContainer ); - if ( FAILED( hr ) || !pOleContainer ) - { - return ( error = -1 ); - } - CComPtr pHtml2Doc; - hr = pOleContainer->QueryInterface( IID_IHTMLDocument, ( void** )&pHtml2Doc ); - if ( FAILED( hr ) || !pHtml2Doc ) - { - return ( error = -1 ); - } - BSTR url; - hr = pHtml2Doc->get_URL( &url ); - if ( FAILED( hr ) || !url ) - { - return ( error = -1 ); - } - m_hostingPageUrl = url; - m_hostingPageUrl.Replace( '\\', '/' ); - - ::SysFreeString( url ); - - CComPtr pHtmlElementCollect; - hr = pHtml2Doc->get_scripts( &pHtmlElementCollect ); - if ( FAILED( hr ) || !pHtmlElementCollect ) - { - return ( error = -1 ); - } - long collectionLength = 0; - hr = pHtmlElementCollect->get_length( &collectionLength ); - if ( FAILED( hr ) || !pHtmlElementCollect ) - { - return ( error = -1 ); - } - if ( collectionLength < 1 ) - { - // javascript engine was not specified on the page. hence we need to - // initialize it by infusing javascript element tags - - CComPtr spHtmlElement; - hr = pHtml2Doc->createElement( CComBSTR( "script" ), &spHtmlElement ); - if ( SUCCEEDED( hr ) && spHtmlElement ) - { - hr = spHtmlElement->put_language( CComBSTR( "javascript" ) ); - if ( SUCCEEDED( hr ) ) - { - CComPtr spElementDomNode; - hr = spHtmlElement->QueryInterface( IID_IHTMLDOMNode, ( void** )&spElementDomNode ); - if ( SUCCEEDED( hr ) && spElementDomNode ) - { - CComPtr spHtmlDomNode; - hr = pHtml2Doc->QueryInterface( IID_IHTMLDOMNode, ( void** )&spHtmlDomNode ); - if ( SUCCEEDED( hr ) && spHtmlDomNode ) - { - CComPtr newNode; - hr = spHtmlDomNode->appendChild( spElementDomNode, &newNode ); - } - } - } - } - } - return 0; -} - -LRESULT CP3DActiveXCtrl::OnPandaNotification(WPARAM wParam, LPARAM lParam) -{ - PPInstance::HandleRequestLoop(); - - return 0; -} - -// The static init method. -void CP3DActiveXCtrl:: -st_init(void *data) { - CP3DActiveXCtrl *self = (CP3DActiveXCtrl *)data; - self->init(); - self->_init_not_running.SetEvent(); -} - -// The init method. This is called once at startup, in a child thread. -int CP3DActiveXCtrl::init( ) -{ - int error( 0 ); - std::string p3dDllFilename; - - error = m_instance.DownloadP3DComponents( p3dDllFilename ); - if ( !error && !( p3dDllFilename.empty() ) ) - { - error = m_instance.LoadPlugin( p3dDllFilename ); - if ( !error ) - { - m_pPandaObject = new PPandaObject( this, NULL ); - if (_state == S_loading) { - // Ready to start. - _state = S_ready; - return error; - } - } - } - - if (_state == S_loading) { - // Something went wrong. - _state = S_failed; - } - return error; -} - - -HRESULT CP3DActiveXCtrl::ExchangeProperties( CPropExchange* pPX ) -{ - USES_CONVERSION; - HRESULT hr = E_FAIL; - - if ( !pPX ) - { - return hr; - } - CPropbagPropExchange* pPropExchange = dynamic_cast( pPX ); - if ( !pPropExchange || !pPropExchange->m_pPropBag ) - { - return hr; - } - - // get the property bag version 2 - IPropertyBag2 * pPropBag2; - hr = pPropExchange->m_pPropBag->QueryInterface( IID_IPropertyBag2, (void**)&pPropBag2); - if (! SUCCEEDED (hr)) { - return hr; - } - - // get the number of parameters - unsigned long aNum; - hr = pPropBag2->CountProperties (& aNum); - ATLASSERT (hr >= 0); - if (! SUCCEEDED (hr)) { - return hr; - } - if (aNum == 0) return S_OK; - - // allocate the parameters names - PROPBAG2 * aPropNames = new PROPBAG2[aNum]; - unsigned long aReaded; - - // get the param names - hr = pPropBag2->GetPropertyInfo (0, aNum, aPropNames, & aReaded); - ATLASSERT (hr >= 0); - if (! SUCCEEDED (hr)) { - delete[] aPropNames; - return hr; - } - // allocate the variants and result array - CComVariant * aVal = new CComVariant[aNum]; - HRESULT * hvs = new HRESULT[aNum]; - hr = pPropBag2->Read (aNum, aPropNames, NULL, aVal, hvs); - ATLASSERT (hr >= 0); - if (! SUCCEEDED (hr)) { - delete[] hvs; - delete[] aVal; - delete[] aPropNames; - return hr; - } - - // get the params ; put them in the ParamList - for (unsigned long ind = 0; ind < aNum; ind++) { - std::pair< CString, CString> p( CString( aPropNames[ind].pstrName ), CString( aVal[ind] ) ); - m_parameters.push_back( p ); -// do_what_you_want_with (OLE2T (aPropNames[ind].pstrName), aVal[ind]); - } - // delete the unused arrays - delete[] hvs; - delete[] aVal; - delete[] aPropNames; - - return hr; -} - -P3D_object* CP3DActiveXCtrl::GetP3DObject( ) -{ - if (_state == S_started) { - return m_instance.m_p3dObject; - } - return NULL; -} - -IOleClientSite* CP3DActiveXCtrl::GetClientSte( ) -{ - return GetClientSite(); -} - -void CP3DActiveXCtrl::OnmainChanged(void) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - // TODO: Add your property handler code here - - SetModifiedFlag(); -} - -void CP3DActiveXCtrl:: -get_twirl_bitmaps() { - static const size_t twirl_size = twirl_width * twirl_height; - unsigned char twirl_data[twirl_size * 3]; - unsigned char new_data[twirl_size * 4]; - - for (int step = 0; step < twirl_num_steps + 1; ++step) { - get_twirl_data(twirl_data, twirl_size, step, - m_instance._fgcolor_r, m_instance._fgcolor_g, m_instance._fgcolor_b, - m_instance._bgcolor_r, m_instance._bgcolor_g, m_instance._bgcolor_b); - - // Expand out the RGB channels into RGBA. - for (int yi = 0; yi < twirl_height; ++yi) { - const unsigned char *sp = twirl_data + yi * twirl_width * 3; - unsigned char *dp = new_data + yi * twirl_width * 4; - for (int xi = 0; xi < twirl_width; ++xi) { - // RGB <= BGR. - dp[0] = sp[2]; - dp[1] = sp[1]; - dp[2] = sp[0]; - dp[3] = (unsigned char)0xff; - sp += 3; - dp += 4; - } - } - - // Now load the image. - _twirl_bitmaps[step].CreateBitmap(twirl_width, twirl_height, 1, 32, new_data); - } -} - -void CP3DActiveXCtrl:: -timer_callback(HWND hwnd, UINT msg, UINT_PTR id, DWORD time) { - // Just invalidate the region and make it draw again. - ::InvalidateRect(hwnd, NULL, FALSE); -} diff --git a/direct/src/plugin_activex/P3DActiveXCtrl.h b/direct/src/plugin_activex/P3DActiveXCtrl.h deleted file mode 100644 index dc1bd9df39..0000000000 --- a/direct/src/plugin_activex/P3DActiveXCtrl.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file P3DActiveXCtrl.h - * @author atrestman - * @date 2009-09-14 - */ - -#pragma once - -// P3DActiveXCtrl.h : Declaration of the CP3DActiveXCtrl ActiveX Control -// class. -#include "PPInstance.h" -#include "PPPandaObject.h" -#include "PPInterface.h" -#include "get_twirl_data.h" -#include - -#include - -// CP3DActiveXCtrl : See P3DActiveXCtrl.cpp for implementation. - -class CP3DActiveXCtrl : public COleControl, - public PPInterface -{ - DECLARE_DYNCREATE(CP3DActiveXCtrl) - -// Constructor -public: - CP3DActiveXCtrl(); - -// Overrides -public: - virtual void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid); - virtual void OnClose( DWORD dwSaveOption ); - virtual BOOL PreCreateWindow(CREATESTRUCT& cs); - virtual void DoPropExchange(CPropExchange* pPX); - virtual void OnResetState(); - virtual DWORD GetControlFlags(); - - int BeginDownload(CString& url); - - PPInstance m_instance; - -// Implementation -protected: - ~CP3DActiveXCtrl(); - - DECLARE_OLECREATE_EX(CP3DActiveXCtrl) // Class factory and guid - DECLARE_OLETYPELIB(CP3DActiveXCtrl) // GetTypeInfo - DECLARE_PROPPAGEIDS(CP3DActiveXCtrl) // Property page IDs - DECLARE_OLECTLTYPE(CP3DActiveXCtrl) // Type name and misc status - - // Subclassed control support - BOOL IsSubclassedControl(); - LRESULT OnOcmCommand(WPARAM wParam, LPARAM lParam); - -// Message maps - DECLARE_MESSAGE_MAP() - -// Dispatch maps - DECLARE_DISPATCH_MAP() - -// Event maps - DECLARE_EVENT_MAP() - -// Dispatch and event IDs -public: - enum { - dispidmain = 1 - }; - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - - static void st_init(void *data); - int init(); - virtual P3D_object* GetP3DObject( ); - virtual IOleClientSite* GetClientSte(); - - // ActiveX properties - std::vector< std::pair < CString, CString > > m_parameters; - - CString m_hostingPageUrl; - -protected: - HRESULT ExchangeProperties( CPropExchange* pPropBag ); - - LRESULT OnPandaNotification(WPARAM wParam, LPARAM lParam); - void OnmainChanged(void); - - void get_twirl_bitmaps(); - static void CALLBACK timer_callback(HWND hwnd, UINT msg, UINT_PTR id, DWORD time); - - PPandaObject* m_pPandaObject; - - CComPtr m_spClientSite; - - CBitmap _twirl_bitmaps[twirl_num_steps + 1]; - - enum State { - S_init, // before starting the download - S_loading, // the instance is downloading - // From S_loading, only the "init" thread may change the state. - - S_ready, // the instance is ready to run - S_started, // the instance has successfully started - S_failed, // something went wrong - }; - State _state; - DWORD _init_time; - CEvent _init_not_running; // set when the init thread has finished, or before it has started. -}; diff --git a/direct/src/plugin_activex/P3DActiveXPropPage.cpp b/direct/src/plugin_activex/P3DActiveXPropPage.cpp deleted file mode 100644 index 181f249838..0000000000 --- a/direct/src/plugin_activex/P3DActiveXPropPage.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file P3DActiveXPropPage.cpp - * @author atrestman - * @date 2009-09-14 - */ - -// P3DActiveXPropPage.cpp : Implementation of the CP3DActiveXPropPage property -// page class. - -#include "stdafx.h" -#include "P3DActiveX.h" -#include "P3DActiveXPropPage.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#endif - - -IMPLEMENT_DYNCREATE(CP3DActiveXPropPage, COlePropertyPage) - - - -// Message map - -BEGIN_MESSAGE_MAP(CP3DActiveXPropPage, COlePropertyPage) -END_MESSAGE_MAP() - - - -// Initialize class factory and guid - -IMPLEMENT_OLECREATE_EX(CP3DActiveXPropPage, "P3DACTIVEX.P3DActiveXPropPage.1", - 0xd0111370, 0xe705, 0x485e, 0x96, 0xfd, 0xa2, 0xef, 0xb1, 0x71, 0x26, 0x9a) - - - -// CP3DActiveXPropPage::CP3DActiveXPropPageFactory::UpdateRegistry - Adds or -// removes system registry entries for CP3DActiveXPropPage - -BOOL CP3DActiveXPropPage::CP3DActiveXPropPageFactory::UpdateRegistry(BOOL bRegister) -{ - if (bRegister) - return AfxOleRegisterPropertyPageClass(AfxGetInstanceHandle(), - m_clsid, IDS_P3DACTIVEX_PPG); - else - return AfxOleUnregisterClass(m_clsid, NULL); -} - - - -// CP3DActiveXPropPage::CP3DActiveXPropPage - Constructor - -CP3DActiveXPropPage::CP3DActiveXPropPage() : - COlePropertyPage(IDD, IDS_P3DACTIVEX_PPG_CAPTION) -{ -} - - - -// CP3DActiveXPropPage::DoDataExchange - Moves data between page and -// properties - -void CP3DActiveXPropPage::DoDataExchange(CDataExchange* pDX) -{ - DDP_PostProcessing(pDX); -} - - - -// CP3DActiveXPropPage message handlers diff --git a/direct/src/plugin_activex/P3DActiveXPropPage.h b/direct/src/plugin_activex/P3DActiveXPropPage.h deleted file mode 100644 index 56b1400a26..0000000000 --- a/direct/src/plugin_activex/P3DActiveXPropPage.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file P3DActiveXPropPage.h - * @author atrestman - * @date 2009-09-14 - */ - -#pragma once - -// P3DActiveXPropPage.h : Declaration of the CP3DActiveXPropPage property page -// class. -#include "PPPandaObject.h" - -// CP3DActiveXPropPage : See P3DActiveXPropPage.cpp for implementation. - -class CP3DActiveXPropPage : public COlePropertyPage -{ - DECLARE_DYNCREATE(CP3DActiveXPropPage) - DECLARE_OLECREATE_EX(CP3DActiveXPropPage) - -// Constructor -public: - CP3DActiveXPropPage(); - -// Dialog Data - enum { IDD = IDD_PROPPAGE_P3DACTIVEX }; - -// Implementation -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - -// Message maps -protected: - DECLARE_MESSAGE_MAP() -}; diff --git a/direct/src/plugin_activex/PPBrowserObject.cpp b/direct/src/plugin_activex/PPBrowserObject.cpp deleted file mode 100644 index 02debb6dc9..0000000000 --- a/direct/src/plugin_activex/PPBrowserObject.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPBrowserObject.cpp - * @author atrestman - * @date 2009-09-14 - */ - -#include "stdafx.h" - -#include "PPBrowserObject.h" -#include "PPInstance.h" -#include "P3DActiveXCtrl.h" - -#include - -// The following functions are C-style wrappers around the above -// PPBrowserObject methods; they are defined to allow us to create the C-style -// P3D_class_definition method table to store in the P3D_object structure. -static void object_finish(P3D_object *object) -{ - delete ((PPBrowserObject *)object); -} - -static int object_get_repr(P3D_object *object, char *buffer, int buffer_length) -{ - return ((const PPBrowserObject *)object)->get_repr(buffer, buffer_length); -} - -static P3D_object* object_get_property(P3D_object *object, const char *property) -{ - return ((const PPBrowserObject *)object)->get_property(property); -} - -static bool object_set_property(P3D_object* object, const char* property, - bool needs_response, P3D_object *value) -{ - return ((PPBrowserObject *)object)->set_property(property, needs_response, value); -} - -static P3D_object* object_call(P3D_object* object, const char* method_name, - bool needs_response, - P3D_object *params[], int num_params) -{ - if (method_name == NULL) - { - method_name = ""; - } - P3D_object *response = ((const PPBrowserObject *)object)->call(method_name, params, num_params); - if (!needs_response) - { - // No response was expected. Throw away the response we received, so - // we can be consistent with defined semantics. - P3D_OBJECT_XDECREF(response); - response = NULL; - } - return response; -} - -static P3D_object* object_eval( P3D_object *object, const char *expression ) -{ - return ( ( const PPBrowserObject* )object )->eval( expression ); -} - -P3D_class_definition* PPBrowserObject::_browser_object_class; - -PPBrowserObject::PPBrowserObject( PPInterface* interfac, IDispatch* pDispatch ) : - m_interface( interfac ), m_pDispatch( pDispatch ) -{ - _class = get_class_definition( ); - _ref_count = 1; -} - -PPBrowserObject::PPBrowserObject( const PPBrowserObject& copy ) : - m_interface( copy.m_interface ), m_pDispatch( copy.m_pDispatch ) -{ - _class = get_class_definition( ); - _ref_count = 1; -} - -PPBrowserObject::~PPBrowserObject( ) -{ - assert( _ref_count == 0 ); -} - -P3D_object* PPBrowserObject::get_property( const std::string &property ) const -{ - assert( m_interface ); - - COleVariant varResult; - CComPtr pDispatch( m_pDispatch ); - HRESULT hr = m_interface->HasProperty( pDispatch, CString( property.c_str() ) ); - if( FAILED( hr ) ) - { - return NULL; - } - - hr = m_interface->GetProperty( pDispatch, CString( property.c_str() ), varResult ); - if ( FAILED( hr ) ) - { - return NULL; - } - - return m_interface->variant_to_p3dobj( &varResult ); -} - -bool PPBrowserObject::set_property( const std::string& property, bool needs_response, - P3D_object* value ) -{ - assert( m_interface ); - - CComPtr pDispatch( m_pDispatch ); - COleVariant varValue, varResult; - m_interface->p3dobj_to_variant( &varValue, value); - - HRESULT hr = m_interface->SetProperty( pDispatch, CString( property.c_str() ), varValue, varResult ); - if ( SUCCEEDED( hr ) ) - { - return true; - } - return false; -} - -P3D_object* PPBrowserObject::call( const std::string &method_name, P3D_object* params[], int num_params ) const -{ - assert( m_interface ); - - COleVariant* varParams = new COleVariant[ num_params ]; - COleVariant varResult; - - // First, convert all of the parameters. - for ( int i = 0; i < num_params; ++i ) - { - m_interface->p3dobj_to_variant( &varParams[i], params[i] ); - } - - CComPtr pDispatch( m_pDispatch ); - HRESULT hr = m_interface->CallMethod( pDispatch, CString( method_name.c_str() ), varResult, num_params, varParams ); - - delete [] varParams; - if ( FAILED( hr ) ) - { - return NULL; } - - return m_interface->variant_to_p3dobj( &varResult ); -} - -P3D_object* PPBrowserObject::eval( const std::string &expression ) const -{ - assert( m_interface ); - - COleVariant varResult; - CComPtr pDispatch( m_pDispatch ); - - CString evalExpression( expression.c_str() ); - HRESULT hr = m_interface->EvalExpression( pDispatch, evalExpression , varResult ); - if ( FAILED( hr ) ) - { - return NULL; - } - - return m_interface->variant_to_p3dobj( &varResult ); -} - -int PPBrowserObject::get_repr( char* buffer, int buffer_length ) const -{ - assert( m_interface ); - - VARIANT var; - var.vt = VT_DISPATCH; - var.pdispVal = m_pDispatch; - - COleVariant varDispatch( var ); - - CString result( m_interface->get_repr( varDispatch ) ); - strncpy( buffer, result, buffer_length ); - return (int)result.GetLength(); -} - -void PPBrowserObject::clear_class_definition() -{ - _browser_object_class = NULL; -} - -P3D_class_definition* PPBrowserObject::get_class_definition() -{ - if ( _browser_object_class == NULL ) - { - // Create a default class_definition object, and fill in the - // appropriate pointers. - _browser_object_class = P3D_make_class_definition_ptr(); - _browser_object_class->_finish = &object_finish; - - _browser_object_class->_get_repr = &object_get_repr; - _browser_object_class->_get_property = &object_get_property; - _browser_object_class->_set_property = &object_set_property; - _browser_object_class->_call = &object_call; - _browser_object_class->_eval = &object_eval; - } - return _browser_object_class; -} diff --git a/direct/src/plugin_activex/PPBrowserObject.h b/direct/src/plugin_activex/PPBrowserObject.h deleted file mode 100644 index ac4d6426c7..0000000000 --- a/direct/src/plugin_activex/PPBrowserObject.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPBrowserObject.h - * @author atrestman - * @date 2009-09-14 - */ - -#pragma once - -#include "p3d_plugin.h" -#include - -class PPInterface; - -class PPBrowserObject : public P3D_object -{ -public: - PPBrowserObject( PPInterface* interfac, IDispatch* pDisp ); - PPBrowserObject( const PPBrowserObject& copy ); - ~PPBrowserObject( ); - - int get_repr( char* buffer, int buffer_length ) const; - P3D_object* get_property( const std::string &property ) const; - bool set_property( const std::string& property, bool needs_response, - P3D_object* value ); - - P3D_object* call( const std::string &method_name, - P3D_object* params[], int num_params ) const; - P3D_object* eval( const std::string &expression ) const; - - static void clear_class_definition(); - -protected: - PPBrowserObject( ); - static P3D_class_definition* get_class_definition( ); - - PPInterface* m_interface; - static P3D_class_definition* _browser_object_class; - - CComPtr m_pDispatch; -}; diff --git a/direct/src/plugin_activex/PPDownloadCallback.cpp b/direct/src/plugin_activex/PPDownloadCallback.cpp deleted file mode 100644 index d7739e2039..0000000000 --- a/direct/src/plugin_activex/PPDownloadCallback.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPDownloadCallback.cpp - * @author atrestman - * @date 2009-09-14 - */ - -#include "stdafx.h" -#include "PPDownloadCallback.h" -#include "PPInstance.h" - - -PPDownloadCallback::PPDownloadCallback( PPDownloadCallbackSync& downloadSync ) - : m_downloadSync( downloadSync ), m_dwTotalRead( 0 ), - m_dwTotalInStream( 0 ), m_ulObjRefCount( 1 ) -{ -} - -PPDownloadCallback::~PPDownloadCallback() -{ - m_spStream.Release(); -} - -STDMETHODIMP PPDownloadCallback::QueryInterface(REFIID riid, void **ppvObject) -{ - TRACE(_T("IUnknown::QueryInterface\n")); - - *ppvObject = NULL; - - // IUnknown - if (::IsEqualIID(riid, __uuidof(IUnknown))) - { - TRACE(_T("IUnknown::QueryInterface(IUnknown)\n")); - - *ppvObject = this; - } - // IBindStatusCallback - else if (::IsEqualIID(riid, __uuidof(IBindStatusCallback))) - { - TRACE(_T("IUnknown::QueryInterface(IBindStatusCallback)\n")); - - *ppvObject = static_cast(this); - } - - if (*ppvObject) - { - (*reinterpret_cast(ppvObject))->AddRef(); - - return S_OK; - } - - return E_NOINTERFACE; -} - -STDMETHODIMP_(ULONG) PPDownloadCallback::AddRef() -{ - TRACE(_T("IUnknown::AddRef\n")); - - return ++m_ulObjRefCount; -} - -STDMETHODIMP_(ULONG) PPDownloadCallback::Release() -{ - TRACE(_T("IUnknown::Release\n")); - - return --m_ulObjRefCount; -} - -STDMETHODIMP PPDownloadCallback::OnStartBinding(DWORD, IBinding *) -{ - TRACE(_T("IBindStatusCallback::OnStartBinding\n")); - - m_downloadSync.Begin(); - - return S_OK; -} - -STDMETHODIMP PPDownloadCallback::GetPriority(LONG *) -{ - TRACE(_T("IBindStatusCallback::GetPriority\n")); - - return E_NOTIMPL; -} - -STDMETHODIMP PPDownloadCallback::OnLowResource(DWORD) -{ - TRACE(_T("IBindStatusCallback::OnLowResource\n")); - - return S_OK; -} - -STDMETHODIMP PPDownloadCallback::OnProgress(ULONG ulProgress, - ULONG ulProgressMax, - ULONG ulStatusCode, - LPCWSTR szStatusText) -{ -#ifdef _DEBUG - static const LPCTSTR plpszStatus[] = - { - _T("BINDSTATUS_FINDINGRESOURCE"), // 1 - _T("BINDSTATUS_CONNECTING"), - _T("BINDSTATUS_REDIRECTING"), - _T("BINDSTATUS_BEGINDOWNLOADDATA"), - _T("BINDSTATUS_DOWNLOADINGDATA"), - _T("BINDSTATUS_ENDDOWNLOADDATA"), - _T("BINDSTATUS_BEGINDOWNLOADCOMPONENTS"), - _T("BINDSTATUS_INSTALLINGCOMPONENTS"), - _T("BINDSTATUS_ENDDOWNLOADCOMPONENTS"), - _T("BINDSTATUS_USINGCACHEDCOPY"), - _T("BINDSTATUS_SENDINGREQUEST"), - _T("BINDSTATUS_CLASSIDAVAILABLE"), - _T("BINDSTATUS_MIMETYPEAVAILABLE"), - _T("BINDSTATUS_CACHEFILENAMEAVAILABLE"), - _T("BINDSTATUS_BEGINSYNCOPERATION"), - _T("BINDSTATUS_ENDSYNCOPERATION"), - _T("BINDSTATUS_BEGINUPLOADDATA"), - _T("BINDSTATUS_UPLOADINGDATA"), - _T("BINDSTATUS_ENDUPLOADINGDATA"), - _T("BINDSTATUS_PROTOCOLCLASSID"), - _T("BINDSTATUS_ENCODING"), - _T("BINDSTATUS_VERFIEDMIMETYPEAVAILABLE"), - _T("BINDSTATUS_CLASSINSTALLLOCATION"), - _T("BINDSTATUS_DECODING"), - _T("BINDSTATUS_LOADINGMIMEHANDLER"), - _T("BINDSTATUS_CONTENTDISPOSITIONATTACH"), - _T("BINDSTATUS_FILTERREPORTMIMETYPE"), - _T("BINDSTATUS_CLSIDCANINSTANTIATE"), - _T("BINDSTATUS_IUNKNOWNAVAILABLE"), - _T("BINDSTATUS_DIRECTBIND"), - _T("BINDSTATUS_RAWMIMETYPE"), - _T("BINDSTATUS_PROXYDETECTING"), - _T("BINDSTATUS_ACCEPTRANGES"), - _T("???") // unknown - }; -#endif - - TRACE(_T("IBindStatusCallback::OnProgress\n")); - - TRACE(_T("ulProgress: %lu, ulProgressMax: %lu\n"), - ulProgress, ulProgressMax); - - TRACE(_T("ulStatusCode: %lu "), ulStatusCode); - - if (ulStatusCode < UF_BINDSTATUS_FIRST || - ulStatusCode > UF_BINDSTATUS_LAST) - { - ulStatusCode = UF_BINDSTATUS_LAST + 1; - } - - m_dwTotalInStream = ulProgressMax; - m_downloadSync.ProgressNotify( ulProgress, ulProgressMax ); - -#ifdef _DEBUG - TRACE(_T("(%s), szStatusText: %ls\n"), - plpszStatus[ulStatusCode - UF_BINDSTATUS_FIRST], - szStatusText); -#endif - - return S_OK; -} - -STDMETHODIMP PPDownloadCallback::OnStopBinding(HRESULT, LPCWSTR) -{ - TRACE(_T("IBindStatusCallback::OnStopBinding\n")); - - m_downloadSync.End( ); - - return S_OK; -} - -STDMETHODIMP PPDownloadCallback::GetBindInfo(DWORD *, BINDINFO *) -{ - TRACE(_T("IBindStatusCallback::GetBindInfo\n")); - - return S_OK; -} - -STDMETHODIMP PPDownloadCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, - FORMATETC *, STGMEDIUM *pstgmed) -{ - TRACE(_T("IBindStatusCallback::OnDataAvailable\n")); - - HRESULT hr = S_OK; - - // Get the Stream passed - if (BSCF_FIRSTDATANOTIFICATION & grfBSCF) - { - if (!m_spStream && pstgmed->tymed == TYMED_ISTREAM) - { - m_spStream = pstgmed->pstm; - } - } - - DWORD dwRead = dwSize - m_dwTotalRead; // Minimum amount available that hasn't been read - DWORD dwActuallyRead = 0; // Placeholder for amount read during this pull - - // If there is some data to be read then go ahead and read them - if (m_spStream) - { - if (dwRead > 0) - { - BYTE* pBytes = NULL; - ATLTRY(pBytes = new BYTE[dwRead + 1]); - if (pBytes == NULL) - return E_OUTOFMEMORY; - hr = m_spStream->Read(pBytes, dwRead, &dwActuallyRead); - if (SUCCEEDED(hr)) - { - pBytes[dwActuallyRead] = 0; - if (dwActuallyRead>0) - { - bool ret = m_downloadSync.DataNotify( m_dwTotalInStream, (const void*)pBytes, dwActuallyRead ); - if (!ret) - { - hr = E_ABORT; - } - - m_dwTotalRead += dwActuallyRead; - } - } - delete[] pBytes; - } - } - - if (BSCF_LASTDATANOTIFICATION & grfBSCF || E_ABORT == hr ) - { - m_spStream.Release(); - } - return hr; -} - -STDMETHODIMP PPDownloadCallback::OnObjectAvailable(REFIID, IUnknown *) -{ - TRACE(_T("IBindStatusCallback::OnObjectAvailable\n")); - - return S_OK; -} diff --git a/direct/src/plugin_activex/PPDownloadCallback.h b/direct/src/plugin_activex/PPDownloadCallback.h deleted file mode 100644 index 0ea6d3de4b..0000000000 --- a/direct/src/plugin_activex/PPDownloadCallback.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPDownloadCallback.h - * @author atrestman - * @date 2009-09-14 - */ - -#pragma once - -#include - -enum -{ - UF_BINDSTATUS_FIRST = BINDSTATUS_FINDINGRESOURCE, - UF_BINDSTATUS_LAST = BINDSTATUS_ACCEPTRANGES -}; - -class PPDownloadCallbackSync -{ -public: - virtual bool Begin( ) = 0; - virtual bool DataNotify( size_t expectedDataSize, const void* data, size_t dataSize ) = 0; - virtual void ProgressNotify( size_t progress, size_t maxProgress ) = 0; - virtual bool End( ) = 0; -}; - -class PPDownloadCallback : public IBindStatusCallback -{ -public: - PPDownloadCallback( PPDownloadCallbackSync& downloadSync ); - virtual ~PPDownloadCallback(); - - // IUnknown methods - STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject); - STDMETHOD_(ULONG, AddRef)(); - STDMETHOD_(ULONG, Release)(); - - // IBindStatusCallback methods - STDMETHOD(OnStartBinding)(DWORD, IBinding *); - STDMETHOD(GetPriority)(LONG *); - STDMETHOD(OnLowResource)(DWORD); - STDMETHOD(OnProgress)(ULONG ulProgress, - ULONG ulProgressMax, - ULONG ulStatusCode, - LPCWSTR szStatusText); - STDMETHOD(OnStopBinding)(HRESULT, LPCWSTR); - STDMETHOD(GetBindInfo)(DWORD *, BINDINFO *); - STDMETHOD(OnDataAvailable)(DWORD, DWORD, FORMATETC *, STGMEDIUM *); - STDMETHOD(OnObjectAvailable)(REFIID, IUnknown *); - -protected: - ULONG m_ulObjRefCount; - CComPtr m_spStream; - -private: - PPDownloadCallbackSync& m_downloadSync; - - DWORD m_dwTotalRead; - DWORD m_dwTotalInStream; - -}; diff --git a/direct/src/plugin_activex/PPDownloadRequest.cpp b/direct/src/plugin_activex/PPDownloadRequest.cpp deleted file mode 100644 index 5a25bfd2cc..0000000000 --- a/direct/src/plugin_activex/PPDownloadRequest.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPDownloadRequest.cpp - * @author atrestman - * @date 2009-09-14 - */ - -#include "stdafx.h" - -#include "PPDownloadRequest.h" -#include "PPInstance.h" -#include "wstring_encode.h" - -bool PPDownloadRequest::Begin( ) -{ - m_instance.m_eventStop.ResetEvent( ); - m_instance.m_eventDownloadStopped.ResetEvent( ); - return true; -} - -bool PPDownloadRequest::DataNotify( size_t expectedDataSize, const void* data, size_t dataSize ) -{ - bool ret = false; - if ( m_instance.m_eventStop.m_hObject != NULL ) - { - if ( ::WaitForSingleObject( m_instance.m_eventStop.m_hObject, 0 ) == WAIT_OBJECT_0 ) - { - return ret; // canceled by the user - } - } - switch ( this->m_requestType ) - { - case ( RequestType::P3DObject ): - { - if ( m_p3dRequest ) - { - ret = P3D_instance_feed_url_stream_ptr( m_p3dRequest->_instance, - m_p3dRequest->_request._get_url._unique_id, - P3D_RC_in_progress, - 0, - expectedDataSize, - data, - dataSize ); - } - } - break; - case ( RequestType::File ): - { - if ( m_hFile == INVALID_HANDLE_VALUE ) - { - wstring filename_w; - string_to_wstring(filename_w, m_fileName); - m_hFile = ::CreateFileW( filename_w.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); - if ( m_hFile == INVALID_HANDLE_VALUE ) - { - return ret; - } - } - DWORD numberOfBytesWritten = 0; - if ( ::WriteFile( m_hFile, data, dataSize, &numberOfBytesWritten, NULL ) == TRUE ) - { - ret = true; - } - } - break; - case ( RequestType::Data ): - { - if ( m_data ) - { - std::string bits( static_cast< const char* >( data ), dataSize ); - *m_data << bits; - ret = true; - } - } - break; - } - return ret; -} - -void PPDownloadRequest::ProgressNotify( size_t progress, size_t maxProgress ) -{ - if ( ::IsWindow( m_instance.m_parentWnd ) ) - { - SendMessage( m_instance.m_parentWnd, WM_PROGRESS, (WPARAM)(progress * 100.0 / maxProgress), 0 ); - } -} - -bool PPDownloadRequest::End( ) -{ - if ( m_hFile != INVALID_HANDLE_VALUE ) - { - ::CloseHandle( m_hFile ); - m_hFile = INVALID_HANDLE_VALUE; - } - m_instance.m_eventDownloadStopped.SetEvent( ); - return true; -} diff --git a/direct/src/plugin_activex/PPDownloadRequest.h b/direct/src/plugin_activex/PPDownloadRequest.h deleted file mode 100644 index 26d5081fc7..0000000000 --- a/direct/src/plugin_activex/PPDownloadRequest.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPDownloadRequest.h - * @author atrestman - * @date 2009-09-14 - */ - -#pragma once - -#include -#include - -#include "PPDownloadCallback.h" -#include "PPInstance.h" - -class PPDownloadRequest : public PPDownloadCallbackSync -{ -public: - enum RequestType - { - File, - Data, - P3DObject - }; - - PPDownloadRequest( PPInstance& instance, P3D_request* p3dRequest ) : - m_instance( instance ), m_p3dRequest( p3dRequest ), m_data( nullptr ), - m_requestType( RequestType::P3DObject ), m_hFile( INVALID_HANDLE_VALUE ) - { - } - - PPDownloadRequest( PPInstance& instance, const std::string& fileName ) : - m_instance( instance ), m_p3dRequest( nullptr ), m_fileName( fileName ), - m_data( nullptr ), m_requestType( RequestType::File ), m_hFile( INVALID_HANDLE_VALUE ) - { - } - - PPDownloadRequest( PPInstance& instance, std::strstream* data ) : - m_instance( instance ), m_p3dRequest ( nullptr ), m_data( data ), - m_requestType( RequestType::Data ), m_hFile( INVALID_HANDLE_VALUE ) - { - } - - virtual ~PPDownloadRequest( ) - { - End(); - } - - // PPDownloadCallbackSync interface - virtual bool Begin( ); - virtual bool DataNotify( size_t expectedDataSize, const void* data, size_t size ); - virtual void ProgressNotify( size_t progress, size_t maxProgress ); - virtual bool End( ); - - PPInstance& m_instance; - RequestType m_requestType; - -protected: - P3D_request* m_p3dRequest; - std::string m_fileName; - std::strstream* m_data; - - HANDLE m_hFile; - -private: - PPDownloadRequest(); -}; diff --git a/direct/src/plugin_activex/PPInstance.cpp b/direct/src/plugin_activex/PPInstance.cpp deleted file mode 100644 index 1c1c6fc071..0000000000 --- a/direct/src/plugin_activex/PPInstance.cpp +++ /dev/null @@ -1,995 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPInstance.cpp - * @author atrestman - * @date 2009-09-14 - */ - -#include "stdafx.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "resource.h" -#include "PPInstance.h" -#include "P3DActiveXCtrl.h" -#include "PPBrowserObject.h" -#include "PPDownloadRequest.h" - -#include "p3d_plugin_config.h" -#include "get_tinyxml.h" -#include "load_plugin.h" -#include "find_root_dir.h" -#include "mkdir_complete.h" -#include "parse_color.h" -#include "wstring_encode.h" - -// We can include this header file to get the DTOOL_PLATFORM definition, even -// though we don't link with dtool. -#include "dtool_platform.h" -#include "pandaVersion.h" - -#define P3D_CONTENTS_FILENAME "contents.xml" -#define P3D_DEFAULT_PLUGIN_FILENAME "p3d_plugin.dll" - -static int s_instanceCount = 0; -void P3D_NotificationSync(P3D_instance *instance) -{ - static bool handleRequestOnUIThread = true; - if ( instance ) - { - CP3DActiveXCtrl* parent = static_cast(instance->_user_data); - if ( parent ) - { - if ( ::IsWindow( parent->m_hWnd ) ) - { - ::PostMessage( parent->m_hWnd, WM_PANDA_NOTIFICATION, 0, 0 ); - } - else - { - nout << "Can handle P3D_Notification on UI thread. Controls window is invalid\n"; - } - } - else - { - nout << "Can handle P3D_Notification on UI thread. Instance's user data is not a Control\n"; - } - } -} - -PPInstance::PPInstance( CP3DActiveXCtrl& parentCtrl ) : - m_parentCtrl( parentCtrl ), m_p3dInstance( NULL ), m_p3dObject( NULL ), m_isInit( false ) -{ - // We need the root dir first. - m_rootDir = find_root_dir( ); - string_to_wstring(m_rootDir_w, m_rootDir); - - // Then open the logfile. - m_logger.Open( m_rootDir ); - - m_pluginLoaded = false; - _contents_expiration = 0; - _failed = false; - - _tokens = NULL; - _num_tokens = 0; - - // Ensure this event is initially in the "set" state, in case we never get a - // download request before we get a close request. - m_eventDownloadStopped.SetEvent( ); - m_eventStop.ResetEvent(); - - nout << "Plugin is built with " << PANDA_PACKAGE_HOST_URL << "\n"; -} - -PPInstance::~PPInstance() { - assert(_tokens == NULL); -} - -// This is called at setup time to read the set of web tokens from the ActiveX -// control. -void PPInstance:: -read_tokens() { - assert(_tokens == NULL); - _num_tokens = (int)m_parentCtrl.m_parameters.size(); - _tokens = new P3D_token[ _num_tokens ]; - for (int i = 0; i < _num_tokens; i++ ) { - std::pair< CString, CString > keyAndValue = m_parentCtrl.m_parameters[ i ]; - // Make the token lowercase, since HTML is case-insensitive but we're - // not. - string keyword; - for (const char *p = m_parentCtrl.m_parameters[ i ].first; *p; ++p) { - keyword += tolower(*p); - } - - _tokens[i]._keyword = strdup( keyword.c_str() ); - _tokens[i]._value = strdup( m_parentCtrl.m_parameters[ i ].second ); - } - - // fgcolor and bgcolor are useful to know here (in case we have to draw a - // twirling icon). - - // The default bgcolor is white. - _bgcolor_r = _bgcolor_g = _bgcolor_b = 0xff; - if (has_token("bgcolor")) { - int r, g, b; - if (parse_color(r, g, b, lookup_token("bgcolor"))) { - _bgcolor_r = r; - _bgcolor_g = g; - _bgcolor_b = b; - } - } - - // The default fgcolor is either black or white, according to the - // brightness of the bgcolor. - if (_bgcolor_r + _bgcolor_g + _bgcolor_b > 0x80 + 0x80 + 0x80) { - _fgcolor_r = _fgcolor_g = _fgcolor_b = 0x00; - } else { - _fgcolor_r = _fgcolor_g = _fgcolor_b = 0xff; - } - if (has_token("fgcolor")) { - int r, g, b; - if (parse_color(r, g, b, lookup_token("fgcolor"))) { - _fgcolor_r = r; - _fgcolor_g = g; - _fgcolor_b = b; - } - } -} - -int PPInstance::DownloadFile( const std::string& from, const std::string& to ) -{ - int error( 0 ); - HRESULT hr( S_OK ); - - nout << "Downloading " << from << " into " << to << "\n"; - { - PPDownloadRequest p3dFileDownloadRequest( *this, to ); - PPDownloadCallback dcForFile( p3dFileDownloadRequest ); - hr = ::URLOpenStream( m_parentCtrl.GetControllingUnknown(), from.c_str(), 0, &dcForFile ); - } - if ( FAILED( hr ) ) - { - error = 1; - nout << "Error downloading " << from << " :" << hr << "\n"; - } - return error; -} - -int PPInstance::CopyFile( const std::string& from, const std::string& to ) -{ - ifstream in(from.c_str(), ios::in | ios::binary); - ofstream out(to.c_str(), ios::out | ios::binary); - - static const size_t buffer_size = 4096; - char buffer[buffer_size]; - - in.read(buffer, buffer_size); - size_t count = in.gcount(); - while (count != 0) { - out.write(buffer, count); - if (out.fail()) { - return 1; - } - in.read(buffer, buffer_size); - count = in.gcount(); - } - - if (!in.eof()) { - return 1; - } - - return 0; -} - -/** - * Attempts to open and read the contents.xml file on disk. Copies the file - * to its standard location on success. Returns true on success, false on - * failure. - */ -bool PPInstance:: -read_contents_file(const string &contents_filename, bool fresh_download) { - TiXmlDocument doc(contents_filename.c_str()); - if (!doc.LoadFile()) { - return false; - } - - bool found_core_package = false; - - TiXmlElement *xcontents = doc.FirstChildElement("contents"); - if (xcontents != NULL) { - int max_age = P3D_CONTENTS_DEFAULT_MAX_AGE; - xcontents->Attribute("max_age", &max_age); - - // Get the latest possible expiration time, based on the max_age - // indication. Any expiration time later than this is in error. - time_t now = time(NULL); - _contents_expiration = now + (time_t)max_age; - - if (fresh_download) { - // Update the XML with the new download information. - TiXmlElement *xorig = xcontents->FirstChildElement("orig"); - while (xorig != NULL) { - xcontents->RemoveChild(xorig); - xorig = xcontents->FirstChildElement("orig"); - } - - xorig = new TiXmlElement("orig"); - xcontents->LinkEndChild(xorig); - - xorig->SetAttribute("expiration", (int)_contents_expiration); - - } else { - // Read the expiration time from the XML. - int expiration = 0; - TiXmlElement *xorig = xcontents->FirstChildElement("orig"); - if (xorig != NULL) { - xorig->Attribute("expiration", &expiration); - } - - _contents_expiration = min(_contents_expiration, (time_t)expiration); - } - - nout << "read contents.xml, max_age = " << max_age - << ", expires in " << max(_contents_expiration, now) - now - << " s\n"; - - // Look for the entry; it might point us at a different download - // URL, and it might mention some mirrors. - find_host(xcontents); - - // Now look for the core API package. - _coreapi_set_ver = ""; - TiXmlElement *xpackage = xcontents->FirstChildElement("package"); - while (xpackage != NULL) { - const char *name = xpackage->Attribute("name"); - if (name != NULL && strcmp(name, "coreapi") == 0) { - const char *platform = xpackage->Attribute("platform"); - if (platform != NULL && strcmp(platform, DTOOL_PLATFORM) == 0) { - _coreapi_dll.load_xml(xpackage); - const char *set_ver = xpackage->Attribute("set_ver"); - if (set_ver != NULL) { - _coreapi_set_ver = set_ver; - } - found_core_package = true; - break; - } - } - - xpackage = xpackage->NextSiblingElement("package"); - } - } - - if (!found_core_package) { - // Couldn't find the coreapi package description. - nout << "No coreapi package defined in contents file for " - << DTOOL_PLATFORM << "\n"; - return false; - } - - // Check the coreapi_set_ver token. If it is given, it specifies a minimum - // Core API version number we expect to find. If we didn't find that - // number, perhaps our contents.xml is out of date. - string coreapi_set_ver = lookup_token("coreapi_set_ver"); - if (!coreapi_set_ver.empty()) { - nout << "Instance asked for Core API set_ver " << coreapi_set_ver - << ", we found " << _coreapi_set_ver << "\n"; - // But don't bother if we just freshly downloaded it. - if (!fresh_download) { - if (compare_seq(coreapi_set_ver, _coreapi_set_ver) > 0) { - // The requested set_ver value is higher than the one we have on file; - // our contents.xml file must be out of date after all. - nout << "expiring contents.xml\n"; - _contents_expiration = 0; - } - } - } - - // Success. Now save the file in its proper place. - string standard_filename = m_rootDir + "/contents.xml"; - - mkfile_complete(standard_filename, nout); - if (!doc.SaveFile(standard_filename.c_str())) { - nout << "Couldn't rewrite " << standard_filename << "\n"; - return false; - } - - return true; -} - -/** - * Scans the element for the matching element. - */ -void PPInstance:: -find_host(TiXmlElement *xcontents) { - string host_url = PANDA_PACKAGE_HOST_URL; - TiXmlElement *xhost = xcontents->FirstChildElement("host"); - if (xhost != NULL) { - const char *url = xhost->Attribute("url"); - if (url != NULL && host_url == string(url)) { - // We're the primary host. This is the normal case. - read_xhost(xhost); - return; - - } else { - // We're not the primary host; perhaps we're an alternate host. - TiXmlElement *xalthost = xhost->FirstChildElement("alt_host"); - while (xalthost != NULL) { - const char *url = xalthost->Attribute("url"); - if (url != NULL && host_url == string(url)) { - // Yep, we're this alternate host. - read_xhost(xhost); - return; - } - xalthost = xalthost->NextSiblingElement("alt_host"); - } - } - - // Hmm, didn't find the URL we used mentioned. Assume we're the primary - // host. - read_xhost(xhost); - } -} - -/** - * Reads the host data from the (or ) entry in the - * contents.xml file. - */ -void PPInstance:: -read_xhost(TiXmlElement *xhost) { - // Get the "download" URL, which is the source from which we download - // everything other than the contents.xml file. - const char *download_url = xhost->Attribute("download_url"); - if (download_url != NULL) { - _download_url_prefix = download_url; - } else { - _download_url_prefix = PANDA_PACKAGE_HOST_URL; - } - if (!_download_url_prefix.empty()) { - if (_download_url_prefix[_download_url_prefix.size() - 1] != '/') { - _download_url_prefix += "/"; - } - } - - TiXmlElement *xmirror = xhost->FirstChildElement("mirror"); - while (xmirror != NULL) { - const char *url = xmirror->Attribute("url"); - if (url != NULL) { - add_mirror(url); - } - xmirror = xmirror->NextSiblingElement("mirror"); - } -} - -/** - * Adds a new URL to serve as a mirror for this host. The mirrors will be - * consulted first, before consulting the host directly. - */ -void PPInstance:: -add_mirror(std::string mirror_url) { - // Ensure the URL ends in a slash. - if (!mirror_url.empty() && mirror_url[mirror_url.size() - 1] != '/') { - mirror_url += '/'; - } - - // Add it to the _mirrors list, but only if it's not already there. - if (std::find(_mirrors.begin(), _mirrors.end(), mirror_url) == _mirrors.end()) { - _mirrors.push_back(mirror_url); - } -} - -/** - * Selects num_mirrors elements, chosen at random, from the _mirrors list. - * Adds the selected mirrors to result. If there are fewer than num_mirrors - * elements in the list, adds only as many mirrors as we can get. - */ -void PPInstance:: -choose_random_mirrors(std::vector &result, int num_mirrors) { - std::vector selected; - - size_t num_to_select = min(_mirrors.size(), (size_t)num_mirrors); - while (num_to_select > 0) { - size_t i = (size_t)(((double)rand() / (double)RAND_MAX) * _mirrors.size()); - while (std::find(selected.begin(), selected.end(), i) != selected.end()) { - // Already found this i, find a new one. - i = (size_t)(((double)rand() / (double)RAND_MAX) * _mirrors.size()); - } - selected.push_back(i); - result.push_back(_mirrors[i]); - --num_to_select; - } -} - -int PPInstance::DownloadP3DComponents( std::string& p3dDllFilename ) -{ - int error(0); - - // Get the pathname of the local copy of the contents.xml file. - std::string finalContentsFileName( m_rootDir ); - finalContentsFileName += "/"; - finalContentsFileName += P3D_CONTENTS_FILENAME; - - // Check to see if the version on disk is already current enough. - bool already_got = false; - if (read_contents_file(finalContentsFileName, false)) { - if (time(NULL) < _contents_expiration) { - // Got the file, and it's good. - already_got = true; - } - } - - if (!already_got) { - // OK, we need to download a new contents.xml file. Start off by - // downloading it into a local temporary file. - WCHAR local_filename_w[ MAX_PATH ]; - if (!::GetTempFileNameW( m_rootDir_w.c_str(), L"p3d", 0, local_filename_w )) { - nout << "GetTempFileName failed (folder is " << m_rootDir << ")\n"; - return 1; - } - - std::string local_filename; - wstring_to_string(local_filename, local_filename_w); - - std::string hostUrl( PANDA_PACKAGE_HOST_URL ); - if (!hostUrl.empty() && hostUrl[hostUrl.size() - 1] != '/') { - hostUrl += '/'; - } - - // Append a query string to the contents.xml URL to uniquify it and - // ensure we don't get a cached version. - std::ostringstream strm; - strm << hostUrl << P3D_CONTENTS_FILENAME << "?" << time(NULL); - std::string remoteContentsUrl( strm.str() ); - - error = DownloadFile( remoteContentsUrl, local_filename ); - if ( !error ) { - if ( !read_contents_file( local_filename, true ) ) - error = 1; - } - - if ( error ) { - // If we couldn't download or read the contents.xml file, check to see - // if there's a good one on disk already, as a fallback. - if ( !read_contents_file( finalContentsFileName, false ) ) - error = 1; - } - - // We don't need the temporary file any more. - ::DeleteFileW( local_filename_w ); - } - - if (!error) { - // OK, at this point we have successfully read contents.xml, and we have - // a good file spec in _coreapi_dll. - if (_coreapi_dll.quick_verify(m_rootDir)) { - // The DLL is already on-disk, and is good. - p3dDllFilename = _coreapi_dll.get_pathname(m_rootDir); - } else { - // The DLL is not already on-disk, or it's stale. Go get it. - std::string p3dLocalModuleFileName(_coreapi_dll.get_pathname(m_rootDir)); - mkfile_complete(p3dLocalModuleFileName, nout); - - // Try one of the mirrors first. - std::vector mirrors; - choose_random_mirrors(mirrors, 2); - - error = 1; - for (std::vector::iterator si = mirrors.begin(); - si != mirrors.end() && error; - ++si) { - std::string url = (*si) + _coreapi_dll.get_filename(); - error = DownloadFile(url, p3dLocalModuleFileName); - if (!error && !_coreapi_dll.full_verify(m_rootDir)) { - // If it's not right after downloading, it's an error. - error = 1; - } - } - - // If that failed, go get it from the authoritative host. - if (error) { - std::string url = _download_url_prefix + _coreapi_dll.get_filename(); - error = DownloadFile(url, p3dLocalModuleFileName); - if (!error && !_coreapi_dll.full_verify(m_rootDir)) { - error = 1; - } - } - - // If *that* failed, go get it again from the same URL, this time with - // a query prefix to bust through any caches. - if (error) { - std::ostringstream strm; - strm << _download_url_prefix << _coreapi_dll.get_filename(); - strm << "?" << time(NULL); - - std::string url = strm.str(); - error = DownloadFile(url, p3dLocalModuleFileName); - if (!error && !_coreapi_dll.full_verify(m_rootDir)) { - nout << "After download, " << _coreapi_dll.get_filename() - << " is no good.\n"; - error = 1; - } - } - - if (!error) { - // Downloaded successfully. - p3dDllFilename = _coreapi_dll.get_pathname(m_rootDir); - } - } - } - - if (error) { - set_failed(); - } - return error; -} - -int PPInstance::LoadPlugin( const std::string& dllFilename ) -{ - CSingleLock lock(&_load_mutex); - lock.Lock(); - if ( !m_pluginLoaded ) - { - ref_plugin(); - m_pluginLoaded = true; - } - - int error = 0; - if (!is_plugin_loaded()) { - - std::string pathname = dllFilename; -#ifdef P3D_PLUGIN_P3D_PLUGIN - // This is a convenience macro for development. If defined and - // nonempty, it indicates the name of the plugin DLL that we will - // actually run, even after downloading a possibly different (presumably - // older) version. Its purpose is to simplify iteration on the plugin - // DLL. - string override_filename = P3D_PLUGIN_P3D_PLUGIN; - if (!override_filename.empty()) { - pathname = override_filename; - } -#endif // P3D_PLUGIN_P3D_PLUGIN - - nout << "Attempting to load core API from " << pathname << "\n"; - string contents_filename = m_rootDir + "/contents.xml"; - if (!load_plugin(pathname, contents_filename, PANDA_PACKAGE_HOST_URL, - P3D_VC_normal, "", "", "", false, false, - m_rootDir, "", "", nout)) { - nout << "Unable to launch core API in " << pathname << "\n"; - error = 1; - } else { - - // Format the coreapi_timestamp as a string, for passing as a - // parameter. - ostringstream stream; - stream << _coreapi_dll.get_timestamp(); - string coreapi_timestamp = stream.str(); - -#ifdef PANDA_OFFICIAL_VERSION - static const bool official = true; -#else - static const bool official = false; -#endif - P3D_set_plugin_version_ptr(P3D_PLUGIN_MAJOR_VERSION, P3D_PLUGIN_MINOR_VERSION, - P3D_PLUGIN_SEQUENCE_VERSION, official, - PANDA_DISTRIBUTOR, - PANDA_PACKAGE_HOST_URL, coreapi_timestamp.c_str(), - _coreapi_set_ver.c_str()); - - } - } - - if (error) { - set_failed(); - } - return error ; -} - -int PPInstance::UnloadPlugin() -{ - CSingleLock lock(&_load_mutex); - lock.Lock(); - - int error( 0 ); - - if ( m_pluginLoaded ) - { - m_pluginLoaded = false; - m_isInit = false; - unref_plugin(); - } - return error; -} - -// Increments the reference count on the "plugin" library (i.e. the core -// API). Call unref_plugin() later to decrement this count. -void PPInstance:: -ref_plugin() { - s_instanceCount += 1; -} - -// Decrements the reference count on the "plugin" library. This must -// correspond to an earlier call to ref_plugin(). When the last reference is -// removed, the plugin will be unloaded. -void PPInstance:: -unref_plugin() { - assert( s_instanceCount > 0 ); - s_instanceCount -= 1; - - if ( s_instanceCount == 0 && is_plugin_loaded() ) { - nout << "Unloading core API\n"; - unload_plugin(nout); - - // This pointer is no longer valid and must be reset for next time. - PPBrowserObject::clear_class_definition(); - } -} - -int PPInstance::Start( const std::string& p3dFilename ) -{ - { - CSingleLock lock(&_load_mutex); - lock.Lock(); - - assert(!m_isInit); - m_isInit = true; - } - - P3D_window_handle parent_window; - memset(&parent_window, 0, sizeof(parent_window)); - parent_window._window_handle_type = P3D_WHT_win_hwnd; - parent_window._handle._win_hwnd._hwnd = m_parentCtrl.m_hWnd; - - RECT rect; - GetClientRect( m_parentCtrl.m_hWnd, &rect ); - - nout << "Creating new P3D instance object for " << p3dFilename << "\n"; - m_p3dInstance = P3D_new_instance_ptr( &P3D_NotificationSync, _tokens, _num_tokens, 0, NULL, (void*)&m_parentCtrl ); - - if ( !m_p3dInstance ) - { - nout << "Error creating P3D instance: " << GetLastError() << "\n"; - return 1; - } - CComPtr pDispatch; - PPBrowserObject *pobj = new PPBrowserObject( &m_parentCtrl, pDispatch ); - P3D_instance_set_browser_script_object_ptr( m_p3dInstance, pobj ); - P3D_OBJECT_DECREF( pobj ); - - m_p3dObject = P3D_instance_get_panda_script_object_ptr( m_p3dInstance ); - P3D_OBJECT_INCREF( m_p3dObject ); - - P3D_instance_setup_window_ptr( m_p3dInstance, P3D_WT_embedded, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, &parent_window ); - - nout << "Starting new P3D instance " << p3dFilename << "\n"; - if ( !P3D_instance_start_ptr( m_p3dInstance, false, p3dFilename.c_str(), 0 ) ) - { - nout << "Error starting P3D instance: " << GetLastError() << "\n"; - return 1; - } - - return 0; -} - -int PPInstance::Stop( ) -{ - m_eventStop.SetEvent( ); - ::WaitForSingleObject( m_eventDownloadStopped.m_hObject, INFINITE ); - if ( m_p3dInstance ) - { - P3D_instance_finish_ptr( m_p3dInstance ); - m_p3dInstance = NULL; - } - if ( m_p3dObject ) - { - P3D_OBJECT_DECREF( m_p3dObject ); - m_p3dObject = NULL; - } - if ( m_pluginLoaded ) - { - UnloadPlugin(); - } - - if (_tokens != NULL) { - for ( int j = 0; j < _num_tokens; ++j) { - delete [] _tokens[j]._keyword; - delete [] _tokens[j]._value; - } - delete [] _tokens; - _tokens = NULL; - _num_tokens = 0; - } - - return 0; -} - -std::string PPInstance::GetHostUrl( ) -{ - CString hostingPageLocation = m_parentCtrl.m_hostingPageUrl.Left( m_parentCtrl.m_hostingPageUrl.ReverseFind( '/' ) );; - std::string p3dRemoteFilename( hostingPageLocation ); - p3dRemoteFilename += "/"; - return p3dRemoteFilename; -} - -std::string PPInstance::GetP3DFilename( ) -{ - std::string p3dFilename; - for ( UINT i = 0; i < m_parentCtrl.m_parameters.size(); i++ ) - { - std::pair< CString, CString > keyAndValue = m_parentCtrl.m_parameters[ i ]; - if ( keyAndValue.first == "data" ) - { - p3dFilename = keyAndValue.second; - } - } - return p3dFilename; -} - -void PPInstance::HandleRequestLoop() { - P3D_instance *p3d_inst = P3D_check_request_ptr(0.0); - while ( p3d_inst != NULL ) { - P3D_request *request = P3D_instance_get_request_ptr(p3d_inst); - if ( request != NULL ) { - CP3DActiveXCtrl* parent = ( CP3DActiveXCtrl* )(p3d_inst->_user_data); - if ( parent ) { - if (!parent->m_instance.HandleRequest( request )) { - // If handling the request is meant to yield control temporarily to - // JavaScript (e.g. P3D_RT_callback), then do so now. - return; - } - - } else { - nout << "Error handling P3D request. Instance's user data is not a Control \n"; - } - } - p3d_inst = P3D_check_request_ptr(0.0); - } -} - -void PPInstance::HandleRequestGetUrl( void* data ) -{ - HRESULT hr( S_OK ); - ThreadedRequestData *trdata = static_cast( data ); - PPInstance *self = trdata->_self; - P3D_request *request = trdata->_request; - std::string host_url = trdata->_host_url; - delete trdata; - - if ( !request ) - { - return; - } - int unique_id = request->_request._get_url._unique_id; - std::string url = request->_request._get_url._url; - CP3DActiveXCtrl* parent = static_cast ( request->_instance->_user_data ); - - if ( !parent ) - { - return; - } - - nout << "Handling P3D_RT_get_url request from " << url << "\n"; - - // Convert a relative URL into a full URL. - size_t colon = url.find(':'); - size_t slash = url.find('/'); - if (colon == std::string::npos || colon > slash) { - // Not a full URL, so it's a relative URL. Prepend the current URL. - if (url.empty() || url[0] == '/') { - // It starts with a slash, so go back to the root of this particular - // host. - colon = host_url.find(':'); - if (colon != std::string::npos && - colon + 2 < host_url.size() && - host_url[colon + 1] == '/' && host_url[colon + 2] == '/') { - slash = host_url.find('/', colon + 3); - url = host_url.substr(0, slash) + url; - } - } else { - // It doesn't start with a slash, so it's relative to this page. - url = host_url + url; - } - nout << "Made fullpath: " << url << "\n"; - } - - { - PPDownloadRequest p3dObjectDownloadRequest( parent->m_instance, request ); - PPDownloadCallback bsc( p3dObjectDownloadRequest ); - hr = ::URLOpenStream( parent->GetControllingUnknown(), url.c_str(), 0, &bsc ); - } - P3D_result_code result_code = P3D_RC_done; - if ( FAILED( hr ) ) - { - nout << "Error handling P3D_RT_get_url request" << " :" << hr << "\n"; - result_code = P3D_RC_generic_error; - } - - P3D_instance_feed_url_stream_ptr( - request->_instance, - request->_request._get_url._unique_id, - result_code, - 0, - 0, - (const void*)NULL, - 0 - ); - P3D_request_finish_ptr( request, true ); -} - -bool PPInstance:: -HandleRequest( P3D_request *request ) { - if ( !request ) { - return false; - } - bool handled = false; - bool continue_loop = true; - - switch ( request->_request_type ) { - case P3D_RT_stop: - { - P3D_instance_finish_ptr( request->_instance ); - handled = true; - break; - } - case P3D_RT_get_url: - { - // We always handle url requests on a thread. - ThreadedRequestData *trdata = new ThreadedRequestData; - trdata->_self = this; - trdata->_request = request; - trdata->_host_url = GetHostUrl(); - - _beginthread( HandleRequestGetUrl, 0, trdata ); - handled = true; - return true; - } - case P3D_RT_callback: - { - // In the case of a callback, yield control temporarily to JavaScript. - continue_loop = false; - break; - } - default: - { - // Some request types are not handled. - break; - } - }; - - P3D_request_finish_ptr( request, handled ); - return continue_loop; -} - -/** - * Compares the two dotted-integer sequence values numerically. Returns -1 if - * seq_a sorts first, 1 if seq_b sorts first, 0 if they are equivalent. - */ -int PPInstance:: -compare_seq(const string &seq_a, const string &seq_b) { - const char *num_a = seq_a.c_str(); - const char *num_b = seq_b.c_str(); - int comp = compare_seq_int(num_a, num_b); - while (comp == 0) { - if (*num_a != '.') { - if (*num_b != '.') { - // Both strings ran out together. - return 0; - } - // a ran out first. - return -1; - } else if (*num_b != '.') { - // b ran out first. - return 1; - } - - // Increment past the dot. - ++num_a; - ++num_b; - comp = compare_seq(num_a, num_b); - } - - return comp; -} - -/** - * Numerically compares the formatted integer value at num_a with num_b. - * Increments both num_a and num_b to the next character following the valid - * integer. - */ -int PPInstance:: -compare_seq_int(const char *&num_a, const char *&num_b) { - long int a; - char *next_a; - long int b; - char *next_b; - - a = strtol((char *)num_a, &next_a, 10); - b = strtol((char *)num_b, &next_b, 10); - - num_a = next_a; - num_b = next_b; - - if (a < b) { - return -1; - } else if (b < a) { - return 1; - } else { - return 0; - } -} - -/** - * Called when something has gone wrong that prevents the plugin instance from - * running. Specifically, this means it failed to load the core API. - */ -void PPInstance:: -set_failed() { - if (!_failed) { - _failed = true; - - nout << "Plugin failed.\n"; - - // Look for the "onpluginfail" token. - string expression = lookup_token("onpluginfail"); - - if (!expression.empty()) { - // Now attempt to evaluate the expression. - COleVariant varResult; - CComPtr pDispatch; - - CString evalExpression( expression.c_str() ); - HRESULT hr = m_parentCtrl.EvalExpression( pDispatch, evalExpression , varResult ); - if (FAILED(hr)) { - nout << "Unable to eval " << expression << "\n"; - } else { - nout << "Eval " << expression << "\n"; - } - } - } -} - - -/** - * Returns the value associated with the first appearance of the named token, - * or empty string if the token does not appear. - */ -std::string PPInstance:: -lookup_token(const std::string &keyword) const { - for (int i = 0; i < _num_tokens; ++i) { - if (strcmp(_tokens[i]._keyword, keyword.c_str()) == 0) { - return _tokens[i]._value; - } - } - - return string(); -} - -/** - * Returns true if the named token appears in the list, false otherwise. - */ -bool PPInstance:: -has_token(const std::string &keyword) const { - for (int i = 0; i < _num_tokens; ++i) { - if (strcmp(_tokens[i]._keyword, keyword.c_str()) == 0) { - return true; - } - } - - return false; -} diff --git a/direct/src/plugin_activex/PPInstance.h b/direct/src/plugin_activex/PPInstance.h deleted file mode 100644 index c8da8ca650..0000000000 --- a/direct/src/plugin_activex/PPInstance.h +++ /dev/null @@ -1,120 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPInstance.h - * @author atrestman - * @date 2009-09-14 - */ - -#pragma once - -#include -#include -#include -#include - -#include "p3d_plugin.h" -#include "PPDownloadCallback.h" -#include "PPLogger.h" -#include "fileSpec.h" -#include "load_plugin.h" - -#define WM_PY_LAUNCHED (WM_USER + 1) -#define WM_PROGRESS (WM_USER + 2) -#define WM_PANDA_NOTIFICATION (WM_USER + 3) - -class CP3DActiveXCtrl; - -class PPInstance -{ -public: - PPInstance( CP3DActiveXCtrl& parentCtrl ); - virtual ~PPInstance( ); - - void read_tokens(); - int DownloadP3DComponents( std::string& p3dDllFilename ); - - int LoadPlugin( const std::string& dllFilename ); - int UnloadPlugin( void ); - - static void ref_plugin(); - static void unref_plugin(); - - int Start( const std::string& p3dFileName ); - int Stop( ); - - std::string GetHostUrl( ); - std::string GetP3DFilename( ); - - static void HandleRequestLoop(); - - inline bool IsInit() { return m_isInit; } - - HWND m_parentWnd; - CEvent m_eventStop; - CEvent m_eventDownloadStopped; - - P3D_object* m_p3dObject; - - // Set from fgcolor & bgcolor. - int _fgcolor_r, _fgcolor_b, _fgcolor_g; - int _bgcolor_r, _bgcolor_b, _bgcolor_g; - -protected: - PPInstance( ); - PPInstance( const PPInstance& ); - - int DownloadFile( const std::string& from, const std::string& to ); - int CopyFile( const std::string& from, const std::string& to ); - - bool read_contents_file(const std::string &contents_filename, bool fresh_download); - void find_host(TiXmlElement *xcontents); - void read_xhost(TiXmlElement *xhost); - void add_mirror(std::string mirror_url); - void choose_random_mirrors(std::vector &result, int num_mirrors); - - bool HandleRequest( P3D_request *request ); - static void HandleRequestGetUrl( void *data ); - - static int compare_seq(const std::string &seq_a, const std::string &seq_b); - static int compare_seq_int(const char *&num_a, const char *&num_b); - - void set_failed(); - - std::string lookup_token(const std::string &keyword) const; - bool has_token(const std::string &keyword) const; - - P3D_instance* m_p3dInstance; - CP3DActiveXCtrl& m_parentCtrl; - PPLogger m_logger; - - bool m_isInit; - bool m_pluginLoaded; - CMutex _load_mutex; - - std::string _download_url_prefix; - typedef std::vector Mirrors; - Mirrors _mirrors; - std::string _coreapi_set_ver; - FileSpec _coreapi_dll; - time_t _contents_expiration; - bool _failed; - - P3D_token *_tokens; - int _num_tokens; - - std::string m_rootDir; - std::wstring m_rootDir_w; - - class ThreadedRequestData { - public: - PPInstance *_self; - P3D_request *_request; - std::string _host_url; - }; -}; diff --git a/direct/src/plugin_activex/PPInterface.cpp b/direct/src/plugin_activex/PPInterface.cpp deleted file mode 100644 index 01eee14d08..0000000000 --- a/direct/src/plugin_activex/PPInterface.cpp +++ /dev/null @@ -1,595 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPInterface.cpp - * @author atrestman - * @date 2009-09-14 - */ - -#include "stdafx.h" - -#include "PPInterface.h" -#include "PPPandaObject.h" -#include "PPBrowserObject.h" -#include "PPInstance.h" -#include "P3DActiveXCtrl.h" - -#include -#include - -PPInterface::PPInterface( ) -{ -} - -PPInterface::~PPInterface( ) -{ -} - - -HRESULT PPInterface::GetIdOfName( IDispatch* pDisp, CString& ptName, DISPID* dispID ) -{ - if( !pDisp ) - { - return E_FAIL; - } - OLECHAR* pElementName = ptName.AllocSysString(); - - HRESULT hr = pDisp->GetIDsOfNames(IID_NULL, &pElementName, 1, LOCALE_USER_DEFAULT, dispID); - SysFreeString( pElementName ); - - return hr; -} - -HRESULT PPInterface::Invoke(int nType, IDispatch* pDisp, CString& ptName, VARIANT* pvResult, int cArgs, VARIANT* params) -{ - if( !pDisp ) - { - return E_FAIL; - } - - DISPPARAMS dp = { NULL, NULL, 0, 0 }; - DISPID dispidNamed = DISPID_PROPERTYPUT; - DISPID dispID; - CComPtr pDispEx; - - HRESULT hr = GetIdOfName( pDisp, ptName, &dispID ); - if ( DISP_E_UNKNOWNNAME == hr ) - { - hr = pDisp->QueryInterface( IID_IDispatchEx, ( void** )&pDispEx ); - if ( SUCCEEDED( hr ) && pDispEx ) - { - OLECHAR* pElementName = ptName.AllocSysString(); - hr = pDispEx->GetDispID( pElementName, fdexNameEnsure, &dispID ); - SysFreeString( pElementName ); - } - } - if ( FAILED( hr ) ) - { - return hr; - } - - // Allocate memory for arguments... - VARIANT *pArgs = new VARIANT[ cArgs + 1 ]; - - // Reversing the arguments!!! NOTE: http:msdn.microsoft.comen- - // uslibrarycc237569(PROT.10).aspx pDispParams: MUST point to a DISPPARAMS - // structure that defines the arguments passed to the method. Arguments - // MUST be stored in pDispParams->rgvarg in reverse order, so that the - // first argument is the one with the highest index in the array. Byref - // arguments MUST be marked in this array as VT_EMPTY entries, and stored - // in rgVarRef instead. - - for( int i = 0; i < cArgs; i++ ) - { - pArgs[i] = params[ cArgs - 1 - i ]; - } - - // Build DISPPARAMS - dp.cArgs = cArgs; - dp.rgvarg = pArgs; - - // Handle special-case for property-puts! - if( nType & DISPATCH_PROPERTYPUT || nType & DISPATCH_PROPERTYPUTREF ) - { - dp.cNamedArgs = 1; - dp.rgdispidNamedArgs = &dispidNamed; - } - - // Make the call! - if ( pDispEx ) - { - hr = pDispEx->InvokeEx(dispID, LOCALE_USER_DEFAULT, - nType, &dp, pvResult, NULL, NULL); - if ( FAILED( hr ) ) - { - pDispEx->DeleteMemberByDispID( dispID ); - } - } - else - { - hr = pDisp->Invoke( dispID, IID_NULL, LOCALE_USER_DEFAULT, - nType, &dp, pvResult, NULL, NULL ); - } - delete [] pArgs; - - return hr; -} - -HRESULT PPInterface::GetHtmlDocDispatch( CComPtr& pDispScript ) -{ - HRESULT hr = S_OK; - - CComPtr pOleClientSite = GetClientSte( ); - if (pOleClientSite == NULL) { - return E_FAIL; - } - - CComPtr pOleContainer; - hr = pOleClientSite->GetContainer(& pOleContainer ); - ASSERT( SUCCEEDED( hr ) && pOleContainer ); - - CComPtr pHtmlDoc; - hr = pOleContainer->QueryInterface( IID_IHTMLDocument, ( void** )&pHtmlDoc ); - ASSERT( SUCCEEDED( hr ) && pHtmlDoc ); - - // Get the script object (this returns the script object, NOT the script - // element(s) that the get_scripts method does). - hr = pHtmlDoc->get_Script( &pDispScript ); - ASSERT( SUCCEEDED( hr ) && pDispScript ); - - CComPtr pDispExScript; - hr = pDispScript->QueryInterface( IID_IDispatchEx, ( void** )&pDispExScript ); - ASSERT( SUCCEEDED( hr ) && pDispExScript ); - - pDispScript = pDispExScript; - - CComPtr pTypeInfo; - hr = pDispScript->GetTypeInfo( 0, 0, &pTypeInfo ); - - return hr; -} - -HRESULT PPInterface::HasProperty( CComPtr& pDispatch, CString& name ) -{ - HRESULT hr = S_OK; - if ( pDispatch == NULL ) - { - hr = GetHtmlDocDispatch( pDispatch ); - } - - DISPID dispID; - if ( SUCCEEDED( hr ) ) - { - hr = GetIdOfName( pDispatch, name, &dispID ); - } - return hr; -} - -HRESULT PPInterface::CallMethod( CComPtr& pDispatch, CString& name, COleVariant& varResult, int numParams, COleVariant* params ) -{ - HRESULT hr = S_OK; - if ( pDispatch == NULL ) - { - hr = GetHtmlDocDispatch( pDispatch ); - } - if ( SUCCEEDED( hr ) ) - { - hr = Invoke( DISPATCH_METHOD, pDispatch, name, &varResult, numParams, params ); - } - return hr; -} - -HRESULT PPInterface::GetProperty( CComPtr& pDispatch, CString& name, COleVariant& varResult ) -{ - HRESULT hr = S_OK; - if ( pDispatch == NULL ) - { - hr = GetHtmlDocDispatch( pDispatch ); - } - if ( SUCCEEDED( hr ) ) - { - hr = Invoke( DISPATCH_PROPERTYGET, pDispatch, name, &varResult, 0, NULL ); - } - return hr; -} - -HRESULT PPInterface::SetProperty( CComPtr& pDispatch, CString& name, COleVariant& varValue, COleVariant& varResult ) -{ - HRESULT hr = S_OK; - if ( pDispatch == NULL ) - { - hr = GetHtmlDocDispatch( pDispatch ); - } - if ( SUCCEEDED( hr ) ) - { - if ( varValue.vt == VT_DISPATCH ) - { - hr = Invoke( DISPATCH_PROPERTYPUTREF, pDispatch, name, &varResult, 1, &varValue ); - } - else - { - hr = Invoke( DISPATCH_PROPERTYPUT, pDispatch, name, &varResult, 1, &varValue ); - } - } - return hr; -} - -HRESULT PPInterface::EvalExpression( CComPtr& pDispatch, CString& expression, COleVariant& varResult ) -{ - HRESULT hr = S_OK; - if ( pDispatch == NULL ) - { - hr = GetHtmlDocDispatch( pDispatch ); - } - if ( SUCCEEDED( hr ) ) - { - COleVariant param( expression ); - hr = Invoke( DISPATCH_METHOD, pDispatch, CString("eval"), &varResult, 1, ¶m ); - } - return hr; -} - -HRESULT PPInterface::P3DHasMethod( P3D_object* p3dObject, CString& name, bool& result ) -{ - if ( !p3dObject ) - { - p3dObject = GetP3DObject( ); - if ( !p3dObject ) - { - return E_FAIL; - } - } - result = P3D_OBJECT_HAS_METHOD( p3dObject, name ); - return S_OK; -} - -HRESULT PPInterface::P3DCallMethod( P3D_object* p3dObject, CString& name, DISPPARAMS FAR* pdispparams, VARIANT FAR* varResult ) -{ - if ( !p3dObject ) - { - p3dObject = GetP3DObject( ); - if ( !p3dObject ) - { - return E_FAIL; - } - } - P3D_object** params = new P3D_object*[pdispparams->cArgs]; - for ( UINT i = 0; i < pdispparams->cArgs; i++ ) - { - // Reversing the arguments!!! http:msdn.microsoft.comen- - // uslibrarycc237569(PROT.10).aspx pDispParams: MUST point to a - // DISPPARAMS structure that defines the arguments passed to the - // method. Arguments MUST be stored in pDispParams->rgvarg in reverse - // order, so that the first argument is the one with the highest index - // in the array. Byref arguments MUST be marked in this array as - // VT_EMPTY entries, and stored in rgVarRef instead. - - COleVariant vaArg( pdispparams->rgvarg[pdispparams->cArgs - 1 - i] ); - params[i] = variant_to_p3dobj( &vaArg ); - } - bool needResult( false ); - if ( varResult ) - { - needResult = true; - } - P3D_object* p3dObjectResult = P3D_OBJECT_CALL( p3dObject, name, needResult, params, pdispparams->cArgs ); - if ( p3dObjectResult ) - { - p3dobj_to_variant( varResult, p3dObjectResult ); - P3D_OBJECT_DECREF( p3dObjectResult ); - } - for ( UINT i = 0; i < pdispparams->cArgs; i++ ) - { - P3D_OBJECT_DECREF( params[i] ); - } - delete [] params; - - return S_OK; -} - -HRESULT PPInterface::P3DGetProperty( P3D_object* p3dObject, CString& name, VARIANT FAR* varResult ) -{ - if ( !p3dObject ) - { - p3dObject = GetP3DObject( ); - if ( !p3dObject ) - { - return E_FAIL; - } - } - P3D_object* p3dObjectResult = P3D_OBJECT_GET_PROPERTY( p3dObject, name ); - if ( p3dObjectResult ) - { - p3dobj_to_variant( varResult, p3dObjectResult ); - P3D_OBJECT_DECREF( p3dObjectResult ); - } - return S_OK; -} - -HRESULT PPInterface::P3DSetProperty( P3D_object* p3dObject, CString& name, DISPPARAMS FAR* pdispparams, bool& result ) -{ - if ( !p3dObject ) - { - p3dObject = GetP3DObject( ); - if ( !p3dObject ) - { - return E_FAIL; - } - } - COleVariant vaArg( pdispparams->rgvarg ); - P3D_object* param = variant_to_p3dobj( &vaArg ); - result = P3D_OBJECT_SET_PROPERTY( p3dObject, name, true, param ); - P3D_OBJECT_DECREF( param ); - - if (!result) { - return E_FAIL; - } - - return S_OK; -} - -void PPInterface::p3dobj_to_variant(VARIANT* result, P3D_object* object) -{ - if ( !result ) - { - return; - } - switch ( P3D_OBJECT_GET_TYPE( object ) ) - { - case P3D_OT_undefined: - { - result->vt = VT_EMPTY; - break; - } - case P3D_OT_none: - { - result->vt = VT_EMPTY; - break; - } - case P3D_OT_bool: - { - result->vt = VT_BOOL; - result->bVal = P3D_OBJECT_GET_BOOL( object ); - break; - } - case P3D_OT_int: - { - result->vt = VT_I4; - result->lVal = P3D_OBJECT_GET_INT( object ); - break; - } - case P3D_OT_float: - { - result->vt = VT_R4; - result->fltVal = P3D_OBJECT_GET_FLOAT( object ); - break; - } - case P3D_OT_string: - { - int size = P3D_OBJECT_GET_STRING(object, NULL, 0); - char *buffer = new char[size]; - P3D_OBJECT_GET_STRING(object, buffer, size); - - int wsize = MultiByteToWideChar(CP_UTF8, 0, buffer, size, NULL, 0); - WCHAR *wbuffer = new WCHAR[wsize + 1]; - MultiByteToWideChar(CP_UTF8, 0, buffer, size, wbuffer, wsize); - wbuffer[wsize] = 0; - - result->vt = VT_BSTR; - result->bstrVal = SysAllocString(wbuffer); - - delete[] buffer; - delete[] wbuffer; - break; - } - case P3D_OT_object: - { - PPBrowserObject *ppBrowserObject = (PPBrowserObject *)object; - PPandaObject* ppPandaObject = new PPandaObject( this, ppBrowserObject ); - result->vt = VT_DISPATCH; - result->pdispVal = ppPandaObject; - break; - } - default: - { - result->vt = VT_EMPTY; - break; - } - } -} - -P3D_object* PPInterface::variant_to_p3dobj(COleVariant* variant) -{ - if ( !variant ) - { - return P3D_new_none_object_ptr(); - } - switch( variant->vt ) - { - case VT_VOID: - { - return P3D_new_undefined_object_ptr(); - break; - } - case VT_EMPTY: - { - // return P3D_new_none_object_ptr(); A.T. Panda really expect - // undefined object here - return P3D_new_undefined_object_ptr(); - break; - } - case VT_BOOL: - { - return P3D_new_bool_object_ptr( variant->bVal ); - break; - } - case VT_I2: - { - return P3D_new_int_object_ptr( variant->iVal ); - break; - } - case VT_I4: - { - return P3D_new_int_object_ptr( variant->lVal ); - break; - } - case VT_I8: - { - return P3D_new_int_object_ptr( variant->llVal ); - break; - } - case VT_R4: - { - return P3D_new_float_object_ptr( variant->fltVal ); - break; - } - case VT_R8: - { - return P3D_new_float_object_ptr( variant->dblVal ); - break; - } - case VT_BSTR: - { - BSTR bstr = variant->bstrVal; - UINT blen = SysStringLen(bstr); - - int slen = WideCharToMultiByte(CP_UTF8, 0, bstr, blen, - 0, 0, NULL, NULL); - char *sbuffer = new char[slen]; - WideCharToMultiByte(CP_UTF8, 0, bstr, blen, - sbuffer, slen, NULL, NULL); - - P3D_object *object = P3D_new_string_object_ptr(sbuffer, slen); - delete[] sbuffer; - return object; - break; - } - case VT_DISPATCH: - { - // The following commented-out code crashes IE7: - /* - CComPtr pDispObject( variant->pdispVal ); - CComPtr pTypeInfo; - HRESULT hr = pDispObject->GetTypeInfo( 0, 0, &pTypeInfo ); - if ( SUCCEEDED( hr ) && pTypeInfo ) - { - TYPEATTR* pTypeAttr; - hr = pTypeInfo->GetTypeAttr( &pTypeAttr ); - - pTypeInfo->ReleaseTypeAttr( pTypeAttr ); - } - */ - return new PPBrowserObject( this, variant->pdispVal ); - break; - } - default: - { - return P3D_new_undefined_object_ptr(); - break; - } - } -} - -CString PPInterface::get_repr(COleVariant& variant) -{ - std::strstream repr; - repr << "IDispatch"; - switch( variant.vt ) - { - case VT_VOID: - { - repr << ":VT_VOID"; - break; - } - case VT_EMPTY: - { - repr << ":VT_EMPTY"; - break; - } - case VT_BOOL: - { - repr << ":VT_BOOL:" << variant.bVal; - break; - } - case VT_I2: - { - repr << ":VT_I2:" << variant.iVal; - break; - } - case VT_I4: - { - repr << ":VT_I4:" << variant.lVal; - break; - } - case VT_I8: - { - repr << ":VT_I8:" << variant.llVal; - break; - } - case VT_R4: - { - repr << ":VT_R4:" << variant.fltVal; - break; - } - case VT_R8: - { - repr << ":VT_R8:" << variant.dblVal; - break; - } - case VT_BSTR: - { - CString str( variant ); - repr << ":VT_BSTR:" << str; - break; - } - case VT_DISPATCH: - { - if ( variant.pdispVal ) - { - CComPtr pDispObject( variant.pdispVal ); - CComPtr pTypeInfo; - HRESULT hr = pDispObject->GetTypeInfo( 0, 0, &pTypeInfo ); - if ( SUCCEEDED( hr ) && pTypeInfo ) - { - TYPEATTR* pTypeAttr; - hr = pTypeInfo->GetTypeAttr( &pTypeAttr ); - if ( pTypeAttr ) - { - OLECHAR szGuid[40] = { 0 }; - int nCount = ::StringFromGUID2( pTypeAttr->guid, szGuid, sizeof( szGuid ) ); - CString guid( szGuid, nCount ); - - repr << ":VT_DISPATCH:GUID:" << guid; - pTypeInfo->ReleaseTypeAttr( pTypeAttr ); - } - else - { - repr << ":VT_DISPATCH:" << variant.pdispVal; - } - } - else - { - repr << ":VT_DISPATCH:" << variant.pdispVal; - } - } - else - { - repr << ":UNKNOWN"; - } - - break; - } - default: - { - repr << ":UNKNOWN"; - break; - } - } - - return CString ( repr.str(), repr.pcount() ); -} diff --git a/direct/src/plugin_activex/PPInterface.h b/direct/src/plugin_activex/PPInterface.h deleted file mode 100644 index 0e516532a7..0000000000 --- a/direct/src/plugin_activex/PPInterface.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPInterface.h - * @author atrestman - * @date 2009-09-14 - */ - -#pragma once - -#include "p3d_plugin.h" - -class PPInterface -{ -public: - PPInterface(); - virtual ~PPInterface(); - - virtual P3D_object* GetP3DObject() = 0; - virtual IOleClientSite* GetClientSte() = 0; - - HRESULT HasProperty( CComPtr& pDispatch, CString& name ); - HRESULT CallMethod( CComPtr& pDispatch, CString& name, COleVariant& varResult, int num_params, COleVariant* params ); - HRESULT GetProperty( CComPtr& pDispatch, CString& name, COleVariant& varResult ); - HRESULT SetProperty( CComPtr& pDispatch, CString& name, COleVariant& varValue, COleVariant& varResult ); - HRESULT EvalExpression( CComPtr& pDispatch, CString& expression, COleVariant& varResult ); - - HRESULT P3DHasMethod( P3D_object* p3dObject, CString& name, bool& result ); - HRESULT P3DCallMethod( P3D_object* p3dObject, CString& name, DISPPARAMS FAR* pdispparams, VARIANT FAR* varResult ); - HRESULT P3DGetProperty( P3D_object* p3dObject, CString& name, VARIANT FAR* varResult ); - HRESULT P3DSetProperty( P3D_object* p3dObject, CString& name, DISPPARAMS FAR* pdispparams, bool& result ); - - void p3dobj_to_variant(VARIANT* result, P3D_object* object); - P3D_object* variant_to_p3dobj(COleVariant* variant); - CString get_repr(COleVariant& variant); - -private: - HRESULT GetIdOfName( IDispatch* pDisp, CString& ptName, DISPID* dispID ); - HRESULT Invoke( int nType, IDispatch* pDisp, CString& ptName, VARIANT* pvResult, int cArgs, VARIANT* params ); - HRESULT GetHtmlDocDispatch( CComPtr& pHTMLDocDispatch ); - -}; diff --git a/direct/src/plugin_activex/PPLogger.cpp b/direct/src/plugin_activex/PPLogger.cpp deleted file mode 100644 index a49f85829d..0000000000 --- a/direct/src/plugin_activex/PPLogger.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPLogger.cpp - * @author atrestman - * @date 2009-09-14 - */ - -#include "stdafx.h" - -#include "PPLogger.h" -#include "mkdir_complete.h" -#include "wstring_encode.h" - -#include - -std::ofstream PPLogger::m_logfile; -bool PPLogger::m_isOpen = false; - -PPLogger::PPLogger( ) -{ -} - -PPLogger::~PPLogger( ) -{ -} - -void PPLogger::Open( const std::string &rootDir ) -{ - if (!m_isOpen) { - // Note that this logfile name may not be specified at runtime. It must - // be compiled in if it is specified at all. - - std::string log_directory; - // Allow the developer to compile in the log directory. -#ifdef P3D_PLUGIN_LOG_DIRECTORY - if (log_directory.empty()) { - log_directory = P3D_PLUGIN_LOG_DIRECTORY; - } -#endif - - // Failing that, we write logfiles to Panda3Dlog. - if (log_directory.empty()) { - log_directory = rootDir + "/log"; - } - mkdir_complete(log_directory, std::cerr); - - // Ensure that the log directory ends with a slash. - if (!log_directory.empty() && log_directory[log_directory.size() - 1] != '/') { -#ifdef _WIN32 - if (log_directory[log_directory.size() - 1] != '\\') -#endif - log_directory += "/"; - } - - // Construct the logfile pathname. - - std::string log_basename; -#ifdef P3D_PLUGIN_LOG_BASENAME1 - if (log_basename.empty()) { - log_basename = P3D_PLUGIN_LOG_BASENAME1; - } -#endif - if (log_basename.empty()) { - log_basename = "p3dplugin"; - } - - if (!log_basename.empty()) { - std::string log_pathname = log_directory; - log_pathname += log_basename; - log_pathname += ".log"; - - m_logfile.close(); - m_logfile.clear(); - wstring log_pathname_w; - string_to_wstring(log_pathname_w, log_pathname); - m_logfile.open(log_pathname_w.c_str(), std::ios::out | std::ios::trunc); - m_logfile.setf(std::ios::unitbuf); - } - - // If we didn't have a logfile name compiled in, we throw away log output - // by the simple expedient of never actually opening the ofstream. - m_isOpen = true; - } -} diff --git a/direct/src/plugin_activex/PPLogger.h b/direct/src/plugin_activex/PPLogger.h deleted file mode 100644 index 2cc49de77a..0000000000 --- a/direct/src/plugin_activex/PPLogger.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPLogger.h - * @author atrestman - * @date 2009-09-14 - */ - -#pragma once - -#include -#include -#include - -#define P3D_DEFAULT_PLUGIN_LOG_FILENAME "p3dActiveXlog.log" - -class PPLogger -{ -public: - PPLogger( ); - virtual ~PPLogger( ); - - void Open( const std::string &rootDir ); - static std::ofstream& Log( ) { return m_logfile; } - -protected: - static bool m_isOpen; - static std::ofstream m_logfile; -}; - -#define nout PPLogger::Log( ) diff --git a/direct/src/plugin_activex/PPPandaObject.cpp b/direct/src/plugin_activex/PPPandaObject.cpp deleted file mode 100644 index e65d6d7974..0000000000 --- a/direct/src/plugin_activex/PPPandaObject.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPPandaObject.cpp - * @author atrestman - * @date 2009-09-14 - */ - -#include "stdafx.h" -#include "PPPandaObject.h" -#include "PPInstance.h" -#include "load_plugin.h" - -PPandaObject::PPandaObject( PPInterface* interfac, P3D_object* p3dObject ) : - m_interface( interfac ), m_p3dObject( p3dObject ), m_refs( 0 ), m_ptinfo( NULL ) -{ - if ( m_p3dObject ) - { - P3D_OBJECT_INCREF( m_p3dObject ); - } - AddRef(); - PPInstance::ref_plugin(); -} - -PPandaObject::~PPandaObject() -{ - if( m_ptinfo ) - { - m_ptinfo->Release(); - } - - // Clean up the p3d_object, but only if we haven't already unloaded the - // plugin. - if ( m_p3dObject ) - { - P3D_OBJECT_DECREF( m_p3dObject ); - } - - PPInstance::unref_plugin(); -} - -// Dispatch Methods - -STDMETHODIMP_(unsigned long) PPandaObject::AddRef() -{ - return ++m_refs; -} - -STDMETHODIMP_(unsigned long) PPandaObject::Release() -{ - --m_refs; - if( m_refs <= 0 ) - { - delete this; - return 0; - } - return m_refs; -} - -STDMETHODIMP PPandaObject::QueryInterface(REFIID riid, void FAR* FAR* ppv) -{ - if(!IsEqualIID(riid, IID_IUnknown)) - { - if(!IsEqualIID(riid, IID_IDispatch)) - { - *ppv = NULL; - return E_NOINTERFACE; - } - } - *ppv = this; - AddRef(); - return NOERROR; -} - -STDMETHODIMP PPandaObject::GetIDsOfNames( - REFIID riid, - OLECHAR FAR* FAR* rgszNames, - unsigned int cNames, - LCID lcid, - DISPID FAR* rgdispid) -{ - UNUSED(lcid); - - if(!IsEqualIID(riid, IID_NULL)) - { - return DISP_E_UNKNOWNINTERFACE; - } - - for ( UINT i = 0; i < cNames; i++ ) - { - UINT j = 0; - for ( j = 0; j < m_idsOfNames.size(); j++ ) - { - if ( m_idsOfNames[j] == rgszNames[i] ) - { - rgdispid[i] = j; - break; - } - } - if ( j >= m_idsOfNames.size() ) - { - CString name( rgszNames[i] ); - m_idsOfNames.push_back( name ); - rgdispid[i] = j; - } - } - return S_OK; -} - -STDMETHODIMP PPandaObject::GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo) -{ - UNUSED(lcid); - - if ( ppTInfo == NULL ) - { - return E_INVALIDARG; - } - *ppTInfo = NULL; - - if( iTInfo != 0 ) - { - return DISP_E_BADINDEX; - } - if ( m_ptinfo == NULL ) - { - return E_FAIL; - } - m_ptinfo->AddRef(); // AddRef and return pointer to cached - // typeinfo for this object. - *ppTInfo = m_ptinfo; - - return NOERROR; -} - -STDMETHODIMP PPandaObject::GetTypeInfoCount(unsigned int FAR* pctinfo) -{ - // This object has a single *introduced* interface - *pctinfo = 1; - - return NOERROR; -} - -STDMETHODIMP PPandaObject::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - unsigned short wFlags, - DISPPARAMS FAR* pdispparams, - VARIANT FAR* pvarResult, - EXCEPINFO FAR* pexcepinfo, - unsigned int FAR* puArgErr) -{ - UNUSED(lcid); - HRESULT hr( S_OK ); - - - if(!IsEqualIID(riid, IID_NULL)) - { - return DISP_E_UNKNOWNINTERFACE; - } - if ( !m_interface ) - { - return E_FAIL; - } - - if ( dispidMember >= m_idsOfNames.size( ) ) - { - return E_FAIL; - } - - CString& name( m_idsOfNames[dispidMember] ); - - switch ( wFlags ) - { - case ( DISPATCH_METHOD ): - case ( DISPATCH_METHOD | DISPATCH_PROPERTYGET ): - { - // NOTE: http:msdn.microsoft.comen-uslibraryms221479.aspx The - // member is invoked as a method. If a property has the same - // name, both the DISPATCH_METHOD and the DISPATCH_PROPERTYGET - // flag may be set. - - bool hasMethod( false ); - hr = m_interface->P3DHasMethod( m_p3dObject, name, hasMethod ); - if ( SUCCEEDED( hr ) && hasMethod ) - { - hr = m_interface->P3DCallMethod( m_p3dObject, name, pdispparams, pvarResult ); - } - } - break; - case ( DISPATCH_PROPERTYGET ): - { - hr = m_interface->P3DGetProperty( m_p3dObject, name, pvarResult ); - } - break; - case ( DISPATCH_PROPERTYPUT ): - { - bool result( false ); - hr = m_interface->P3DSetProperty( m_p3dObject, name, pdispparams, result ); - } - break; - } - return hr; -} diff --git a/direct/src/plugin_activex/PPPandaObject.h b/direct/src/plugin_activex/PPPandaObject.h deleted file mode 100644 index ea64b83e16..0000000000 --- a/direct/src/plugin_activex/PPPandaObject.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file PPPandaObject.h - * @author atrestman - * @date 2009-09-14 - */ - -#pragma once - -#include -#include - -#include "p3d_plugin.h" -#include "PPInterface.h" - -class PPandaObject : public IDispatch -{ -public: - - // Methods - PPandaObject( PPInterface* interfac, P3D_object* p3dObject ); - virtual ~PPandaObject(); - - // IUnknown methods - STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); - STDMETHOD_(unsigned long, AddRef)(void); - STDMETHOD_(unsigned long, Release)(void); - - // IDispatch methods - STDMETHOD(GetTypeInfoCount)(unsigned int FAR* pcTypeInfo); - - STDMETHOD(GetTypeInfo)( - unsigned int iTypeInfo, - LCID lcid, - ITypeInfo FAR* FAR* ppTypeInfo); - - STDMETHOD(GetIDsOfNames)( - REFIID riid, - OLECHAR FAR* FAR* rgszNames, - unsigned int cNames, - LCID lcid, - DISPID FAR* rgdispid); - - STDMETHOD(Invoke)( - DISPID dispidMember, - REFIID riid, - LCID lcid, - unsigned short wFlags, - DISPPARAMS FAR* pdispparams, - VARIANT FAR* pvarResult, - EXCEPINFO FAR* pexcepinfo, - unsigned int FAR* puArgErr); - -private: - PPandaObject(); - - // Props - Dispatch related - unsigned long m_refs; - ITypeInfo FAR* m_ptinfo; - std::vector m_idsOfNames; - PPInterface* m_interface; - P3D_object *m_p3dObject; -}; diff --git a/direct/src/plugin_activex/ReadMe.txt b/direct/src/plugin_activex/ReadMe.txt deleted file mode 100644 index c40fee8cfc..0000000000 --- a/direct/src/plugin_activex/ReadMe.txt +++ /dev/null @@ -1,79 +0,0 @@ -======================================================================== - ACTIVEX CONTROL DLL : MyActiveX Project Overview -======================================================================== - -ControlWizard has created this project for your MyActiveX ActiveX Control -DLL, which contains 1 control. - -This skeleton project not only demonstrates the basics of writing an -ActiveX Control, but is also a starting point for writing the specific -features of your control. - -This file contains a summary of what you will find in each of the files -that make up your MyActiveX ActiveX Control DLL. - -P3DActiveX.vcproj - This is the main project file for VC++ projects generated using an - Application Wizard. It contains information about the version of - Visual C++ that generated the file, and information about the platforms, - configurations, and project features selected with the Application Wizard. - -P3DActiveX.h - This is the main include file for the ActiveX Control DLL. It - includes other project-specific includes such as resource.h. - -P3DActiveX.cpp - This is the main source file that contains code for DLL initialization, - termination and other bookkeeping. - -P3DActiveX.rc - This is a listing of the Microsoft Windows resources that the project - uses. This file can be directly edited with the Visual C++ resource - editor. - -P3DActiveX.def - This file contains information about the ActiveX Control DLL that - must be provided to run with Microsoft Windows. - -P3DActiveX.idl - This file contains the Object Description Language source code for the - type library of your control. - -///////////////////////////////////////////////////////////////////////////// -CP3DActiveXCtrl control: - -P3DActiveXCtrl.h - This file contains the declaration of the CP3DActiveXCtrl C++ class. - -P3DActiveXCtrl.cpp - This file contains the implementation of the CP3DActiveXCtrl C++ class. - -P3DActiveXPropPage.h - This file contains the declaration of the CP3DActiveXPropPage C++ class. - -P3DActiveXPropPage.cpp - This file contains the implementation of the CP3DActiveXPropPage C++ class. - -CP3DActiveXCtrl.bmp - This file contains a bitmap that a container will use to represent the - CP3DActiveXCtrl control when it appears on a tool palette. This bitmap - is included by the main resource file P3DActiveX.rc. - -///////////////////////////////////////////////////////////////////////////// -Other standard files: - -stdafx.h, stdafx.cpp - These files are used to build a precompiled header (PCH) file - named P3DActiveX.pch and a precompiled types (PCT) file named stdafx.obj. - -resource.h - This is the standard header file, which defines new resource IDs. - The Visual C++ resource editor reads and updates this file. - -///////////////////////////////////////////////////////////////////////////// -Other notes: - -ControlWizard uses "TODO:" to indicate parts of the source code you -should add to or customize. - -///////////////////////////////////////////////////////////////////////////// diff --git a/direct/src/plugin_activex/p3dactivex_composite1.cxx b/direct/src/plugin_activex/p3dactivex_composite1.cxx deleted file mode 100644 index c18e6d9bf4..0000000000 --- a/direct/src/plugin_activex/p3dactivex_composite1.cxx +++ /dev/null @@ -1,10 +0,0 @@ -#include "P3DActiveX.cpp" -#include "P3DActiveXCtrl.cpp" -#include "P3DActiveXPropPage.cpp" -#include "PPBrowserObject.cpp" -#include "PPDownloadCallback.cpp" -#include "PPDownloadRequest.cpp" -#include "PPInstance.cpp" -#include "PPInterface.cpp" -#include "PPLogger.cpp" -#include "PPPandaObject.cpp" diff --git a/direct/src/plugin_activex/resource.h b/direct/src/plugin_activex/resource.h deleted file mode 100644 index cb7e075db2..0000000000 --- a/direct/src/plugin_activex/resource.h +++ /dev/null @@ -1,27 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by P3DActiveX.rc -// -#define IDS_P3DACTIVEX 1 -#define IDB_P3DACTIVEX 1 -#define IDS_P3DACTIVEX_PPG 2 -#define IDS_P3DACTIVEX_PPG_CAPTION 200 -#define IDD_PROPPAGE_P3DACTIVEX 200 -#define IDR_GIF1 201 -#define IDC_PANDALAUNCH_BUTTON 202 -#define IDC_PANDAOUT 203 -#define IDC_EDIT1 204 -#define IDC_EDIT2 205 -#define IDC_CLEAR 206 -#define IDC_PANDACONTAINER 207 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 203 -#define _APS_NEXT_COMMAND_VALUE 32768 -#define _APS_NEXT_CONTROL_VALUE 208 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/direct/src/plugin_activex/stdafx.cpp b/direct/src/plugin_activex/stdafx.cpp deleted file mode 100644 index 40ffb29d93..0000000000 --- a/direct/src/plugin_activex/stdafx.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// stdafx.cpp : source file that includes just the standard includes -// P3DActiveX.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" diff --git a/direct/src/plugin_activex/stdafx.h b/direct/src/plugin_activex/stdafx.h deleted file mode 100644 index a651a9c0f4..0000000000 --- a/direct/src/plugin_activex/stdafx.h +++ /dev/null @@ -1,41 +0,0 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, -// but are changed infrequently - -#pragma once - -#ifndef VC_EXTRALEAN -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers -#endif - -// Modify the following defines if you have to target a platform prior to the ones specified below. -// Refer to MSDN for the latest info on corresponding values for different platforms. -#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later. -#define WINVER 0x0501 // Change this to the appropriate value to target Windows XP or later. -#endif - -#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. -#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target Windows 2000 or later. -#endif - -#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows XP or later. -#define _WIN32_WINDOWS 0x0501 // Change this to the appropriate value to target Windows Me or later. -#endif - -#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later. -#define _WIN32_IE 0x0500 // Change this to the appropriate value to target IE 5.0 or later. -#endif - -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit - -#include // MFC support for ActiveX Controls -#include // MFC extensions -#include // MFC support for Internet Explorer 4 Comon Controls -#ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT - -#include - -#include - diff --git a/direct/src/plugin_installer/FileAssociation.nsh b/direct/src/plugin_installer/FileAssociation.nsh deleted file mode 100644 index 71a9162efc..0000000000 --- a/direct/src/plugin_installer/FileAssociation.nsh +++ /dev/null @@ -1,190 +0,0 @@ -/* -_____________________________________________________________________________ - - File Association -_____________________________________________________________________________ - - Based on code taken from http://nsis.sourceforge.net/File_Association - - Usage in script: - 1. !include "FileAssociation.nsh" - 2. [Section|Function] - ${FileAssociationFunction} "Param1" "Param2" "..." $var - [SectionEnd|FunctionEnd] - - FileAssociationFunction=[RegisterExtension|UnRegisterExtension] - -_____________________________________________________________________________ - - ${RegisterExtension} "[executable]" "[extension]" "[description]" - -"[executable]" ; executable which opens the file format - ; -"[extension]" ; extension, which represents the file format to open - ; -"[description]" ; description for the extension. This will be display in Windows Explorer. - ; - - - ${UnRegisterExtension} "[extension]" "[description]" - -"[extension]" ; extension, which represents the file format to open - ; -"[description]" ; description for the extension. This will be display in Windows Explorer. - ; - -_____________________________________________________________________________ - - Macros -_____________________________________________________________________________ - - Change log window verbosity (default: 3=no script) - - Example: - !include "FileAssociation.nsh" - !insertmacro RegisterExtension - ${FileAssociation_VERBOSE} 4 # all verbosity - !insertmacro UnRegisterExtension - ${FileAssociation_VERBOSE} 3 # no script -*/ - - -!ifndef FileAssociation_INCLUDED -!define FileAssociation_INCLUDED - -!include Util.nsh - -!verbose push -!verbose 3 -!ifndef _FileAssociation_VERBOSE - !define _FileAssociation_VERBOSE 3 -!endif -!verbose ${_FileAssociation_VERBOSE} -!define FileAssociation_VERBOSE `!insertmacro FileAssociation_VERBOSE` -!verbose pop - -!macro FileAssociation_VERBOSE _VERBOSE - !verbose push - !verbose 3 - !undef _FileAssociation_VERBOSE - !define _FileAssociation_VERBOSE ${_VERBOSE} - !verbose pop -!macroend - - - -!macro RegisterExtensionCall _EXECUTABLE _EXTENSION _DESCRIPTION - !verbose push - !verbose ${_FileAssociation_VERBOSE} - Push `${_DESCRIPTION}` - Push `${_EXTENSION}` - Push `${_EXECUTABLE}` - ${CallArtificialFunction} RegisterExtension_ - !verbose pop -!macroend - -!macro UnRegisterExtensionCall _EXTENSION _DESCRIPTION - !verbose push - !verbose ${_FileAssociation_VERBOSE} - Push `${_EXTENSION}` - Push `${_DESCRIPTION}` - ${CallArtificialFunction} UnRegisterExtension_ - !verbose pop -!macroend - - - -!define RegisterExtension `!insertmacro RegisterExtensionCall` -!define un.RegisterExtension `!insertmacro RegisterExtensionCall` - -!macro RegisterExtension -!macroend - -!macro un.RegisterExtension -!macroend - -!macro RegisterExtension_ - !verbose push - !verbose ${_FileAssociation_VERBOSE} - - Exch $R2 ;exe - Exch - Exch $R1 ;ext - Exch - Exch 2 - Exch $R0 ;desc - Exch 2 - Push $0 - Push $1 - - ReadRegStr $1 HKCR $R1 "" ; read current file association - StrCmp "$1" "" NoBackup ; is it empty - StrCmp "$1" "$R0" NoBackup ; is it our own - WriteRegStr HKCR $R1 "backup_val" "$1" ; backup current value -NoBackup: - WriteRegStr HKCR $R1 "" "$R0" ; set our file association - - ReadRegStr $0 HKCR $R0 "" - StrCmp $0 "" 0 Skip - WriteRegStr HKCR "$R0" "" "$R0" - WriteRegStr HKCR "$R0\shell" "" "open" - WriteRegStr HKCR "$R0\DefaultIcon" "" "$R2,0" -Skip: - WriteRegStr HKCR "$R0\shell\open\command" "" '"$R2" "%1"' - WriteRegStr HKCR "$R0\shell\edit" "" "Edit $R0" - WriteRegStr HKCR "$R0\shell\edit\command" "" '"$R2" "%1"' - - Pop $1 - Pop $0 - Pop $R2 - Pop $R1 - Pop $R0 - - !verbose pop -!macroend - - - -!define UnRegisterExtension `!insertmacro UnRegisterExtensionCall` -!define un.UnRegisterExtension `!insertmacro UnRegisterExtensionCall` - -!macro UnRegisterExtension -!macroend - -!macro un.UnRegisterExtension -!macroend - -!macro UnRegisterExtension_ - !verbose push - !verbose ${_FileAssociation_VERBOSE} - - Exch $R1 ;desc - Exch - Exch $R0 ;ext - Exch - Push $0 - Push $1 - - ReadRegStr $1 HKCR $R0 "" - StrCmp $1 $R1 0 NoOwn ; only do this if we own it - ReadRegStr $1 HKCR $R0 "backup_val" - StrCmp $1 "" 0 Restore ; if backup="" then delete the whole key - DeleteRegKey HKCR $R0 - Goto NoOwn - -Restore: - WriteRegStr HKCR $R0 "" $1 - DeleteRegValue HKCR $R0 "backup_val" - DeleteRegKey HKCR $R1 ;Delete key with association name settings - -NoOwn: - - Pop $1 - Pop $0 - Pop $R1 - Pop $R0 - - !verbose pop -!macroend - -!endif # !FileAssociation_INCLUDED diff --git a/direct/src/plugin_installer/VersionInfo.vbs b/direct/src/plugin_installer/VersionInfo.vbs deleted file mode 100644 index ab813d764a..0000000000 --- a/direct/src/plugin_installer/VersionInfo.vbs +++ /dev/null @@ -1,4 +0,0 @@ -set args = WScript.Arguments -Set fso = CreateObject("Scripting.FileSystemObject") -WScript.Echo fso.GetFileVersion(args(0)) -Wscript.Quit diff --git a/direct/src/plugin_installer/make_installer.py b/direct/src/plugin_installer/make_installer.py deleted file mode 100755 index 9410f4fb90..0000000000 --- a/direct/src/plugin_installer/make_installer.py +++ /dev/null @@ -1,601 +0,0 @@ -#! /usr/bin/env python - -import os -import sys -import shutil -import platform -import tempfile -from optparse import OptionParser -import subprocess - -try: - from hashlib import sha1 as sha -except ImportError: - from sha import sha - -usage = """ -This command creates a graphical installer for the -Panda3D plugin and runtime environment. - - %prog [opts]""" - -parser = OptionParser(usage = usage) -parser.add_option('-n', '--short', dest = 'short_name', - help = 'The product short name', - default = 'Panda3D') -parser.add_option('-N', '--long', dest = 'long_name', - help = 'The product long name', - default = 'Panda3D Game Engine') -parser.add_option('-v', '--version', dest = 'version', - help = 'The product version', - default = None) -parser.add_option('-p', '--publisher', dest = 'publisher', - help = 'The name of the publisher', - default = 'Carnegie Mellon Entertainment Technology Center') -parser.add_option('', '--install', dest = 'install_dir', - help = "The install directory on the user's machine (Windows only)", - default = '$PROGRAMFILES\\Panda3D') -parser.add_option('-l', '--license', dest = 'license', - help = 'A file containing the license or EULA text', - default = None) -parser.add_option('-w', '--website', dest = 'website', - help = 'The product website', - default = 'https://www.panda3d.org') -parser.add_option('', '--start', dest = 'start', - help = 'Specify this option to add a start menu', - action = 'store_true', default = False) -parser.add_option('', '--welcome_image', dest = 'welcome_image', - help = 'The image to display on the installer, 170x312 BMP', - default = None) -parser.add_option('', '--install_icon', dest = 'install_icon', - help = 'The icon to give to the installer', - default = None) -parser.add_option('', '--nsis', dest = 'nsis', - help = 'The path to the makensis executable', - default = None) -parser.add_option('', '--cab', dest = 'cab', - help = 'Generate an ActiveX CAB file (Windows only). If --spc and --pvk are not also specified, the CAB file will be unsigned.', - action = 'store_true', default = False) -parser.add_option('', '--spc', dest = 'spc', - help = 'Sign the CAB file generated by --cab with the indicated spc file (Windows only). You must also specify --pvk.', - default = None) -parser.add_option('', '--pvk', dest = 'pvk', - help = 'Specifies the private key to be used in conjuction with --spc to sign a CAB file (Windows only).', - default = None) -parser.add_option('', '--mssdk', dest = 'mssdk', - help = 'The path to the MS Platform SDK directory (Windows only). mssdk/bin should contain cabarc.exe and signcode.exe.', - default = None) -parser.add_option('', '--regview', dest = 'regview', - help = 'Which registry view to use, 64 or 32.', - default = None) - -(options, args) = parser.parse_args() - -this_dir = os.path.split(sys.argv[0])[0] - -assert options.version, "A version number must be supplied!" - -############################################################################## -# -# This Info.plist file is used only for the OSX 10.4 version of packagemaker. -# -############################################################################## - -Info_plist = """ - - - - CFBundleIdentifier - %(package_id)s - CFBundleShortVersionString - %(version)s - IFPkgFlagRelocatable - - IFPkgFlagAuthorizationAction - RootAuthorization - - -""" - -############################################################################## -# -# This Description.plist file is used only for the OSX 10.4 version of packagemaker. -# -############################################################################## - -Description_plist = """ - - - - IFPkgDescriptionDescription - - IFPkgDescriptionTitle - %(long_name)s - - -""" - - -############################################################################## -# -# Locate the relevant files. -# -############################################################################## - -def findExecutable(filename): - """ Searches for the named .exe or .dll file along the system PATH - and returns its full path if found, or None if not found. """ - - if sys.platform == "win32": - for p in os.defpath.split(";") + os.environ["PATH"].split(";"): - if os.path.isfile(os.path.join(p, filename)): - return os.path.join(p, filename) - else: - for p in os.defpath.split(":") + os.environ["PATH"].split(":"): - if os.path.isfile(os.path.join(p, filename)): - return os.path.join(p, filename) - return None - - -if not options.nsis: - makensis = findExecutable('makensis.exe') - if sys.platform == "win32": - if not makensis: - try: - import pandac - makensis = os.path.dirname(os.path.dirname(pandac.__file__)) - makensis = os.path.join(makensis, "nsis", "makensis.exe") - if not os.path.isfile(makensis): - makensis = None - except ImportError: pass - if not makensis: - thirdparty = os.environ.get("MAKEPANDA_THIRDPARTY", "thirdparty") - makensis = os.path.join(thirdparty, "win-nsis", "makensis.exe") - if not os.path.isfile(makensis): - makensis = None - options.nsis = makensis - -if not options.license: - try: - import pandac - options.license = os.path.join(os.path.dirname(os.path.dirname(pandac.__file__)), "LICENSE") - if not os.path.isfile(options.license): - options.license = None - except: pass - if not options.license: - options.license = os.path.join("doc", "LICENSE") - if not os.path.isfile(options.license): - options.license = None - if options.license: - options.license = os.path.abspath(options.license) - -if sys.platform == "win32" and not options.welcome_image: - filename = os.path.join('models', 'plugin_images', 'installer.bmp') - if not os.path.exists(filename): - sys.exit("Couldn't find installer.bmp for welcome_image.") - options.welcome_image = os.path.abspath(filename) - -def parseDependenciesWindows(tempFile): - """ Reads the indicated temporary file, the output from - dumpbin /dependents, to determine the list of dll's this - executable file depends on. """ - - lines = open(tempFile, 'rU').readlines() - li = 0 - while li < len(lines): - line = lines[li] - li += 1 - if line.find(' has the following dependencies') != -1: - break - - if li < len(lines): - line = lines[li] - if line.strip() == '': - # Skip a blank line. - li += 1 - - # Now we're finding filenames, until the next blank line. - filenames = [] - while li < len(lines): - line = lines[li] - li += 1 - line = line.strip() - if line == '': - # We're done. - return filenames - filenames.append(line) - - # Hmm, we ran out of data. Oh well. - if not filenames: - # Some parse error. - return None - - # At least we got some data. - return filenames - -def parseDependenciesUnix(tempFile): - """ Reads the indicated temporary file, the output from - otool -XL or ldd, to determine the list of dll's this - executable file depends on. """ - - lines = open(tempFile, 'rU').readlines() - filenames = [] - for l in lines: - filenames.append(l.strip().split(' ', 1)[0]) - return filenames - -def addDependencies(path, pathname, file, pluginDependencies, dependentFiles, required=True): - """ Checks the named file for DLL dependencies, and adds any - appropriate dependencies found into pluginDependencies and - dependentFiles. """ - - tempFile = tempfile.mktemp('.txt', 'p3d_') - if sys.platform == "darwin": - command = 'otool -XL "%s" >"%s"' - elif sys.platform == "win32": - command = 'dumpbin /dependents "%s" >"%s"' - else: - command = 'ldd "%s" >"%s"' - command = command % (pathname, tempFile) - try: - os.system(command) - except: - pass - filenames = None - - if os.path.isfile(tempFile): - if sys.platform == "win32": - filenames = parseDependenciesWindows(tempFile) - else: - filenames = parseDependenciesUnix(tempFile) - os.unlink(tempFile) - if filenames is None: - sys.exit("Unable to determine dependencies from %s" % (pathname)) - - # Look for MSVC[RP]*.dll, and MFC*.dll. These dependent files - # have to be included too. Also, any Panda-based libraries, or - # the Python DLL, should be included, in case panda3d.exe wasn't - # built static. The Panda-based libraries begin with "lib" and - # are all lowercase, or start with libpanda/libp3d. - for dfile in filenames: - dfilelower = dfile.lower() - if dfilelower not in dependentFiles: - if dfilelower.startswith('msvc') or \ - dfilelower.startswith('mfc') or \ - dfilelower.startswith('zlib1') or \ - (dfile.startswith('lib') and dfile == dfilelower) or \ - dfilelower.startswith('libpanda') or \ - dfilelower.startswith('libp3d') or \ - dfilelower.startswith('python'): - pathname = None - for pitem in path: - pathname = os.path.join(pitem, dfile) - if os.path.exists(pathname): - break - pathname = None - if not pathname: - if required: - sys.exit("Couldn't find %s." % (dfile)) - sys.stderr.write("Warning: couldn't find %s." % (dfile)) - continue - pathname = os.path.abspath(pathname) - dependentFiles[dfilelower] = pathname - - # Also recurse. - addDependencies(path, pathname, file, pluginDependencies, dependentFiles) - - if dfilelower in dependentFiles and dfilelower not in pluginDependencies[file]: - pluginDependencies[file].append(dfilelower) - -def getDllVersion(filename): - """ Returns the DLL version number in the indicated DLL, as a - string of comma-separated integers. Windows only. """ - - # This relies on the VBScript program in the same directory as - # this script. - thisdir = os.path.split(sys.argv[0])[0] - versionInfo = os.path.join(thisdir, 'VersionInfo.vbs') - tempfile = 'tversion.txt' - tempdata = open(tempfile, 'w+') - cmd = 'cscript //nologo "%s" "%s"' % (versionInfo, filename) - print(cmd) - result = subprocess.call(cmd, stdout = tempdata) - if result: - sys.exit(result) - - tempdata.seek(0) - data = tempdata.read() - tempdata.close() - os.unlink(tempfile) - return ','.join(data.strip().split('.')) - - -def makeCabFile(ocx, pluginDependencies): - """ Creates an ActiveX CAB file. Windows only. """ - - ocxFullpath = findExecutable(ocx) - cabFilename = os.path.splitext(ocx)[0] + '.cab' - - cabarc = 'cabarc' - signcode = 'signcode' - if options.mssdk: - cabarc = options.mssdk + '/bin/cabarc' - signcode = options.mssdk + '/bin/signcode' - - # First, we must generate an INF file. - infFile = 'temp.inf' - inf = open(infFile, 'w') - - info.write('[Add.Code]\n%s=%s\n%s=%s\n' % (infFile, infFile, ocx, ocx)) - dependencies = pluginDependencies[ocx] - for filename in dependencies: - inf.write('%s=%s\n' % (filename, filename)) - inf.write('\n[%s]\nfile=thiscab\n' % (infFile)) - inf.write('\n[%s]\nfile=thiscab\nclsid={924B4927-D3BA-41EA-9F7E-8A89194AB3AC}\nRegisterServer=yes\nFileVersion=%s\n' % (ocx, getDllVersion(ocxFullpath))) - - fullpaths = [] - for filename in dependencies: - fullpath = findExecutable(filename) - fullpaths.append(fullpath) - inf.write('\n[%s]\nfile=thiscab\nDestDir=11\nRegisterServer=yes\nFileVersion=%s\n' % (filename, getDllVersion(fullpath))) - inf.close() - - # Now process the inf file with cabarc. - try: - os.unlink(cabFilename) - except OSError: - pass - - cmd = '"%s" -s 6144 n "%s"' % (cabarc, cabFilename) - for fullpath in fullpaths: - cmd += ' "%s"' % (fullpath) - cmd += ' "%s" %s' % (ocxFullpath, infFile) - print(cmd) - result = subprocess.call(cmd) - if result: - sys.exit(result) - if not os.path.exists(cabFilename): - print("Couldn't generate %s" % (cabFilename)) - sys.exit(1) - - print("Successfully generated %s" % (cabFilename)) - - if options.spc and options.pvk: - # Now we have to sign the cab file. - cmd = '"%s" -spc "%s" -k "%s" "%s"' % (signcode, options.spc, options.pvk, cabFilename) - print(cmd) - result = subprocess.call(cmd) - if result: - sys.exit(result) - -def makeInstaller(): - # Locate the plugin(s). - pluginFiles = {} - pluginDependencies = {} - dependentFiles = {} - - # These are the primary files that make - # up the plugin/runtime. - if sys.platform == "darwin": - npapi = 'nppanda3d.plugin' - panda3d = 'panda3d' - panda3dapp = 'Panda3D.app' - baseFiles = [npapi, panda3d, panda3dapp] - elif sys.platform == 'win32': - ocx = 'p3dactivex.ocx' - npapi = 'nppanda3d.dll' - panda3d = 'panda3d.exe' - panda3dw = 'panda3dw.exe' - baseFiles = [ocx, npapi, panda3d, panda3dw] - else: - baseFiles = [] - - path = [] - pathsep = ':' - if sys.platform == "win32": - pathsep = ';' - if 'PATH' in os.environ: - path += os.environ['PATH'].split(pathsep) - if sys.platform != "win32" and 'LD_LIBRARY_PATH' in os.environ: - path += os.environ['LD_LIBRARY_PATH'].split(pathsep) - if sys.platform == "darwin" and 'DYLD_LIBRARY_PATH' in os.environ: - path += os.environ['DYLD_LIBRARY_PATH'].split(pathsep) - path += os.defpath.split(pathsep) - for file in baseFiles: - pathname = None - for pitem in path: - pathname = os.path.join(pitem, file) - if os.path.exists(pathname): - break - pathname = None - if not pathname: - sys.exit("Couldn't find %s." % (file)) - - pathname = os.path.abspath(pathname) - pluginFiles[file] = pathname - pluginDependencies[file] = [] - - if sys.platform == "win32": - # Also look for the dll's that these plugins reference. - addDependencies(path, pathname, file, pluginDependencies, dependentFiles) - - if sys.platform == "darwin": - tmproot = "/var/tmp/Panda3D Runtime/" - - # Apparently, we have to rename this package with each - # version, or Snow Leopard won't think the versions are - # increasing. I don't really understand why this is so. It - # might be related to the use of the Tiger PackageMaker's - # output being run on Snow Leopard. Whatever. Numbering the - # package files works around the problem and doesn't seem to - # cause additional problems, so we'll do that. - pkgname = 'p3d-setup-%s.pkg' % (options.version) - - if os.path.exists(tmproot): - shutil.rmtree(tmproot) - if os.path.isfile(pkgname): - os.remove(pkgname) - elif os.path.isdir(pkgname): - shutil.rmtree(pkgname) - if not os.path.exists(tmproot): - os.makedirs(tmproot) - dst_npapi = os.path.join(tmproot, "Library", "Internet Plug-Ins", npapi) - dst_panda3d = os.path.join(tmproot, "usr", "local", "bin", panda3d) - dst_panda3dapp = os.path.join(tmproot, "Applications", panda3dapp) - if not os.path.exists(dst_npapi): os.makedirs(os.path.dirname(dst_npapi)) - if not os.path.exists(dst_panda3d): os.makedirs(os.path.dirname(dst_panda3d)) - if not os.path.exists(dst_panda3dapp): os.makedirs(os.path.dirname(dst_panda3dapp)) - shutil.copytree(pluginFiles[npapi], dst_npapi) - shutil.copyfile(pluginFiles[panda3d], dst_panda3d) - os.chmod(dst_panda3d, 493) # 0o755 - shutil.copytree(pluginFiles[panda3dapp], dst_panda3dapp) - - tmpresdir = tempfile.mktemp('', 'p3d-resources') - if os.path.exists(tmpresdir): - shutil.rmtree(tmpresdir) - os.makedirs(tmpresdir) - if options.license: - shutil.copyfile(options.license, os.path.join(tmpresdir, "License.txt")) - - package_id = 'org.panda3d.pkg.runtime' #TODO: maybe more customizable? - - infoFilename = None - descriptionFilename = None - packagemaker = "/Applications/Xcode.app/Contents/Applications/PackageMaker.app/Contents/MacOS/PackageMaker" - if not os.path.exists(packagemaker): - packagemaker = "/Developer/usr/bin/packagemaker" - - if os.path.exists(packagemaker): - # PackageMaker 3.0 or better, e.g. OSX 10.5. - CMD = packagemaker - CMD += ' --id "%s"' % package_id - CMD += ' --version "%s"' % options.version - CMD += ' --title "%s"' % options.long_name - CMD += ' --out "%s"' % (pkgname) - CMD += ' --target 10.5' # The earliest version of OSX supported by Panda - CMD += ' --domain system' - CMD += ' --root "%s"' % tmproot - CMD += ' --resources "%s"' % tmpresdir - CMD += ' --no-relocate' - else: - # PackageMaker 2.0, e.g. OSX 10.4. - packagemaker = "/Developer/Tools/packagemaker" - infoFilename = '/tmp/Info_plist' - info = open(infoFilename, 'w') - info.write(Info_plist % { - 'package_id' : package_id, - 'version' : options.version, - }) - info.close() - descriptionFilename = '/tmp/Description_plist' - description = open(descriptionFilename, 'w') - description.write(Description_plist % { - 'long_name' : options.long_name, - 'short_name' : options.short_name, - }) - description.close() - CMD = packagemaker - CMD += ' -build' - CMD += ' -f "%s"' % (tmproot) - CMD += ' -r "%s"' % (tmpresdir) - CMD += ' -p "%s"' % (pkgname) - CMD += ' -i "%s"' % (infoFilename) - CMD += ' -d "%s"' % (descriptionFilename) - - print("") - print(CMD) - - # Don't check the exit status of packagemaker; it's not always - # reliable. - subprocess.call(CMD, shell = True) - shutil.rmtree(tmproot) - - if infoFilename: - os.unlink(infoFilename) - if descriptionFilename: - os.unlink(descriptionFilename) - if os.path.exists(tmpresdir): - shutil.rmtree(tmpresdir) - - if not os.path.exists(pkgname): - print("Unable to create %s." % (pkgname)) - sys.exit(1) - - # Pack the .pkg into a .dmg - if not os.path.exists(tmproot): os.makedirs(tmproot) - if os.path.isdir(pkgname): - shutil.copytree(pkgname, os.path.join(tmproot, pkgname)) - else: - shutil.copyfile(pkgname, os.path.join(tmproot, pkgname)) - - tmpdmg = tempfile.mktemp('', 'p3d-setup') + ".dmg" - CMD = 'hdiutil create "%s" -srcfolder "%s"' % (tmpdmg, tmproot) - print("") - print(CMD) - result = subprocess.call(CMD, shell = True) - if result: - sys.exit(result) - shutil.rmtree(tmproot) - - # Compress the .dmg (and make it read-only) - if os.path.exists("p3d-setup.dmg"): - os.remove("p3d-setup.dmg") - CMD = 'hdiutil convert "%s" -format UDBZ -o "p3d-setup.dmg"' % tmpdmg - print("") - print(CMD) - result = subprocess.call(CMD, shell = True) - if result: - sys.exit(result) - - elif sys.platform == 'win32': - # Now build the NSIS command. - CMD = "\"" + options.nsis + "\" /V3 " - CMD += '/DPRODUCT_NAME="' + options.long_name + '" ' - CMD += '/DPRODUCT_NAME_SHORT="' + options.short_name + '" ' - CMD += '/DPRODUCT_PUBLISHER="' + options.publisher + '" ' - CMD += '/DPRODUCT_WEB_SITE="' + options.website + '" ' - CMD += '/DPRODUCT_VERSION="' + options.version + '" ' - CMD += '/DINSTALL_DIR="' + options.install_dir + '" ' - CMD += '/DLICENSE_FILE="' + options.license + '" ' - CMD += '/DOCX="' + ocx + '" ' - CMD += '/DOCX_PATH="' + pluginFiles[ocx] + '" ' - CMD += '/DNPAPI="' + npapi + '" ' - CMD += '/DNPAPI_PATH="' + pluginFiles[npapi] + '" ' - CMD += '/DPANDA3D="' + panda3d + '" ' - CMD += '/DPANDA3D_PATH="' + pluginFiles[panda3d] + '" ' - CMD += '/DPANDA3DW="' + panda3dw + '" ' - CMD += '/DPANDA3DW_PATH="' + pluginFiles[panda3dw] + '" ' - - if options.regview: - CMD += '/DREGVIEW=%s ' % (options.regview) - - for i, dep in enumerate(dependentFiles.items()): - CMD += '/DDEP%s="%s" ' % (i, dep[0]) - CMD += '/DDEP%sP="%s" ' % (i, dep[1]) - - for i, dep in enumerate(pluginDependencies[npapi]): - CMD += '/DNPAPI_DEP%s="%s" ' % (i, dep) - - if options.start: - CMD += '/DADD_START_MENU ' - - if options.welcome_image: - CMD += '/DMUI_WELCOMEFINISHPAGE_BITMAP="' + options.welcome_image + '" ' - CMD += '/DMUI_UNWELCOMEFINISHPAGE_BITMAP="' + options.welcome_image + '" ' - if options.install_icon: - CMD += '/DINSTALL_ICON="' + options.install_icon + '" ' - - CMD += '"' + this_dir + '\\p3d_installer.nsi"' - - print("") - print(CMD) - print("packing...") - result = subprocess.call(CMD) - if result: - sys.exit(result) - - if options.cab: - # Generate a CAB file and optionally sign it. - makeCabFile(ocx, pluginDependencies) - -makeInstaller() diff --git a/direct/src/plugin_installer/make_xpi.py b/direct/src/plugin_installer/make_xpi.py deleted file mode 100755 index 7cd02fd908..0000000000 --- a/direct/src/plugin_installer/make_xpi.py +++ /dev/null @@ -1,202 +0,0 @@ -#! /usr/bin/env python - -import os -import sys -import shutil -import platform -import tempfile -import zipfile -from optparse import OptionParser -import subprocess - -try: - from hashlib import sha1 as sha -except ImportError: - from sha import sha - -usage = """ -This command creates a Firefox XPI installer for the Panda3D Firefox -plugin. Also see make_installer.py. - - %prog [opts]""" - -parser = OptionParser(usage = usage) -parser.add_option('-v', '--version', dest = 'version', - help = 'The product version', - default = None) -parser.add_option('-i', '--plugin_root', dest = 'plugin_root', - help = 'The root of a directory hierarchy in which the Firefox plugins for various platforms can be found, to build a Firefox xpi file. This is normally the same as the staging directory populated by the -i parameter to ppackage. This directory should contain a directory called "plugin", which contains in turn a number of directories named for the platform, by the Panda plugin convention, e.g. linux_i386, osx_ppc, and so on. Each platform directory should contain a Firefox plugin, e.g. nppanda3d.so.') -parser.add_option('', '--host_url', dest = 'host_url', - help = "The URL at which plugin_root will be hosted. This is used to construct the update URL for the xpi file. This is required if you specify --plugin_root.") - -(options, args) = parser.parse_args() - -this_dir = os.path.split(sys.argv[0])[0] - -assert options.version, "A version number must be supplied!" -assert options.plugin_root, "The plugin_root must be supplied!" -assert options.host_url, "The host_url must be supplied!" - -# A mapping of Panda's platform strings to Firefox's equivalent -# strings. - -# I'm leaving out the Linux platforms for now. I think there is too -# much variance between distro's for this to be reliable; we'll make -# each Linux user install their distro-specific plugin instead of -# going through this mechanism. -FirefoxPlatformMap = { - 'win32' : 'WINNT_x86-msvc', - 'win_i386' : 'WINNT_x86-msvc', - 'win_amd64' : 'WINNT_x86_64-msvc', -# 'linux_i386' : 'Linux_x86-gcc3', -# 'linux_amd64' : 'Linux_x86_64-gcc3', -# 'linux_ppc' : 'Linux_ppc-gcc3', - 'osx_i386' : 'Darwin_x86-gcc3', - 'osx_amd64' : 'Darwin_x86_64-gcc3', - 'osx_ppc' : 'Darwin_ppc-gcc3', - 'freebsd_i386' : 'FreeBSD_x86-gcc3', - 'freebsd_amd64' : 'FreeBSD_x86_64-gcc3', - } - -############################################################################## -# -# This install.rdf file is used when building a Firefox XPI file. -# -############################################################################## - -install_rdf = """ - - - %(package_id)s - true - Panda3D Game Engine Plug-In - Runs 3-D games and interactive applets - %(version)s - - - {ec8030f7-c20a-464f-9b0e-13a3a9e97384} - 3.0 - * - - - http://www.panda3d.org/ - %(host_url)s/plugin/firefox/update.rdf - - -""" - -############################################################################## -# -# This update.rdf file is used when building a Firefox XPI file. -# -############################################################################## - -update_rdf = """ - - - - - - - - %(version)s - - - {ec8030f7-c20a-464f-9b0e-13a3a9e97384} - 3.0 - * - %(host_url)s/plugin/firefox/nppanda3d.xpi - sha1:%(xpi_hash)s - - - - - - - - -""" - -def makeXpiFile(): - """ Creates a Firefox XPI file, based on the various platform - version files. """ - - if not options.host_url: - print("Cannot generate xpi file without --host-url.") - sys.exit(1) - - print("Generating xpi file") - root = options.plugin_root - if os.path.isdir(os.path.join(root, 'plugin')): - root = os.path.join(root, 'plugin') - - xpi = zipfile.ZipFile('nppanda3d.xpi', 'w') - - package_id = 'runtime@panda3d.org' #TODO: maybe more customizable? - - tempFile = tempfile.mktemp('.txt', 'p3d_') - rdf = open(tempFile, 'w') - rdf.write(install_rdf % { - 'package_id' : package_id, - 'version' : options.version, - 'host_url' : options.host_url, - }) - rdf.close() - xpi.write(tempFile, 'install.rdf') - os.unlink(tempFile) - - subdirs = os.listdir(root) - for subdir in subdirs: - platform = FirefoxPlatformMap.get(subdir, None) - path = os.path.join(root, subdir) - if platform and os.path.isdir(path): - if subdir in ['win32', 'osx_i386']: - pluginsXpiDir = 'plugins' - else: - # Create the XPI directory platform//plugins - pluginsXpiDir = 'platform/%s/plugins' % (platform) - - # Copy the Firefox plugin into this directory. - if subdir.startswith('win32'): - pluginFilename = 'nppanda3d.dll' - elif subdir.startswith('osx'): - pluginFilename = 'nppanda3d.plugin' - else: - pluginFilename = 'nppanda3d.so' - - addZipTree(xpi, os.path.join(path, pluginFilename), - pluginsXpiDir + '/' + pluginFilename) - xpi.close() - - # Now that we've generated the xpi file, get its hash. - data = open('nppanda3d.xpi', 'rb').read() - xpi_hash = sha(data).hexdigest() - - # And now we can generate the update.rdf file. - update = open('update.rdf', 'w') - update.write(update_rdf % { - 'package_id' : package_id, - 'version' : options.version, - 'host_url' : options.host_url, - 'xpi_hash' : xpi_hash, - }) - update.close() - -def addZipTree(zip, sourceFile, zipName): - """ Adds the sourceFile to the zip archive at the indicated name. - If it is a directory, recursively adds all nested files as - well. """ - - if os.path.isdir(sourceFile): - subdirs = os.listdir(sourceFile) - for subdir in subdirs: - addZipTree(zip, os.path.join(sourceFile, subdir), - zipName + '/' + subdir) - - else: - # Not a directory, just add the file. - zip.write(sourceFile, zipName) - -makeXpiFile() - diff --git a/direct/src/plugin_installer/p3d_installer.nsi b/direct/src/plugin_installer/p3d_installer.nsi deleted file mode 100644 index b16c170ca5..0000000000 --- a/direct/src/plugin_installer/p3d_installer.nsi +++ /dev/null @@ -1,300 +0,0 @@ -!include "MUI.nsh" -!include LogicLib.nsh - -; Several variables are assumed to be pre-defined by the caller. See -; make_installer.py in this directory. - -!define UNINSTALL_SUCCESS "$(^Name) was successfully removed from your computer." -!define UNINSTALL_CONFIRM "Are you sure you want to completely remove $(^Name) and all of its components?" -!define UNINSTALL_LINK_NAME "Uninstall" -!define WEBSITE_LINK_NAME "Website" -!define PLID "@panda3d.org/Panda3D Runtime" - -; HM NIS Edit Wizard helper defines -!define APP_INTERNAL_NAME "Panda3D" - -!define PRODUCT_DIR_REGKEY_PANDA3D "Software\Microsoft\Windows\CurrentVersion\App Paths\${PANDA3D}" -!define PRODUCT_DIR_REGKEY_PANDA3DW "Software\Microsoft\Windows\CurrentVersion\App Paths\${PANDA3DW}" -!define PRODUCT_DIR_REGKEY_OCX "Software\Microsoft\Windows\CurrentVersion\App Paths\${OCX}" -!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" -!define PRODUCT_UNINST_ROOT_KEY "HKLM" -!define PROG_GROUPNAME "${PRODUCT_NAME}" - -SetCompressor lzma - -; MUI Settings -!define MUI_ABORTWARNING -!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico" -!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" - -; Welcome page -!define MUI_WELCOMEPAGE_TITLE_3LINES -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_LICENSE "${LICENSE_FILE}" ; EULA -; Directory page -!insertmacro MUI_PAGE_DIRECTORY -; Instfiles page -!insertmacro MUI_PAGE_INSTFILES -; Finish page -;!define MUI_FINISHPAGE_NOAUTOCLOSE ;un-comment to put a pause after the file installation screen -!define MUI_FINISHPAGE_TITLE_3LINES -!insertmacro MUI_PAGE_FINISH - -; Uninstaller pages -!insertmacro MUI_UNPAGE_INSTFILES - -; Language files -!insertmacro MUI_LANGUAGE "English" - -; Reserve files -!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS - -; MUI end ------ - -Name "${PRODUCT_NAME}" -OutFile p3d-setup.exe -InstallDir "${INSTALL_DIR}" -!ifdef INSTALL_ICON - Icon "${INSTALL_ICON}" - UninstallIcon "${INSTALL_ICON}" -!endif -WindowIcon on - -ShowInstDetails show -ShowUnInstDetails show - -Function .onInit -!ifdef REGVIEW - SetRegView ${REGVIEW} -!endif - - ClearErrors - - ReadRegStr $0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "InstallLocation" - - IfErrors +2 0 - StrCpy $INSTDIR $0 - -FunctionEnd - -Section "MainSection" SEC01 - SetShellVarContext all - SetOutPath "$INSTDIR" - SetOverwrite ifdiff - -!ifdef OCX_PATH - File "${OCX_PATH}" -!endif - File "${NPAPI_PATH}" - File "${PANDA3D_PATH}" - File "${PANDA3DW_PATH}" - -; Auto-detected dependencies on the above executables. Python -; computes these values for us. -!ifdef DEP0P - File "${DEP0P}" -!endif -!ifdef DEP1P - File "${DEP1P}" -!endif -!ifdef DEP2P - File "${DEP2P}" -!endif -!ifdef DEP3P - File "${DEP3P}" -!endif -!ifdef DEP4P - File "${DEP4P}" -!endif -!ifdef DEP5P - File "${DEP5P}" -!endif -!ifdef DEP6P - File "${DEP6P}" -!endif -!ifdef DEP7P - File "${DEP7P}" -!endif - -!ifdef ADD_START_MENU -; Start->Programs links - CreateDirectory "$SMPROGRAMS\${PROG_GROUPNAME}" -; CreateShortCut "$SMPROGRAMS\${PROG_GROUPNAME}\${PRODUCT_NAME_SHORT}.lnk" "$INSTDIR\${LAUNCHER}" -!endif - -; Desktop Icon...commented out for now -; CreateShortCut "$DESKTOP\${PRODUCT_NAME_SHORT}.lnk" "$INSTDIR\${OCX}" - - # Make the directory "$INSTDIR" read write accessible by all users - AccessControl::GrantOnFile "$INSTDIR" "(BU)" "FullAccess" - -; File "..\..\..\path\to\file\Example.file" -SectionEnd - -Section -AdditionalIcons - WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}" -!ifdef ADD_START_MENU - CreateShortCut "$SMPROGRAMS\${PROG_GROUPNAME}\${WEBSITE_LINK_NAME}.lnk" "$INSTDIR\${PRODUCT_NAME}.url" - CreateShortCut "$SMPROGRAMS\${PROG_GROUPNAME}\${UNINSTALL_LINK_NAME}.lnk" "$INSTDIR\uninst.exe" -!endif -SectionEnd - -Section -Post -!ifdef REGVIEW - SetRegView ${REGVIEW} -!endif - - WriteUninstaller "$INSTDIR\uninst.exe" - - WriteRegStr HKCR ".p3d" "" "Panda3D applet" - WriteRegStr HKCR ".p3d" "Content Type" "application/x-panda3d" - WriteRegStr HKCR ".p3d" "PerceivedType" "application" - WriteRegStr HKCR "Panda3D applet" "" "Panda3D applet" - WriteRegStr HKCR "Panda3D applet\DefaultIcon" "" "$INSTDIR\${PANDA3DW}" - WriteRegStr HKCR "Panda3D applet\shell" "" "open" - WriteRegStr HKCR "Panda3D applet\shell\open\command" "" '"$INSTDIR\${PANDA3DW}" "%1"' - WriteRegExpandStr HKCR "Panda3D applet\shell\open2" "" "Open &with Command Prompt" - ;WriteRegExpandStr HKCR "Panda3D applet\shell\open2" "MUIVerb" "@%SystemRoot%\System32\wshext.dll,-4511" - WriteRegExpandStr HKCR "Panda3D applet\shell\open2\command" "" '"$INSTDIR\${PANDA3D}" "%1"' - - WriteRegStr HKLM "${PRODUCT_DIR_REGKEY_PANDA3D}" "" "$INSTDIR\${PANDA3D}" - WriteRegStr HKLM "${PRODUCT_DIR_REGKEY_PANDA3DW}" "" "$INSTDIR\${PANDA3DW}" - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe" - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PANDA3D}" - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" - WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "InstallLocation" "$INSTDIR" - WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "NoModify" 1 - WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "NoRepair" 1 - - SectionGetSize SEC01 $0 - WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "EstimatedSize" $0 - - # Delete keys we used in older versions - DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY_OCX}" - DeleteRegKey HKCR "Panda3D applet\shell\edit" -SectionEnd - - -Function un.onUninstSuccess - HideWindow - MessageBox MB_ICONINFORMATION|MB_OK "${UNINSTALL_SUCCESS}" -FunctionEnd - -Function un.onInit - MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "${UNINSTALL_CONFIRM}" IDYES +2 - Abort -FunctionEnd - -Function .onInstSuccess - # Register ActiveX - ExecWait 'regsvr32 /s "$INSTDIR/${OCX}"' - -!ifdef REGVIEW - SetRegView ${REGVIEW} -!endif - - # Register Mozilla Plugin - WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "Description" "Runs 3-D games and interactive applets" - WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "Path" "$INSTDIR\${NPAPI}" - WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "ProductName" "${PRODUCT_NAME_SHORT}" - WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "Vendor" "${PRODUCT_PUBLISHER}" - WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}" "Version" "${PRODUCT_VERSION}" - WriteRegStr HKLM "SOFTWARE\MozillaPlugins\${PLID}\MimeTypes\application/x-panda3d" "Description" "Panda3D applet" - - # Remove old stuff - DeleteRegKey HKLM "SOFTWARE\MozillaPlugins\${PLID},version=0.0" - -FunctionEnd - -Section Uninstall - SetShellVarContext all - - ExecWait 'regsvr32 /u /s "$INSTDIR/${OCX}"' - - Delete "$INSTDIR\${OCX}" - Delete "$INSTDIR\${NPAPI}" - Delete "$INSTDIR\${PANDA3D}" - Delete "$INSTDIR\${PANDA3DW}" -!ifdef DEP0 - Delete "$INSTDIR\${DEP0}" -!endif -!ifdef DEP1 - Delete "$INSTDIR\${DEP1}" -!endif -!ifdef DEP2 - Delete "$INSTDIR\${DEP2}" -!endif -!ifdef DEP3 - Delete "$INSTDIR\${DEP3}" -!endif -!ifdef DEP4 - Delete "$INSTDIR\${DEP4}" -!endif -!ifdef DEP5 - Delete "$INSTDIR\${DEP5}" -!endif -!ifdef DEP6 - Delete "$INSTDIR\${DEP6}" -!endif -!ifdef DEP7 - Delete "$INSTDIR\${DEP7}" -!endif - -!ifdef REGVIEW - SetRegView ${REGVIEW} -!endif - -# The following loop uninstalls the plugin where it may have been -# copied into one of the Mozilla Extensions dirs. Older versions of -# the installer would have done this, but now we just update the -# registry to point to $INSTDIR. -StrCpy $1 "0" -Mozilla-Uninstall-Loop: - EnumRegKey $0 HKLM "SOFTWARE\Mozilla" "$1" - StrCmp $0 "" Mozilla-Uninstall-End - IntOp $1 $1 + 1 - ReadRegStr $2 HKLM "SOFTWARE\Mozilla\$0\Extensions" "Plugins" - ${If} $2 != "" - Delete "$2\${NPAPI}" - # We can't delete the dependency files, because who knows--maybe - # some other plugins are also using the same files. - ${EndIf} - goto Mozilla-Uninstall-Loop -Mozilla-Uninstall-End: - - DeleteRegKey HKLM "SOFTWARE\MozillaPlugins\${PLID}" - DeleteRegKey HKLM "SOFTWARE\MozillaPlugins\${PLID},version=0.0" - - DeleteRegKey HKCR ".p3d" - DeleteRegKey HKCR "Panda3D applet" - - # Remove the user's "Panda3D" directory, where all of the downloaded - # contents are installed. Too bad we can't do this for every system - # user, not just the current user. - - RmDir /r "$LOCALAPPDATALow\${APP_INTERNAL_NAME}" - RmDir /r "$LOCALAPPDATA\${APP_INTERNAL_NAME}" - - Delete "$INSTDIR\uninst.exe" - Delete "$INSTDIR\${PRODUCT_NAME}.url" - -!ifdef ADD_START_MENU - Delete "$SMPROGRAMS\${PROG_GROUPNAME}\${UNINSTALL_LINK_NAME}.lnk" - Delete "$SMPROGRAMS\${PROG_GROUPNAME}\${WEBSITE_LINK_NAME}.lnk" -; Delete "$DESKTOP\${PRODUCT_NAME_SHORT}${PRODUCT_RELEASE}.lnk" -; Delete "$SMPROGRAMS\${PROG_GROUPNAME}\${PRODUCT_NAME_SHORT}.lnk" - RMDir "$SMPROGRAMS\${PROG_GROUPNAME}" -!endif - - RMDir "$INSTDIR" - - DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" - DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY_PANDA3D}" - DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY_PANDA3DW}" - DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY_OCX}" - SetAutoClose true -SectionEnd - diff --git a/direct/src/plugin_npapi/make_osx_bundle.py b/direct/src/plugin_npapi/make_osx_bundle.py deleted file mode 100755 index ce7a102b06..0000000000 --- a/direct/src/plugin_npapi/make_osx_bundle.py +++ /dev/null @@ -1,97 +0,0 @@ -#! /usr/bin/env python - -""" - -This script constructs the bundle directory structure for the OSX web -plugin that is built by the code in this directory. It takes no -parameters, and produces the plugin bundle in the same place. - -""" - -import getopt -import sys -import os -import glob -import shutil - -import direct -from panda3d.core import Filename, DSearchPath - -def usage(code, msg = ''): - sys.stderr.write(__doc__) - sys.stderr.write(msg + '\n') - sys.exit(code) - -def makeBundle(startDir): - fstartDir = Filename.fromOsSpecific(startDir) - - # Search for nppandad along $DYLD_LIBRARY_PATH. - path = DSearchPath() - if 'LD_LIBRARY_PATH' in os.environ: - path.appendPath(os.environ['LD_LIBRARY_PATH']) - if 'DYLD_LIBRARY_PATH' in os.environ: - path.appendPath(os.environ['DYLD_LIBRARY_PATH']) - nppanda3d = path.findFile('nppanda3d') - if not nppanda3d: - raise Exception("Couldn't find nppanda3d on path.") - - # Generate the bundle directory structure - rootFilename = Filename(fstartDir, 'bundle') - - if os.path.exists(rootFilename.toOsSpecific()): - shutil.rmtree(rootFilename.toOsSpecific()) - - bundleFilename = Filename(rootFilename, 'nppanda3d.plugin') - plistFilename = Filename(bundleFilename, 'Contents/Info.plist') - plistFilename.makeDir() - exeFilename = Filename(bundleFilename, 'Contents/MacOS/nppanda3d') - exeFilename.makeDir() - resourceFilename = Filename(bundleFilename, 'Contents/Resources/nppanda3d.rsrc') - resourceFilename.makeDir() - - # Compile the .r file to an .rsrc file. - os.system('/Developer/Tools/Rez -useDF -o %s %s' % ( - resourceFilename.toOsSpecific(), Filename(fstartDir, "nppanda3d.r").toOsSpecific())) - - if not resourceFilename.exists(): - raise IOError('Unable to run Rez') - - # Copy in Info.plist and the compiled executable. - shutil.copyfile(Filename(fstartDir, "nppanda3d.plist").toOsSpecific(), plistFilename.toOsSpecific()) - shutil.copyfile(nppanda3d.toOsSpecific(), exeFilename.toOsSpecific()) - - # All done! - bundleFilename.touch() - print(bundleFilename.toOsSpecific()) - -def buildDmg(startDir): - fstartDir = Filename.fromOsSpecific(startDir) - rootFilename = Filename(fstartDir, 'bundle') - output = Filename(fstartDir, 'nppanda3d.dmg') - output.unlink() - cmd = 'hdiutil create -fs HFS+ -srcfolder "%(dir)s" -volname "%(volname)s" "%(output)s"' % { - 'dir' : rootFilename.toOsSpecific(), - 'volname' : 'nppanda3d', - 'output' : output.toOsSpecific(), - } - os.system(cmd) - -if __name__ == '__main__': - try: - opts, args = getopt.getopt(sys.argv[1:], 'h') - except getopt.error as msg: - usage(1, msg) - - for opt, arg in opts: - if opt == '-h': - usage(0) - - if args: - usage(1, 'No arguments are expected.') - - startDir = os.path.split(sys.argv[0])[0] - makeBundle(startDir) - - # We don't need the dmg these days; the installer is better. - #buildDmg(startDir) - diff --git a/direct/src/plugin_npapi/npapi.h b/direct/src/plugin_npapi/npapi.h deleted file mode 100644 index f34603182d..0000000000 --- a/direct/src/plugin_npapi/npapi.h +++ /dev/null @@ -1,928 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef npapi_h_ -#define npapi_h_ - -#if defined(__OS2__) -#pragma pack(1) -#endif - -#include "nptypes.h" - -#if defined(__OS2__) || defined(OS2) -#ifndef XP_OS2 -#define XP_OS2 1 -#endif -#endif - -#if defined(_WIN32) && !defined(__SYMBIAN32__) -#include -#ifndef XP_WIN -#define XP_WIN 1 -#endif -#endif - -#if defined(__SYMBIAN32__) -#ifndef XP_SYMBIAN -#define XP_SYMBIAN 1 -#undef XP_WIN -#endif -#endif - -#if defined(__APPLE_CC__) && !defined(XP_UNIX) -#ifndef XP_MACOSX -#define XP_MACOSX 1 -#endif -#endif - -#if defined(XP_MACOSX) -#if !defined(NP_NO_OPENGL) -#define NP_NO_OPENGL 1 -#endif /* !defined(NP_NO_OPENGL) */ -#if defined(__LP64__) -#define NP_NO_QUICKDRAW -#define NP_NO_CARBON -#endif /* defined(__LP64__) */ -#endif - -#if defined(XP_MACOSX) -#include -#if !NP_NO_OPENGL -#include -#endif /* !NP_NO_OPENGL */ -#ifndef NP_NO_CARBON -#include -#endif -#endif - -#if defined(XP_UNIX) -#include -#if defined(MOZ_X11) -#include -#include -#endif -#endif - -#if defined(XP_SYMBIAN) -#include -#include -#endif - -/*----------------------------------------------------------------------*/ -/* Plugin Version Constants */ -/*----------------------------------------------------------------------*/ - -#define NP_VERSION_MAJOR 0 -#define NP_VERSION_MINOR 28 - - -/* The OS/2 version of Netscape uses RC_DATA to define the - mime types, file extensions, etc that are required. - Use a vertical bar to separate types, end types with \0. - FileVersion and ProductVersion are 32bit ints, all other - entries are strings that MUST be terminated with a \0. - -AN EXAMPLE: - -RCDATA NP_INFO_ProductVersion { 1,0,0,1,} - -RCDATA NP_INFO_MIMEType { "video/x-video|", - "video/x-flick\0" } -RCDATA NP_INFO_FileExtents { "avi|", - "flc\0" } -RCDATA NP_INFO_FileOpenName{ "MMOS2 video player(*.avi)|", - "MMOS2 Flc/Fli player(*.flc)\0" } - -RCDATA NP_INFO_FileVersion { 1,0,0,1 } -RCDATA NP_INFO_CompanyName { "Netscape Communications\0" } -RCDATA NP_INFO_FileDescription { "NPAVI32 Extension DLL\0" -RCDATA NP_INFO_InternalName { "NPAVI32\0" ) -RCDATA NP_INFO_LegalCopyright { "Copyright Netscape Communications \251 1996\0" -RCDATA NP_INFO_OriginalFilename { "NVAPI32.DLL" } -RCDATA NP_INFO_ProductName { "NPAVI32 Dynamic Link Library\0" } -*/ -/* RC_DATA types for version info - required */ -#define NP_INFO_ProductVersion 1 -#define NP_INFO_MIMEType 2 -#define NP_INFO_FileOpenName 3 -#define NP_INFO_FileExtents 4 -/* RC_DATA types for version info - used if found */ -#define NP_INFO_FileDescription 5 -#define NP_INFO_ProductName 6 -/* RC_DATA types for version info - optional */ -#define NP_INFO_CompanyName 7 -#define NP_INFO_FileVersion 8 -#define NP_INFO_InternalName 9 -#define NP_INFO_LegalCopyright 10 -#define NP_INFO_OriginalFilename 11 - -#ifndef RC_INVOKED - -/*----------------------------------------------------------------------*/ -/* Definition of Basic Types */ -/*----------------------------------------------------------------------*/ - -typedef unsigned char NPBool; -typedef int16_t NPError; -typedef int16_t NPReason; -typedef char* NPMIMEType; - -/*----------------------------------------------------------------------*/ -/* Structures and definitions */ -/*----------------------------------------------------------------------*/ - -#if !defined(__LP64__) -#if defined(XP_MACOSX) -#pragma options align=mac68k -#endif -#endif /* __LP64__ */ - -/* - * NPP is a plug-in's opaque instance handle - */ -typedef struct _NPP -{ - void* pdata; /* plug-in private data */ - void* ndata; /* netscape private data */ -} NPP_t; - -typedef NPP_t* NPP; - -typedef struct _NPStream -{ - void* pdata; /* plug-in private data */ - void* ndata; /* netscape private data */ - const char* url; - uint32_t end; - uint32_t lastmodified; - void* notifyData; - const char* headers; /* Response headers from host. - * Exists only for >= NPVERS_HAS_RESPONSE_HEADERS. - * Used for HTTP only; NULL for non-HTTP. - * Available from NPP_NewStream onwards. - * Plugin should copy this data before storing it. - * Includes HTTP status line and all headers, - * preferably verbatim as received from server, - * headers formatted as in HTTP ("Header: Value"), - * and newlines (\n, NOT \r\n) separating lines. - * Terminated by \n\0 (NOT \n\n\0). */ -} NPStream; - -typedef struct _NPByteRange -{ - int32_t offset; /* negative offset means from the end */ - uint32_t length; - struct _NPByteRange* next; -} NPByteRange; - -typedef struct _NPSavedData -{ - int32_t len; - void* buf; -} NPSavedData; - -typedef struct _NPRect -{ - uint16_t top; - uint16_t left; - uint16_t bottom; - uint16_t right; -} NPRect; - -typedef struct _NPSize -{ - int32_t width; - int32_t height; -} NPSize; - -typedef enum { - NPFocusNext = 0, - NPFocusPrevious = 1 -} NPFocusDirection; - -/* Return values for NPP_HandleEvent */ -#define kNPEventNotHandled 0 -#define kNPEventHandled 1 -/* Exact meaning must be spec'd in event model. */ -#define kNPEventStartIME 2 - -#if defined(XP_UNIX) -/* - * Unix specific structures and definitions - */ - -/* - * Callback Structures. - * - * These are used to pass additional platform specific information. - */ -enum { - NP_SETWINDOW = 1, - NP_PRINT -}; - -typedef struct -{ - int32_t type; -} NPAnyCallbackStruct; - -typedef struct -{ - int32_t type; -#if defined(MOZ_X11) - Display* display; - Visual* visual; - Colormap colormap; - unsigned int depth; -#endif -} NPSetWindowCallbackStruct; - -typedef struct -{ - int32_t type; - FILE* fp; -} NPPrintCallbackStruct; - -#endif /* XP_UNIX */ - -typedef enum { - NPDrawingModelDUMMY -#if defined(XP_MACOSX) -#ifndef NP_NO_QUICKDRAW - , NPDrawingModelQuickDraw = 0 -#endif - , NPDrawingModelCoreGraphics = 1 - , NPDrawingModelOpenGL = 2 - , NPDrawingModelCoreAnimation = 3 - , NPDrawingModelInvalidatingCoreAnimation = 4 -#endif -#if defined(XP_WIN) - , NPDrawingModelSyncWin = 5 -#endif -#if defined(MOZ_X11) - , NPDrawingModelSyncX = 6 -#endif -#if 0 /* OBSOLETE */ - , NPDrawingModelAsyncBitmapSurfaceOBSOLETE = 7 -#if defined(XP_WIN) - , NPDrawingModelAsyncWindowsDXGISurfaceOBSOLETE = 8 -#endif -#endif -} NPDrawingModel; - -#ifdef XP_MACOSX -typedef enum { -#ifndef NP_NO_CARBON - NPEventModelCarbon = 0, -#endif - NPEventModelCocoa = 1 -} NPEventModel; -#endif - -/* - * The following masks are applied on certain platforms to NPNV and - * NPPV selectors that pass around pointers to COM interfaces. Newer - * compilers on some platforms may generate vtables that are not - * compatible with older compilers. To prevent older plugins from - * not understanding a new browser's ABI, these masks change the - * values of those selectors on those platforms. To remain backwards - * compatible with different versions of the browser, plugins can - * use these masks to dynamically determine and use the correct C++ - * ABI that the browser is expecting. This does not apply to Windows - * as Microsoft's COM ABI will likely not change. - */ - -#define NP_ABI_GCC3_MASK 0x10000000 -/* - * gcc 3.x generated vtables on UNIX and OSX are incompatible with - * previous compilers. - */ -#if (defined(XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3)) -#define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK -#else -#define _NP_ABI_MIXIN_FOR_GCC3 0 -#endif - -#if defined(XP_MACOSX) -#define NP_ABI_MACHO_MASK 0x01000000 -#define _NP_ABI_MIXIN_FOR_MACHO NP_ABI_MACHO_MASK -#else -#define _NP_ABI_MIXIN_FOR_MACHO 0 -#endif - -#define NP_ABI_MASK (_NP_ABI_MIXIN_FOR_GCC3 | _NP_ABI_MIXIN_FOR_MACHO) - -/* - * List of variable names for which NPP_GetValue shall be implemented - */ -typedef enum { - NPPVpluginNameString = 1, - NPPVpluginDescriptionString, - NPPVpluginWindowBool, - NPPVpluginTransparentBool, - NPPVjavaClass, - NPPVpluginWindowSize, - NPPVpluginTimerInterval, - NPPVpluginScriptableInstance = (10 | NP_ABI_MASK), - NPPVpluginScriptableIID = 11, - NPPVjavascriptPushCallerBool = 12, - NPPVpluginKeepLibraryInMemory = 13, - NPPVpluginNeedsXEmbed = 14, - - /* Get the NPObject for scripting the plugin. Introduced in NPAPI minor version 14. - */ - NPPVpluginScriptableNPObject = 15, - - /* Get the plugin value (as \0-terminated UTF-8 string data) for - * form submission if the plugin is part of a form. Use - * NPN_MemAlloc() to allocate memory for the string data. Introduced - * in NPAPI minor version 15. - */ - NPPVformValue = 16, - - NPPVpluginUrlRequestsDisplayedBool = 17, - - /* Checks if the plugin is interested in receiving the http body of - * all http requests (including failed ones, http status != 200). - */ - NPPVpluginWantsAllNetworkStreams = 18, - - /* Browsers can retrieve a native ATK accessibility plug ID via this variable. */ - NPPVpluginNativeAccessibleAtkPlugId = 19, - - /* Checks to see if the plug-in would like the browser to load the "src" attribute. */ - NPPVpluginCancelSrcStream = 20, - - NPPVsupportsAdvancedKeyHandling = 21, - - NPPVpluginUsesDOMForCursorBool = 22, - - /* Used for negotiating drawing models */ - NPPVpluginDrawingModel = 1000 -#if defined(XP_MACOSX) - /* Used for negotiating event models */ - , NPPVpluginEventModel = 1001 - /* In the NPDrawingModelCoreAnimation drawing model, the browser asks the plug-in for a Core Animation layer. */ - , NPPVpluginCoreAnimationLayer = 1003 -#endif - -#if defined(MOZ_PLATFORM_MAEMO) && ((MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)) - , NPPVpluginWindowlessLocalBool = 2002 -#endif -} NPPVariable; - -/* - * List of variable names for which NPN_GetValue should be implemented. - */ -typedef enum { - NPNVxDisplay = 1, - NPNVxtAppContext, - NPNVnetscapeWindow, - NPNVjavascriptEnabledBool, - NPNVasdEnabledBool, - NPNVisOfflineBool, - - NPNVserviceManager = (10 | NP_ABI_MASK), - NPNVDOMElement = (11 | NP_ABI_MASK), - NPNVDOMWindow = (12 | NP_ABI_MASK), - NPNVToolkit = (13 | NP_ABI_MASK), - NPNVSupportsXEmbedBool = 14, - - /* Get the NPObject wrapper for the browser window. */ - NPNVWindowNPObject = 15, - - /* Get the NPObject wrapper for the plugins DOM element. */ - NPNVPluginElementNPObject = 16, - - NPNVSupportsWindowless = 17, - - NPNVprivateModeBool = 18, - - NPNVsupportsAdvancedKeyHandling = 21, - - NPNVdocumentOrigin = 22, - - NPNVpluginDrawingModel = 1000 /* Get the current drawing model (NPDrawingModel) */ -#if defined(XP_MACOSX) - , NPNVcontentsScaleFactor = 1001 -#ifndef NP_NO_QUICKDRAW - , NPNVsupportsQuickDrawBool = 2000 -#endif - , NPNVsupportsCoreGraphicsBool = 2001 - , NPNVsupportsOpenGLBool = 2002 - , NPNVsupportsCoreAnimationBool = 2003 - , NPNVsupportsInvalidatingCoreAnimationBool = 2004 -#endif -#if 0 /* OBSOLETE */ - , NPNVsupportsAsyncBitmapSurfaceBoolOBSOLETE = 2007 -#if defined(XP_WIN) - , NPNVsupportsAsyncWindowsDXGISurfaceBoolOBSOLETE = 2008 -#endif -#endif -#if defined(XP_MACOSX) -#ifndef NP_NO_CARBON - , NPNVsupportsCarbonBool = 3000 /* TRUE if the browser supports the Carbon event model */ -#endif - , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */ - , NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated - Cocoa text input specification. */ - , NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports - CA model compositing */ -#endif -#if defined(MOZ_PLATFORM_MAEMO) && ((MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)) - , NPNVSupportsWindowlessLocal = 2002 -#endif -} NPNVariable; - -typedef enum { - NPNURLVCookie = 501, - NPNURLVProxy -} NPNURLVariable; - -/* - * The type of Toolkit the widgets use - */ -typedef enum { - NPNVGtk12 = 1, - NPNVGtk2 -} NPNToolkitType; - -/* - * The type of a NPWindow - it specifies the type of the data structure - * returned in the window field. - */ -typedef enum { - NPWindowTypeWindow = 1, - NPWindowTypeDrawable -} NPWindowType; - -typedef struct _NPWindow -{ - void* window; /* Platform specific window handle */ - /* OS/2: x - Position of bottom left corner */ - /* OS/2: y - relative to visible netscape window */ - int32_t x; /* Position of top left corner relative */ - int32_t y; /* to a netscape page. */ - uint32_t width; /* Maximum window size */ - uint32_t height; - NPRect clipRect; /* Clipping rectangle in port coordinates */ -#if (defined(XP_UNIX) || defined(XP_SYMBIAN)) && !defined(XP_MACOSX) - void * ws_info; /* Platform-dependent additional data */ -#endif /* XP_UNIX */ - NPWindowType type; /* Is this a window or a drawable? */ -} NPWindow; - -typedef struct _NPImageExpose -{ - char* data; /* image pointer */ - int32_t stride; /* Stride of data image pointer */ - int32_t depth; /* Depth of image pointer */ - int32_t x; /* Expose x */ - int32_t y; /* Expose y */ - uint32_t width; /* Expose width */ - uint32_t height; /* Expose height */ - NPSize dataSize; /* Data buffer size */ - float translateX; /* translate X matrix value */ - float translateY; /* translate Y matrix value */ - float scaleX; /* scale X matrix value */ - float scaleY; /* scale Y matrix value */ -} NPImageExpose; - -typedef struct _NPFullPrint -{ - NPBool pluginPrinted;/* Set TRUE if plugin handled fullscreen printing */ - NPBool printOne; /* TRUE if plugin should print one copy to default - printer */ - void* platformPrint; /* Platform-specific printing info */ -} NPFullPrint; - -typedef struct _NPEmbedPrint -{ - NPWindow window; - void* platformPrint; /* Platform-specific printing info */ -} NPEmbedPrint; - -typedef struct _NPPrint -{ - uint16_t mode; /* NP_FULL or NP_EMBED */ - union - { - NPFullPrint fullPrint; /* if mode is NP_FULL */ - NPEmbedPrint embedPrint; /* if mode is NP_EMBED */ - } print; -} NPPrint; - -#if defined(XP_MACOSX) -#ifndef NP_NO_CARBON -typedef EventRecord NPEvent; -#endif -#elif defined(XP_SYMBIAN) -typedef QEvent NPEvent; -#elif defined(XP_WIN) -typedef struct _NPEvent -{ - uint16_t event; - uintptr_t wParam; - uintptr_t lParam; -} NPEvent; -#elif defined(XP_OS2) -typedef struct _NPEvent -{ - uint32_t event; - uint32_t wParam; - uint32_t lParam; -} NPEvent; -#elif defined(XP_UNIX) && defined(MOZ_X11) -typedef XEvent NPEvent; -#else -typedef void* NPEvent; -#endif - -#if defined(XP_MACOSX) -typedef void* NPRegion; -#ifndef NP_NO_QUICKDRAW -typedef RgnHandle NPQDRegion; -#endif -typedef CGPathRef NPCGRegion; -#elif defined(XP_WIN) -typedef HRGN NPRegion; -#elif defined(XP_UNIX) && defined(MOZ_X11) -typedef Region NPRegion; -#elif defined(XP_SYMBIAN) -typedef QRegion* NPRegion; -#else -typedef void *NPRegion; -#endif - -typedef struct _NPNSString NPNSString; -typedef struct _NPNSWindow NPNSWindow; -typedef struct _NPNSMenu NPNSMenu; - -#if defined(XP_MACOSX) -typedef NPNSMenu NPMenu; -#else -typedef void *NPMenu; -#endif - -typedef enum { - NPCoordinateSpacePlugin = 1, - NPCoordinateSpaceWindow, - NPCoordinateSpaceFlippedWindow, - NPCoordinateSpaceScreen, - NPCoordinateSpaceFlippedScreen -} NPCoordinateSpace; - -#if defined(XP_MACOSX) - -#ifndef NP_NO_QUICKDRAW -typedef struct NP_Port -{ - CGrafPtr port; - int32_t portx; /* position inside the topmost window */ - int32_t porty; -} NP_Port; -#endif /* NP_NO_QUICKDRAW */ - -/* - * NP_CGContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelCoreGraphics - * as its drawing model. - */ - -typedef struct NP_CGContext -{ - CGContextRef context; - void *window; /* A WindowRef under the Carbon event model. */ -} NP_CGContext; - -/* - * NP_GLContext is the type of the NPWindow's 'window' when the plugin specifies NPDrawingModelOpenGL as its - * drawing model. - */ - -#if !NP_NO_OPENGL -typedef struct NP_GLContext -{ - CGLContextObj context; -#ifdef NP_NO_CARBON - NPNSWindow *window; -#else - void *window; /* Can be either an NSWindow or a WindowRef depending on the event model */ -#endif -} NP_GLContext; -#endif /* !NP_NO_OPENGL */ - -typedef enum { - NPCocoaEventDrawRect = 1, - NPCocoaEventMouseDown, - NPCocoaEventMouseUp, - NPCocoaEventMouseMoved, - NPCocoaEventMouseEntered, - NPCocoaEventMouseExited, - NPCocoaEventMouseDragged, - NPCocoaEventKeyDown, - NPCocoaEventKeyUp, - NPCocoaEventFlagsChanged, - NPCocoaEventFocusChanged, - NPCocoaEventWindowFocusChanged, - NPCocoaEventScrollWheel, - NPCocoaEventTextInput -} NPCocoaEventType; - -typedef struct _NPCocoaEvent { - NPCocoaEventType type; - uint32_t version; - union { - struct { - uint32_t modifierFlags; - double pluginX; - double pluginY; - int32_t buttonNumber; - int32_t clickCount; - double deltaX; - double deltaY; - double deltaZ; - } mouse; - struct { - uint32_t modifierFlags; - NPNSString *characters; - NPNSString *charactersIgnoringModifiers; - NPBool isARepeat; - uint16_t keyCode; - } key; - struct { - CGContextRef context; - double x; - double y; - double width; - double height; - } draw; - struct { - NPBool hasFocus; - } focus; - struct { - NPNSString *text; - } text; - } data; -} NPCocoaEvent; - -#ifndef NP_NO_CARBON -/* Non-standard event types that can be passed to HandleEvent */ -enum NPEventType { - NPEventType_GetFocusEvent = (osEvt + 16), - NPEventType_LoseFocusEvent, - NPEventType_AdjustCursorEvent, - NPEventType_MenuCommandEvent, - NPEventType_ClippingChangedEvent, - NPEventType_ScrollingBeginsEvent = 1000, - NPEventType_ScrollingEndsEvent -}; -#endif /* NP_NO_CARBON */ - -#endif /* XP_MACOSX */ - -/* - * Values for mode passed to NPP_New: - */ -#define NP_EMBED 1 -#define NP_FULL 2 - -/* - * Values for stream type passed to NPP_NewStream: - */ -#define NP_NORMAL 1 -#define NP_SEEK 2 -#define NP_ASFILE 3 -#define NP_ASFILEONLY 4 - -#define NP_MAXREADY (((unsigned)(~0)<<1)>>1) - -/* - * Flags for NPP_ClearSiteData. - */ -#define NP_CLEAR_ALL 0 -#define NP_CLEAR_CACHE (1 << 0) - -#if !defined(__LP64__) -#if defined(XP_MACOSX) -#pragma options align=reset -#endif -#endif /* __LP64__ */ - -/*----------------------------------------------------------------------*/ -/* Error and Reason Code definitions */ -/*----------------------------------------------------------------------*/ - -/* - * Values of type NPError: - */ -#define NPERR_BASE 0 -#define NPERR_NO_ERROR (NPERR_BASE + 0) -#define NPERR_GENERIC_ERROR (NPERR_BASE + 1) -#define NPERR_INVALID_INSTANCE_ERROR (NPERR_BASE + 2) -#define NPERR_INVALID_FUNCTABLE_ERROR (NPERR_BASE + 3) -#define NPERR_MODULE_LOAD_FAILED_ERROR (NPERR_BASE + 4) -#define NPERR_OUT_OF_MEMORY_ERROR (NPERR_BASE + 5) -#define NPERR_INVALID_PLUGIN_ERROR (NPERR_BASE + 6) -#define NPERR_INVALID_PLUGIN_DIR_ERROR (NPERR_BASE + 7) -#define NPERR_INCOMPATIBLE_VERSION_ERROR (NPERR_BASE + 8) -#define NPERR_INVALID_PARAM (NPERR_BASE + 9) -#define NPERR_INVALID_URL (NPERR_BASE + 10) -#define NPERR_FILE_NOT_FOUND (NPERR_BASE + 11) -#define NPERR_NO_DATA (NPERR_BASE + 12) -#define NPERR_STREAM_NOT_SEEKABLE (NPERR_BASE + 13) -#define NPERR_TIME_RANGE_NOT_SUPPORTED (NPERR_BASE + 14) -#define NPERR_MALFORMED_SITE (NPERR_BASE + 15) - -/* - * Values of type NPReason: - */ -#define NPRES_BASE 0 -#define NPRES_DONE (NPRES_BASE + 0) -#define NPRES_NETWORK_ERR (NPRES_BASE + 1) -#define NPRES_USER_BREAK (NPRES_BASE + 2) - -/* - * Don't use these obsolete error codes any more. - */ -#define NP_NOERR NP_NOERR_is_obsolete_use_NPERR_NO_ERROR -#define NP_EINVAL NP_EINVAL_is_obsolete_use_NPERR_GENERIC_ERROR -#define NP_EABORT NP_EABORT_is_obsolete_use_NPRES_USER_BREAK - -/* - * Version feature information - */ -#define NPVERS_HAS_STREAMOUTPUT 8 -#define NPVERS_HAS_NOTIFICATION 9 -#define NPVERS_HAS_LIVECONNECT 9 -#define NPVERS_68K_HAS_LIVECONNECT 11 -#define NPVERS_HAS_WINDOWLESS 11 -#define NPVERS_HAS_XPCONNECT_SCRIPTING 13 -#define NPVERS_HAS_NPRUNTIME_SCRIPTING 14 -#define NPVERS_HAS_FORM_VALUES 15 -#define NPVERS_HAS_POPUPS_ENABLED_STATE 16 -#define NPVERS_HAS_RESPONSE_HEADERS 17 -#define NPVERS_HAS_NPOBJECT_ENUM 18 -#define NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL 19 -#define NPVERS_HAS_ALL_NETWORK_STREAMS 20 -#define NPVERS_HAS_URL_AND_AUTH_INFO 21 -#define NPVERS_HAS_PRIVATE_MODE 22 -#define NPVERS_MACOSX_HAS_COCOA_EVENTS 23 -#define NPVERS_HAS_ADVANCED_KEY_HANDLING 25 -#define NPVERS_HAS_URL_REDIRECT_HANDLING 26 -#define NPVERS_HAS_CLEAR_SITE_DATA 27 - -/*----------------------------------------------------------------------*/ -/* Function Prototypes */ -/*----------------------------------------------------------------------*/ - -#if defined(__OS2__) -#define NP_LOADDS _System -#else -#define NP_LOADDS -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* NPP_* functions are provided by the plugin and called by the navigator. */ - -#if defined(XP_UNIX) -const char* NPP_GetMIMEDescription(void); -#endif - -NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance, - uint16_t mode, int16_t argc, char* argn[], - char* argv[], NPSavedData* saved); -NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData** save); -NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window); -NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type, - NPStream* stream, NPBool seekable, - uint16_t* stype); -NPError NP_LOADDS NPP_DestroyStream(NPP instance, NPStream* stream, - NPReason reason); -int32_t NP_LOADDS NPP_WriteReady(NPP instance, NPStream* stream); -int32_t NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32_t offset, - int32_t len, void* buffer); -void NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream, - const char* fname); -void NP_LOADDS NPP_Print(NPP instance, NPPrint* platformPrint); -int16_t NP_LOADDS NPP_HandleEvent(NPP instance, void* event); -void NP_LOADDS NPP_URLNotify(NPP instance, const char* url, - NPReason reason, void* notifyData); -NPError NP_LOADDS NPP_GetValue(NPP instance, NPPVariable variable, void *value); -NPError NP_LOADDS NPP_SetValue(NPP instance, NPNVariable variable, void *value); -NPBool NP_LOADDS NPP_GotFocus(NPP instance, NPFocusDirection direction); -void NP_LOADDS NPP_LostFocus(NPP instance); -void NP_LOADDS NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status, void* notifyData); -NPError NP_LOADDS NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge); -char** NP_LOADDS NPP_GetSitesWithData(void); -void NP_LOADDS NPP_DidComposite(NPP instance); - -/* NPN_* functions are provided by the navigator and called by the plugin. */ -void NP_LOADDS NPN_Version(int* plugin_major, int* plugin_minor, - int* netscape_major, int* netscape_minor); -NPError NP_LOADDS NPN_GetURLNotify(NPP instance, const char* url, - const char* target, void* notifyData); -NPError NP_LOADDS NPN_GetURL(NPP instance, const char* url, - const char* target); -NPError NP_LOADDS NPN_PostURLNotify(NPP instance, const char* url, - const char* target, uint32_t len, - const char* buf, NPBool file, - void* notifyData); -NPError NP_LOADDS NPN_PostURL(NPP instance, const char* url, - const char* target, uint32_t len, - const char* buf, NPBool file); -NPError NP_LOADDS NPN_RequestRead(NPStream* stream, NPByteRange* rangeList); -NPError NP_LOADDS NPN_NewStream(NPP instance, NPMIMEType type, - const char* target, NPStream** stream); -int32_t NP_LOADDS NPN_Write(NPP instance, NPStream* stream, int32_t len, - void* buffer); -NPError NP_LOADDS NPN_DestroyStream(NPP instance, NPStream* stream, - NPReason reason); -void NP_LOADDS NPN_Status(NPP instance, const char* message); -const char* NP_LOADDS NPN_UserAgent(NPP instance); -void* NP_LOADDS NPN_MemAlloc(uint32_t size); -void NP_LOADDS NPN_MemFree(void* ptr); -uint32_t NP_LOADDS NPN_MemFlush(uint32_t size); -void NP_LOADDS NPN_ReloadPlugins(NPBool reloadPages); -NPError NP_LOADDS NPN_GetValue(NPP instance, NPNVariable variable, - void *value); -NPError NP_LOADDS NPN_SetValue(NPP instance, NPPVariable variable, - void *value); -void NP_LOADDS NPN_InvalidateRect(NPP instance, NPRect *invalidRect); -void NP_LOADDS NPN_InvalidateRegion(NPP instance, - NPRegion invalidRegion); -void NP_LOADDS NPN_ForceRedraw(NPP instance); -void NP_LOADDS NPN_PushPopupsEnabledState(NPP instance, NPBool enabled); -void NP_LOADDS NPN_PopPopupsEnabledState(NPP instance); -void NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance, - void (*func) (void *), - void *userData); -NPError NP_LOADDS NPN_GetValueForURL(NPP instance, NPNURLVariable variable, - const char *url, char **value, - uint32_t *len); -NPError NP_LOADDS NPN_SetValueForURL(NPP instance, NPNURLVariable variable, - const char *url, const char *value, - uint32_t len); -NPError NP_LOADDS NPN_GetAuthenticationInfo(NPP instance, - const char *protocol, - const char *host, int32_t port, - const char *scheme, - const char *realm, - char **username, uint32_t *ulen, - char **password, - uint32_t *plen); -uint32_t NP_LOADDS NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID)); -void NP_LOADDS NPN_UnscheduleTimer(NPP instance, uint32_t timerID); -NPError NP_LOADDS NPN_PopUpContextMenu(NPP instance, NPMenu* menu); -NPBool NP_LOADDS NPN_ConvertPoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace); -NPBool NP_LOADDS NPN_HandleEvent(NPP instance, void *event, NPBool handled); -NPBool NP_LOADDS NPN_UnfocusInstance(NPP instance, NPFocusDirection direction); -void NP_LOADDS NPN_URLRedirectResponse(NPP instance, void* notifyData, NPBool allow); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* RC_INVOKED */ -#if defined(__OS2__) -#pragma pack() -#endif - -#endif /* npapi_h_ */ diff --git a/direct/src/plugin_npapi/npfunctions.h b/direct/src/plugin_npapi/npfunctions.h deleted file mode 100644 index a40e402dca..0000000000 --- a/direct/src/plugin_npapi/npfunctions.h +++ /dev/null @@ -1,329 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef npfunctions_h_ -#define npfunctions_h_ - -#ifdef __OS2__ -#pragma pack(1) -#define NP_LOADDS _System -#else -#define NP_LOADDS -#endif - -#include "npapi.h" -#include "npruntime.h" - -typedef NPError (* NP_LOADDS NPP_NewProcPtr)(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved); -typedef NPError (* NP_LOADDS NPP_DestroyProcPtr)(NPP instance, NPSavedData** save); -typedef NPError (* NP_LOADDS NPP_SetWindowProcPtr)(NPP instance, NPWindow* window); -typedef NPError (* NP_LOADDS NPP_NewStreamProcPtr)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype); -typedef NPError (* NP_LOADDS NPP_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason); -typedef int32_t (* NP_LOADDS NPP_WriteReadyProcPtr)(NPP instance, NPStream* stream); -typedef int32_t (* NP_LOADDS NPP_WriteProcPtr)(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer); -typedef void (* NP_LOADDS NPP_StreamAsFileProcPtr)(NPP instance, NPStream* stream, const char* fname); -typedef void (* NP_LOADDS NPP_PrintProcPtr)(NPP instance, NPPrint* platformPrint); -typedef int16_t (* NP_LOADDS NPP_HandleEventProcPtr)(NPP instance, void* event); -typedef void (* NP_LOADDS NPP_URLNotifyProcPtr)(NPP instance, const char* url, NPReason reason, void* notifyData); -/* Any NPObjects returned to the browser via NPP_GetValue should be retained - by the plugin on the way out. The browser is responsible for releasing. */ -typedef NPError (* NP_LOADDS NPP_GetValueProcPtr)(NPP instance, NPPVariable variable, void *ret_value); -typedef NPError (* NP_LOADDS NPP_SetValueProcPtr)(NPP instance, NPNVariable variable, void *value); -typedef NPBool (* NP_LOADDS NPP_GotFocusPtr)(NPP instance, NPFocusDirection direction); -typedef void (* NP_LOADDS NPP_LostFocusPtr)(NPP instance); -typedef void (* NP_LOADDS NPP_URLRedirectNotifyPtr)(NPP instance, const char* url, int32_t status, void* notifyData); -typedef NPError (* NP_LOADDS NPP_ClearSiteDataPtr)(const char* site, uint64_t flags, uint64_t maxAge); -typedef char** (* NP_LOADDS NPP_GetSitesWithDataPtr)(void); -typedef void (* NP_LOADDS NPP_DidCompositePtr)(NPP instance); - -typedef NPError (* NP_LOADDS NPN_GetValueProcPtr)(NPP instance, NPNVariable variable, void *ret_value); -typedef NPError (* NP_LOADDS NPN_SetValueProcPtr)(NPP instance, NPPVariable variable, void *value); -typedef NPError (* NP_LOADDS NPN_GetURLNotifyProcPtr)(NPP instance, const char* url, const char* window, void* notifyData); -typedef NPError (* NP_LOADDS NPN_PostURLNotifyProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, const char* buf, NPBool file, void* notifyData); -typedef NPError (* NP_LOADDS NPN_GetURLProcPtr)(NPP instance, const char* url, const char* window); -typedef NPError (* NP_LOADDS NPN_PostURLProcPtr)(NPP instance, const char* url, const char* window, uint32_t len, const char* buf, NPBool file); -typedef NPError (* NP_LOADDS NPN_RequestReadProcPtr)(NPStream* stream, NPByteRange* rangeList); -typedef NPError (* NP_LOADDS NPN_NewStreamProcPtr)(NPP instance, NPMIMEType type, const char* window, NPStream** stream); -typedef int32_t (* NP_LOADDS NPN_WriteProcPtr)(NPP instance, NPStream* stream, int32_t len, void* buffer); -typedef NPError (* NP_LOADDS NPN_DestroyStreamProcPtr)(NPP instance, NPStream* stream, NPReason reason); -typedef void (* NP_LOADDS NPN_StatusProcPtr)(NPP instance, const char* message); -/* Browser manages the lifetime of the buffer returned by NPN_UserAgent, don't - depend on it sticking around and don't free it. */ -typedef const char* (* NP_LOADDS NPN_UserAgentProcPtr)(NPP instance); -typedef void* (* NP_LOADDS NPN_MemAllocProcPtr)(uint32_t size); -typedef void (* NP_LOADDS NPN_MemFreeProcPtr)(void* ptr); -typedef uint32_t (* NP_LOADDS NPN_MemFlushProcPtr)(uint32_t size); -typedef void (* NP_LOADDS NPN_ReloadPluginsProcPtr)(NPBool reloadPages); -typedef void* (* NP_LOADDS NPN_GetJavaEnvProcPtr)(void); -typedef void* (* NP_LOADDS NPN_GetJavaPeerProcPtr)(NPP instance); -typedef void (* NP_LOADDS NPN_InvalidateRectProcPtr)(NPP instance, NPRect *rect); -typedef void (* NP_LOADDS NPN_InvalidateRegionProcPtr)(NPP instance, NPRegion region); -typedef void (* NP_LOADDS NPN_ForceRedrawProcPtr)(NPP instance); -typedef NPIdentifier (* NP_LOADDS NPN_GetStringIdentifierProcPtr)(const NPUTF8* name); -typedef void (* NP_LOADDS NPN_GetStringIdentifiersProcPtr)(const NPUTF8** names, int32_t nameCount, NPIdentifier* identifiers); -typedef NPIdentifier (* NP_LOADDS NPN_GetIntIdentifierProcPtr)(int32_t intid); -typedef bool (* NP_LOADDS NPN_IdentifierIsStringProcPtr)(NPIdentifier identifier); -typedef NPUTF8* (* NP_LOADDS NPN_UTF8FromIdentifierProcPtr)(NPIdentifier identifier); -typedef int32_t (* NP_LOADDS NPN_IntFromIdentifierProcPtr)(NPIdentifier identifier); -typedef NPObject* (* NP_LOADDS NPN_CreateObjectProcPtr)(NPP npp, NPClass *aClass); -typedef NPObject* (* NP_LOADDS NPN_RetainObjectProcPtr)(NPObject *obj); -typedef void (* NP_LOADDS NPN_ReleaseObjectProcPtr)(NPObject *obj); -typedef bool (* NP_LOADDS NPN_InvokeProcPtr)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result); -typedef bool (* NP_LOADDS NPN_InvokeDefaultProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result); -typedef bool (* NP_LOADDS NPN_EvaluateProcPtr)(NPP npp, NPObject *obj, NPString *script, NPVariant *result); -typedef bool (* NP_LOADDS NPN_GetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result); -typedef bool (* NP_LOADDS NPN_SetPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value); -typedef bool (* NP_LOADDS NPN_RemovePropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName); -typedef bool (* NP_LOADDS NPN_HasPropertyProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName); -typedef bool (* NP_LOADDS NPN_HasMethodProcPtr)(NPP npp, NPObject *obj, NPIdentifier propertyName); -typedef void (* NP_LOADDS NPN_ReleaseVariantValueProcPtr)(NPVariant *variant); -typedef void (* NP_LOADDS NPN_SetExceptionProcPtr)(NPObject *obj, const NPUTF8 *message); -typedef void (* NP_LOADDS NPN_PushPopupsEnabledStateProcPtr)(NPP npp, NPBool enabled); -typedef void (* NP_LOADDS NPN_PopPopupsEnabledStateProcPtr)(NPP npp); -typedef bool (* NP_LOADDS NPN_EnumerateProcPtr)(NPP npp, NPObject *obj, NPIdentifier **identifier, uint32_t *count); -typedef void (* NP_LOADDS NPN_PluginThreadAsyncCallProcPtr)(NPP instance, void (*func)(void *), void *userData); -typedef bool (* NP_LOADDS NPN_ConstructProcPtr)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result); -typedef NPError (* NP_LOADDS NPN_GetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, char **value, uint32_t *len); -typedef NPError (* NP_LOADDS NPN_SetValueForURLPtr)(NPP npp, NPNURLVariable variable, const char *url, const char *value, uint32_t len); -typedef NPError (* NP_LOADDS NPN_GetAuthenticationInfoPtr)(NPP npp, const char *protocol, const char *host, int32_t port, const char *scheme, const char *realm, char **username, uint32_t *ulen, char **password, uint32_t *plen); -typedef uint32_t (* NP_LOADDS NPN_ScheduleTimerPtr)(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID)); -typedef void (* NP_LOADDS NPN_UnscheduleTimerPtr)(NPP instance, uint32_t timerID); -typedef NPError (* NP_LOADDS NPN_PopUpContextMenuPtr)(NPP instance, NPMenu* menu); -typedef NPBool (* NP_LOADDS NPN_ConvertPointPtr)(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace); -typedef NPBool (* NP_LOADDS NPN_HandleEventPtr)(NPP instance, void *event, NPBool handled); -typedef NPBool (* NP_LOADDS NPN_UnfocusInstancePtr)(NPP instance, NPFocusDirection direction); -typedef void (* NP_LOADDS NPN_URLRedirectResponsePtr)(NPP instance, void* notifyData, NPBool allow); - -typedef void (* NP_LOADDS NPN_DummyPtr)(void); - -typedef struct _NPPluginFuncs { - uint16_t size; - uint16_t version; - NPP_NewProcPtr newp; - NPP_DestroyProcPtr destroy; - NPP_SetWindowProcPtr setwindow; - NPP_NewStreamProcPtr newstream; - NPP_DestroyStreamProcPtr destroystream; - NPP_StreamAsFileProcPtr asfile; - NPP_WriteReadyProcPtr writeready; - NPP_WriteProcPtr write; - NPP_PrintProcPtr print; - NPP_HandleEventProcPtr event; - NPP_URLNotifyProcPtr urlnotify; - void* javaClass; - NPP_GetValueProcPtr getvalue; - NPP_SetValueProcPtr setvalue; - NPP_GotFocusPtr gotfocus; - NPP_LostFocusPtr lostfocus; - NPP_URLRedirectNotifyPtr urlredirectnotify; - NPP_ClearSiteDataPtr clearsitedata; - NPP_GetSitesWithDataPtr getsiteswithdata; - NPP_DidCompositePtr didComposite; -} NPPluginFuncs; - -typedef struct _NPNetscapeFuncs { - uint16_t size; - uint16_t version; - NPN_GetURLProcPtr geturl; - NPN_PostURLProcPtr posturl; - NPN_RequestReadProcPtr requestread; - NPN_NewStreamProcPtr newstream; - NPN_WriteProcPtr write; - NPN_DestroyStreamProcPtr destroystream; - NPN_StatusProcPtr status; - NPN_UserAgentProcPtr uagent; - NPN_MemAllocProcPtr memalloc; - NPN_MemFreeProcPtr memfree; - NPN_MemFlushProcPtr memflush; - NPN_ReloadPluginsProcPtr reloadplugins; - NPN_GetJavaEnvProcPtr getJavaEnv; - NPN_GetJavaPeerProcPtr getJavaPeer; - NPN_GetURLNotifyProcPtr geturlnotify; - NPN_PostURLNotifyProcPtr posturlnotify; - NPN_GetValueProcPtr getvalue; - NPN_SetValueProcPtr setvalue; - NPN_InvalidateRectProcPtr invalidaterect; - NPN_InvalidateRegionProcPtr invalidateregion; - NPN_ForceRedrawProcPtr forceredraw; - NPN_GetStringIdentifierProcPtr getstringidentifier; - NPN_GetStringIdentifiersProcPtr getstringidentifiers; - NPN_GetIntIdentifierProcPtr getintidentifier; - NPN_IdentifierIsStringProcPtr identifierisstring; - NPN_UTF8FromIdentifierProcPtr utf8fromidentifier; - NPN_IntFromIdentifierProcPtr intfromidentifier; - NPN_CreateObjectProcPtr createobject; - NPN_RetainObjectProcPtr retainobject; - NPN_ReleaseObjectProcPtr releaseobject; - NPN_InvokeProcPtr invoke; - NPN_InvokeDefaultProcPtr invokeDefault; - NPN_EvaluateProcPtr evaluate; - NPN_GetPropertyProcPtr getproperty; - NPN_SetPropertyProcPtr setproperty; - NPN_RemovePropertyProcPtr removeproperty; - NPN_HasPropertyProcPtr hasproperty; - NPN_HasMethodProcPtr hasmethod; - NPN_ReleaseVariantValueProcPtr releasevariantvalue; - NPN_SetExceptionProcPtr setexception; - NPN_PushPopupsEnabledStateProcPtr pushpopupsenabledstate; - NPN_PopPopupsEnabledStateProcPtr poppopupsenabledstate; - NPN_EnumerateProcPtr enumerate; - NPN_PluginThreadAsyncCallProcPtr pluginthreadasynccall; - NPN_ConstructProcPtr construct; - NPN_GetValueForURLPtr getvalueforurl; - NPN_SetValueForURLPtr setvalueforurl; - NPN_GetAuthenticationInfoPtr getauthenticationinfo; - NPN_ScheduleTimerPtr scheduletimer; - NPN_UnscheduleTimerPtr unscheduletimer; - NPN_PopUpContextMenuPtr popupcontextmenu; - NPN_ConvertPointPtr convertpoint; - NPN_HandleEventPtr handleevent; - NPN_UnfocusInstancePtr unfocusinstance; - NPN_URLRedirectResponsePtr urlredirectresponse; - NPN_DummyPtr initasyncsurfaceOBSOLETE; - NPN_DummyPtr finalizeasyncsurfaceOBSOLETE; - NPN_DummyPtr setcurrentasyncsurfaceOBSOLETE; -} NPNetscapeFuncs; - -#ifdef XP_MACOSX -/* - * Mac OS X version(s) of NP_GetMIMEDescription(const char *) - * These can be called to retreive MIME information from the plugin dynamically - * - * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way - * to get mime info from the plugin only on OSX and may not be supported - * in furture version -- use NP_GetMIMEDescription instead - */ -enum -{ - kBPSupportedMIMETypesStructVers_1 = 1 -}; -typedef struct _BPSupportedMIMETypes -{ - SInt32 structVersion; /* struct version */ - Handle typeStrings; /* STR# formated handle, allocated by plug-in */ - Handle infoStrings; /* STR# formated handle, allocated by plug-in */ -} BPSupportedMIMETypes; -OSErr BP_GetSupportedMIMETypes(BPSupportedMIMETypes *mimeInfo, UInt32 flags); -#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescription" -typedef const char* (*NP_GetMIMEDescriptionProcPtr)(void); -typedef OSErr (*BP_GetSupportedMIMETypesProcPtr)(BPSupportedMIMETypes*, UInt32); -#endif - -#if defined(_WIN32) -#define OSCALL WINAPI -#else -#if defined(__OS2__) -#define OSCALL _System -#else -#define OSCALL -#endif -#endif - -#if defined(XP_UNIX) -/* GCC 3.3 and later support the visibility attribute. */ -#if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) -#define NP_VISIBILITY_DEFAULT __attribute__((visibility("default"))) -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) -#define NP_VISIBILITY_DEFAULT __global -#else -#define NP_VISIBILITY_DEFAULT -#endif -#define NP_EXPORT(__type) NP_VISIBILITY_DEFAULT __type -#endif - -#if defined(_WIN32) || defined (__OS2__) -#ifdef __cplusplus -extern "C" { -#endif -/* plugin meta member functions */ -#if defined(__OS2__) -typedef struct _NPPluginData { /* Alternate OS2 Plugin interface */ - char *pMimeTypes; - char *pFileExtents; - char *pFileOpenTemplate; - char *pProductName; - char *pProductDescription; - unsigned long dwProductVersionMS; - unsigned long dwProductVersionLS; -} NPPluginData; -typedef NPError (OSCALL *NP_GetPluginDataFunc)(NPPluginData*); -NPError OSCALL NP_GetPluginData(NPPluginData * pPluginData); -#endif -typedef NPError (OSCALL *NP_GetEntryPointsFunc)(NPPluginFuncs*); -NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs); -typedef NPError (OSCALL *NP_InitializeFunc)(NPNetscapeFuncs*); -NPError OSCALL NP_Initialize(NPNetscapeFuncs* bFuncs); -typedef NPError (OSCALL *NP_ShutdownFunc)(void); -NPError OSCALL NP_Shutdown(void); -typedef const char* (*NP_GetMIMEDescriptionFunc)(void); -const char* NP_GetMIMEDescription(void); -#ifdef __cplusplus -} -#endif -#endif - -#if defined(__OS2__) -#pragma pack() -#endif - -#ifdef XP_UNIX -#ifdef __cplusplus -extern "C" { -#endif -typedef char* (*NP_GetPluginVersionFunc)(void); -NP_EXPORT(char*) NP_GetPluginVersion(void); -typedef const char* (*NP_GetMIMEDescriptionFunc)(void); -NP_EXPORT(const char*) NP_GetMIMEDescription(void); -#ifdef XP_MACOSX -typedef NPError (*NP_InitializeFunc)(NPNetscapeFuncs*); -NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs); -typedef NPError (*NP_GetEntryPointsFunc)(NPPluginFuncs*); -NP_EXPORT(NPError) NP_GetEntryPoints(NPPluginFuncs* pFuncs); -#else -typedef NPError (*NP_InitializeFunc)(NPNetscapeFuncs*, NPPluginFuncs*); -NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs); -#endif -typedef NPError (*NP_ShutdownFunc)(void); -NP_EXPORT(NPError) NP_Shutdown(void); -typedef NPError (*NP_GetValueFunc)(void *, NPPVariable, void *); -NP_EXPORT(NPError) NP_GetValue(void *future, NPPVariable aVariable, void *aValue); -#ifdef __cplusplus -} -#endif -#endif - -#endif /* npfunctions_h_ */ diff --git a/direct/src/plugin_npapi/nppanda3d.def b/direct/src/plugin_npapi/nppanda3d.def deleted file mode 100644 index ee2da2e02e..0000000000 --- a/direct/src/plugin_npapi/nppanda3d.def +++ /dev/null @@ -1,9 +0,0 @@ -; This file is required on Windows to export the appropriate symbols -; from the DLL. - -LIBRARY nppanda3d - -EXPORTS - NP_GetEntryPoints @1 - NP_Initialize @2 - NP_Shutdown @3 diff --git a/direct/src/plugin_npapi/nppanda3d.plist b/direct/src/plugin_npapi/nppanda3d.plist deleted file mode 100644 index 73c6745d02..0000000000 --- a/direct/src/plugin_npapi/nppanda3d.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en-US - CFBundleExecutable - nppanda3d - CFBundleIdentifier - org.panda3d.nppanda3d - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - Panda3D - CFBundlePackageType - BRPL - CFBundleVersion - 1.0 - WebPluginName - Panda3D Game Engine Plug-In - WebPluginDescription - Runs 3-D games and interactive applets - WebPluginMIMETypes - - application/x-panda3d - - WebPluginExtensions - - p3d - - WebPluginTypeDescription - Panda3D applet - - - - diff --git a/direct/src/plugin_npapi/nppanda3d.r b/direct/src/plugin_npapi/nppanda3d.r deleted file mode 100644 index 6768adc357..0000000000 --- a/direct/src/plugin_npapi/nppanda3d.r +++ /dev/null @@ -1,19 +0,0 @@ -/* Apparently Firefox ignores the Info.plist file, - and looks only in the .rsrc file within the bundle, - which is compiled from the following source file. */ - -#include - -resource 'STR#' (126) { - { "Runs 3-D games and interactive applets", - "Panda3D Game Engine Plug-In" } -}; - -resource 'STR#' (127) { - { "Panda3D applet" } -}; - -resource 'STR#' (128) { - { "application/x-panda3d", "p3d" } -}; - diff --git a/direct/src/plugin_npapi/nppanda3d_common.h b/direct/src/plugin_npapi/nppanda3d_common.h deleted file mode 100644 index e6eeca6d99..0000000000 --- a/direct/src/plugin_npapi/nppanda3d_common.h +++ /dev/null @@ -1,118 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file nppanda3d_common.h - * @author drose - * @date 2009-06-19 - */ - -#ifndef NPPANDA3D_COMMON -#define NPPANDA3D_COMMON - -// This header file is included by all C++ files in this directory - -// It's a good idea to pick up this header file, even though we don't actually -// link with dtool. This header file defines useful system-wide config -// settings. -#include "dtool_config.h" - -// We include this header file directly out of its source directory, so we -// don't have to link with the library that builds it. -#include "../plugin/p3d_plugin.h" - -#include -#include -#include -#include - -// Appears in startup.cxx. -extern std::ostream *nout_stream; -#define nout (*nout_stream) - -extern std::string global_root_dir; -extern bool has_plugin_thread_async_call; - -#ifdef _WIN32 - -// Gecko requires all these symbols to be defined for Windows. -#define MOZILLA_STRICT_API -#define XP_WIN -#define _X86_ -#define _WINDOWS -#define _USRDLL -#define NPBASIC_EXPORTS - -// Panda already defines this one. #define WIN32 - -#include - -#elif defined(__APPLE__) - -// On Mac, Gecko requires this symbol to be defined. -#define XP_MACOSX - -#else - -#define XP_UNIX - -#endif // _WIN32, __APPLE__ - -#include "npapi.h" -#if NP_VERSION_MAJOR == 0 && NP_VERSION_MINOR <= 19 - #include -#else - // Somewhere between version 0.19 and 0.22, Mozilla renamed npupp.h to - // npfunctions.h. - #include "npfunctions.h" -#endif - -#if NP_VERSION_MAJOR == 0 && NP_VERSION_MINOR <= 19 - #ifdef _WIN32 - // Also somewhere in there, they started defining and using int16_t - // instead of int16, and so on. They already had int32_t from earlier, - // but the typedef is not quite the same as int32 (!), so we have to use - // #define to keep things compatible. - typedef int16 int16_t; - typedef uint16 uint16_t; -// #define int32_t int32 #define uint32_t uint32 - #endif // _WIN32 -#endif // NP_VERSION - -#include "load_plugin.h" - -// Mozilla's version of NPAPI has these names lowercase. WebKit's version has -// them uppercase. What a mess. We have to define a duplicate of the -// structure to allow us to reference them consistently. -struct UC_NPString { - const NPUTF8 *UTF8Characters; - uint32_t UTF8Length; -}; - - -// If we are building with a version of Gecko that supports the asynchronous -// callback function, we should use it--it's just so handy. -#if defined(NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL) && NP_VERSION_MINOR >= NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL -#define HAS_PLUGIN_THREAD_ASYNC_CALL 1 -#endif - -// We also need to know whether we have Apple's new Cocoa-based drawing and -// event callbacks. -#if defined(NPVERS_MACOSX_HAS_EVENT_MODELS) && NP_VERSION_MINOR >= NPVERS_MACOSX_HAS_EVENT_MODELS -#define MACOSX_HAS_EVENT_MODELS 1 -#endif - -// No one defined a symbol for the introduction of the Cocoa drawing, but it -// appears to have been version 19. -#if NP_VERSION_MINOR >= 19 -#define MACOSX_HAS_COREGRAPHICS_DRAWING_MODEL 1 -#endif - -// Appears in startup.cxx. -extern NPNetscapeFuncs *browser; - -#endif diff --git a/direct/src/plugin_npapi/nppanda3d_composite1.cxx b/direct/src/plugin_npapi/nppanda3d_composite1.cxx deleted file mode 100644 index 3bde838995..0000000000 --- a/direct/src/plugin_npapi/nppanda3d_composite1.cxx +++ /dev/null @@ -1,8 +0,0 @@ -#include "ppBrowserObject.cxx" -#include "ppDownloadRequest.cxx" -#include "ppInstance.cxx" -#include "ppPandaObject.cxx" -#include "ppToplevelObject.cxx" -#include "startup.cxx" - - diff --git a/direct/src/plugin_npapi/npruntime.h b/direct/src/plugin_npapi/npruntime.h deleted file mode 100644 index 2039225cbe..0000000000 --- a/direct/src/plugin_npapi/npruntime.h +++ /dev/null @@ -1,393 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * Copyright (c) 2004, Apple Computer, Inc. and The Mozilla Foundation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the names of Apple Computer, Inc. ("Apple") or The Mozilla - * Foundation ("Mozilla") nor the names of their contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE, MOZILLA AND THEIR CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, MOZILLA OR - * THEIR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -#ifndef _NP_RUNTIME_H_ -#define _NP_RUNTIME_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "nptypes.h" - -/* - This API is used to facilitate binding code written in C to script - objects. The API in this header does not assume the presence of a - user agent. That is, it can be used to bind C code to scripting - environments outside of the context of a user agent. - - However, the normal use of the this API is in the context of a - scripting environment running in a browser or other user agent. - In particular it is used to support the extended Netscape - script-ability API for plugins (NP-SAP). NP-SAP is an extension - of the Netscape plugin API. As such we have adopted the use of - the "NP" prefix for this API. - - The following NP{N|P}Variables were added to the Netscape plugin - API (in npapi.h): - - NPNVWindowNPObject - NPNVPluginElementNPObject - NPPVpluginScriptableNPObject - - These variables are exposed through NPN_GetValue() and - NPP_GetValue() (respectively) and are used to establish the - initial binding between the user agent and native code. The DOM - objects in the user agent can be examined and manipulated using - the NPN_ functions that operate on NPObjects described in this - header. - - To the extent possible the assumptions about the scripting - language used by the scripting environment have been minimized. -*/ - -#define NP_BEGIN_MACRO do { -#define NP_END_MACRO } while (0) - -/* - Objects (non-primitive data) passed between 'C' and script is - always wrapped in an NPObject. The 'interface' of an NPObject is - described by an NPClass. -*/ -typedef struct NPObject NPObject; -typedef struct NPClass NPClass; - -typedef char NPUTF8; -typedef struct _NPString { - const NPUTF8 *UTF8Characters; - uint32_t UTF8Length; -} NPString; - -typedef enum { - NPVariantType_Void, - NPVariantType_Null, - NPVariantType_Bool, - NPVariantType_Int32, - NPVariantType_Double, - NPVariantType_String, - NPVariantType_Object -} NPVariantType; - -typedef struct _NPVariant { - NPVariantType type; - union { - bool boolValue; - int32_t intValue; - double doubleValue; - NPString stringValue; - NPObject *objectValue; - } value; -} NPVariant; - -/* - NPN_ReleaseVariantValue is called on all 'out' parameters - references. Specifically it is to be called on variants that own - their value, as is the case with all non-const NPVariant* - arguments after a successful call to any methods (except this one) - in this API. - - After calling NPN_ReleaseVariantValue, the type of the variant - will be NPVariantType_Void. -*/ -void NPN_ReleaseVariantValue(NPVariant *variant); - -#define NPVARIANT_IS_VOID(_v) ((_v).type == NPVariantType_Void) -#define NPVARIANT_IS_NULL(_v) ((_v).type == NPVariantType_Null) -#define NPVARIANT_IS_BOOLEAN(_v) ((_v).type == NPVariantType_Bool) -#define NPVARIANT_IS_INT32(_v) ((_v).type == NPVariantType_Int32) -#define NPVARIANT_IS_DOUBLE(_v) ((_v).type == NPVariantType_Double) -#define NPVARIANT_IS_STRING(_v) ((_v).type == NPVariantType_String) -#define NPVARIANT_IS_OBJECT(_v) ((_v).type == NPVariantType_Object) - -#define NPVARIANT_TO_BOOLEAN(_v) ((_v).value.boolValue) -#define NPVARIANT_TO_INT32(_v) ((_v).value.intValue) -#define NPVARIANT_TO_DOUBLE(_v) ((_v).value.doubleValue) -#define NPVARIANT_TO_STRING(_v) ((_v).value.stringValue) -#define NPVARIANT_TO_OBJECT(_v) ((_v).value.objectValue) - -#define VOID_TO_NPVARIANT(_v) \ -NP_BEGIN_MACRO \ - (_v).type = NPVariantType_Void; \ - (_v).value.objectValue = nullptr; \ -NP_END_MACRO - -#define NULL_TO_NPVARIANT(_v) \ -NP_BEGIN_MACRO \ - (_v).type = NPVariantType_Null; \ - (_v).value.objectValue = nullptr; \ -NP_END_MACRO - -#define BOOLEAN_TO_NPVARIANT(_val, _v) \ -NP_BEGIN_MACRO \ - (_v).type = NPVariantType_Bool; \ - (_v).value.boolValue = !!(_val); \ -NP_END_MACRO - -#define INT32_TO_NPVARIANT(_val, _v) \ -NP_BEGIN_MACRO \ - (_v).type = NPVariantType_Int32; \ - (_v).value.intValue = _val; \ -NP_END_MACRO - -#define DOUBLE_TO_NPVARIANT(_val, _v) \ -NP_BEGIN_MACRO \ - (_v).type = NPVariantType_Double; \ - (_v).value.doubleValue = _val; \ -NP_END_MACRO - -#define STRINGZ_TO_NPVARIANT(_val, _v) \ -NP_BEGIN_MACRO \ - (_v).type = NPVariantType_String; \ - NPString str = { _val, (uint32_t)(strlen(_val)) }; \ - (_v).value.stringValue = str; \ -NP_END_MACRO - -#define STRINGN_TO_NPVARIANT(_val, _len, _v) \ -NP_BEGIN_MACRO \ - (_v).type = NPVariantType_String; \ - NPString str = { _val, (uint32_t)(_len) }; \ - (_v).value.stringValue = str; \ -NP_END_MACRO - -#define OBJECT_TO_NPVARIANT(_val, _v) \ -NP_BEGIN_MACRO \ - (_v).type = NPVariantType_Object; \ - (_v).value.objectValue = _val; \ -NP_END_MACRO - - -/* - Type mappings (JavaScript types have been used for illustration - purposes): - - JavaScript to C (NPVariant with type:) - undefined NPVariantType_Void - null NPVariantType_Null - Boolean NPVariantType_Bool - Number NPVariantType_Double or NPVariantType_Int32 - String NPVariantType_String - Object NPVariantType_Object - - C (NPVariant with type:) to JavaScript - NPVariantType_Void undefined - NPVariantType_Null null - NPVariantType_Bool Boolean - NPVariantType_Int32 Number - NPVariantType_Double Number - NPVariantType_String String - NPVariantType_Object Object -*/ - -typedef void *NPIdentifier; - -/* - NPObjects have methods and properties. Methods and properties are - identified with NPIdentifiers. These identifiers may be reflected - in script. NPIdentifiers can be either strings or integers, IOW, - methods and properties can be identified by either strings or - integers (i.e. foo["bar"] vs foo[1]). NPIdentifiers can be - compared using ==. In case of any errors, the requested - NPIdentifier(s) will be NULL. NPIdentifier lifetime is controlled - by the browser. Plugins do not need to worry about memory management - with regards to NPIdentifiers. -*/ -NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name); -void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, - NPIdentifier *identifiers); -NPIdentifier NPN_GetIntIdentifier(int32_t intid); -bool NPN_IdentifierIsString(NPIdentifier identifier); - -/* - The NPUTF8 returned from NPN_UTF8FromIdentifier SHOULD be freed. -*/ -NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier); - -/* - Get the integer represented by identifier. If identifier is not an - integer identifier, the behaviour is undefined. -*/ -int32_t NPN_IntFromIdentifier(NPIdentifier identifier); - -/* - NPObject behavior is implemented using the following set of - callback functions. - - The NPVariant *result argument of these functions (where - applicable) should be released using NPN_ReleaseVariantValue(). -*/ -typedef NPObject *(*NPAllocateFunctionPtr)(NPP npp, NPClass *aClass); -typedef void (*NPDeallocateFunctionPtr)(NPObject *npobj); -typedef void (*NPInvalidateFunctionPtr)(NPObject *npobj); -typedef bool (*NPHasMethodFunctionPtr)(NPObject *npobj, NPIdentifier name); -typedef bool (*NPInvokeFunctionPtr)(NPObject *npobj, NPIdentifier name, - const NPVariant *args, uint32_t argCount, - NPVariant *result); -typedef bool (*NPInvokeDefaultFunctionPtr)(NPObject *npobj, - const NPVariant *args, - uint32_t argCount, - NPVariant *result); -typedef bool (*NPHasPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name); -typedef bool (*NPGetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name, - NPVariant *result); -typedef bool (*NPSetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name, - const NPVariant *value); -typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj, - NPIdentifier name); -typedef bool (*NPEnumerationFunctionPtr)(NPObject *npobj, NPIdentifier **value, - uint32_t *count); -typedef bool (*NPConstructFunctionPtr)(NPObject *npobj, - const NPVariant *args, - uint32_t argCount, - NPVariant *result); - -/* - NPObjects returned by create, retain, invoke, and getProperty pass - a reference count to the caller. That is, the callee adds a - reference count which passes to the caller. It is the caller's - responsibility to release the returned object. - - NPInvokeFunctionPtr function may return 0 to indicate a void - result. - - NPInvalidateFunctionPtr is called by the scripting environment - when the native code is shutdown. Any attempt to message a - NPObject instance after the invalidate callback has been - called will result in undefined behavior, even if the native code - is still retaining those NPObject instances. (The runtime - will typically return immediately, with 0 or NULL, from an attempt - to dispatch to a NPObject, but this behavior should not be - depended upon.) - - The NPEnumerationFunctionPtr function may pass an array of - NPIdentifiers back to the caller. The callee allocs the memory of - the array using NPN_MemAlloc(), and it's the caller's responsibility - to release it using NPN_MemFree(). -*/ -struct NPClass -{ - uint32_t structVersion; - NPAllocateFunctionPtr allocate; - NPDeallocateFunctionPtr deallocate; - NPInvalidateFunctionPtr invalidate; - NPHasMethodFunctionPtr hasMethod; - NPInvokeFunctionPtr invoke; - NPInvokeDefaultFunctionPtr invokeDefault; - NPHasPropertyFunctionPtr hasProperty; - NPGetPropertyFunctionPtr getProperty; - NPSetPropertyFunctionPtr setProperty; - NPRemovePropertyFunctionPtr removeProperty; - NPEnumerationFunctionPtr enumerate; - NPConstructFunctionPtr construct; -}; - -#define NP_CLASS_STRUCT_VERSION 3 - -#define NP_CLASS_STRUCT_VERSION_ENUM 2 -#define NP_CLASS_STRUCT_VERSION_CTOR 3 - -#define NP_CLASS_STRUCT_VERSION_HAS_ENUM(npclass) \ - ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM) - -#define NP_CLASS_STRUCT_VERSION_HAS_CTOR(npclass) \ - ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR) - -struct NPObject { - NPClass *_class; - uint32_t referenceCount; - /* - * Additional space may be allocated here by types of NPObjects - */ -}; - -/* - If the class has an allocate function, NPN_CreateObject invokes - that function, otherwise a NPObject is allocated and - returned. This method will initialize the referenceCount member of - the NPObject to 1. -*/ -NPObject *NPN_CreateObject(NPP npp, NPClass *aClass); - -/* - Increment the NPObject's reference count. -*/ -NPObject *NPN_RetainObject(NPObject *npobj); - -/* - Decremented the NPObject's reference count. If the reference - count goes to zero, the class's destroy function is invoke if - specified, otherwise the object is freed directly. -*/ -void NPN_ReleaseObject(NPObject *npobj); - -/* - Functions to access script objects represented by NPObject. - - Calls to script objects are synchronous. If a function returns a - value, it will be supplied via the result NPVariant - argument. Successful calls will return true, false will be - returned in case of an error. - - Calls made from plugin code to script must be made from the thread - on which the plugin was initialized. -*/ - -bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName, - const NPVariant *args, uint32_t argCount, NPVariant *result); -bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args, - uint32_t argCount, NPVariant *result); -bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *script, - NPVariant *result); -bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, - NPVariant *result); -bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, - const NPVariant *value); -bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName); -bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName); -bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName); -bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier, - uint32_t *count); -bool NPN_Construct(NPP npp, NPObject *npobj, const NPVariant *args, - uint32_t argCount, NPVariant *result); - -/* - NPN_SetException may be called to trigger a script exception upon - return from entry points into NPObjects. Typical usage: - - NPN_SetException (npobj, message); -*/ -void NPN_SetException(NPObject *npobj, const NPUTF8 *message); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/direct/src/plugin_npapi/nptypes.h b/direct/src/plugin_npapi/nptypes.h deleted file mode 100644 index 4d87fb844d..0000000000 --- a/direct/src/plugin_npapi/nptypes.h +++ /dev/null @@ -1,121 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * mozilla.org. - * Portions created by the Initial Developer are Copyright (C) 2004 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Johnny Stenback (Original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef nptypes_h_ -#define nptypes_h_ - -/* - * Header file for ensuring that C99 types ([u]int32_t, [u]int64_t and bool) and - * true/false macros are available. - */ - -#if (defined(WIN32) && !defined(__GNUC__)) || defined(OS2) - /* - * Win32 and OS/2 don't know C99, so define [u]int_16/32/64 here. The bool - * is predefined tho, both in C and C++. - */ - typedef short int16_t; - typedef unsigned short uint16_t; - typedef int int32_t; - typedef unsigned int uint32_t; - typedef long long int64_t; - typedef unsigned long long uint64_t; -#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX) - /* - * AIX and SunOS ship a inttypes.h header that defines [u]int32_t, - * but not bool for C. - */ - #include - - #ifndef __cplusplus - typedef int bool; - #define true 1 - #define false 0 - #endif -#elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD) - /* - * BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and - * u_int32_t. - */ - #include - - /* - * BSD/OS ships no header that defines uint32_t, nor bool (for C) - */ - #if defined(bsdi) - typedef u_int32_t uint32_t; - typedef u_int64_t uint64_t; - - #if !defined(__cplusplus) - typedef int bool; - #define true 1 - #define false 0 - #endif - #else - /* - * FreeBSD and OpenBSD define uint32_t and bool. - */ - #include - #include - #endif -#elif defined(BEOS) - #include -#else - /* - * For those that ship a standard C99 stdint.h header file, include - * it. Can't do the same for stdbool.h tho, since some systems ship - * with a stdbool.h file that doesn't compile! - */ - #include - - #ifndef __cplusplus - #if !defined(__GNUC__) || (__GNUC__ > 2 || __GNUC_MINOR__ > 95) - #include - #else - /* - * GCC 2.91 can't deal with a typedef for bool, but a #define - * works. - */ - #define bool int - #define true 1 - #define false 0 - #endif - #endif -#endif - -#endif /* nptypes_h_ */ diff --git a/direct/src/plugin_npapi/ppBrowserObject.I b/direct/src/plugin_npapi/ppBrowserObject.I deleted file mode 100644 index 431535af85..0000000000 --- a/direct/src/plugin_npapi/ppBrowserObject.I +++ /dev/null @@ -1,12 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppBrowserObject.I - * @author drose - * @date 2009-07-05 - */ diff --git a/direct/src/plugin_npapi/ppBrowserObject.cxx b/direct/src/plugin_npapi/ppBrowserObject.cxx deleted file mode 100644 index 17104b9e6c..0000000000 --- a/direct/src/plugin_npapi/ppBrowserObject.cxx +++ /dev/null @@ -1,257 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppBrowserObject.cxx - * @author drose - * @date 2009-07-05 - */ - -#include "ppBrowserObject.h" -#include "ppInstance.h" -#include -#include // strncpy - -using std::string; - -// The following functions are C-style wrappers around the above -// PPBrowserObject methods; they are defined to allow us to create the C-style -// P3D_class_definition method table to store in the P3D_object structure. -static void -object_finish(P3D_object *object) { - delete ((PPBrowserObject *)object); -} - -static int -object_get_repr(P3D_object *object, char *buffer, int buffer_length) { - return ((const PPBrowserObject *)object)->get_repr(buffer, buffer_length); -} - -static P3D_object * -object_get_property(P3D_object *object, const char *property) { - return ((const PPBrowserObject *)object)->get_property(property); -} - -static bool -object_set_property(P3D_object *object, const char *property, - bool needs_response, P3D_object *value) { - return ((PPBrowserObject *)object)->set_property(property, needs_response, value); -} - -static P3D_object * -object_call(P3D_object *object, const char *method_name, - bool needs_response, - P3D_object *params[], int num_params) { - if (method_name == nullptr) { - method_name = ""; - } - P3D_object *response = ((const PPBrowserObject *)object)->call(method_name, params, num_params); - if (!needs_response) { - // No response was expected. Throw away the response we received, so we - // can be consistent with defined semantics. - P3D_OBJECT_XDECREF(response); - response = nullptr; - } - return response; -} - -static P3D_object * -object_eval(P3D_object *object, const char *expression) { - return ((const PPBrowserObject *)object)->eval(expression); -} - -P3D_class_definition *PPBrowserObject::_browser_object_class; - -/** - * - */ -PPBrowserObject:: -PPBrowserObject(PPInstance *inst, NPObject *npobj) : - _instance(inst), - _npobj(npobj) -{ - _class = get_class_definition(); - _ref_count = 1; - browser->retainobject(_npobj); -} - -/** - * - */ -PPBrowserObject:: -PPBrowserObject(const PPBrowserObject ©) : - _instance(copy._instance), - _npobj(copy._npobj) -{ - _class = get_class_definition(); - _ref_count = 1; - browser->retainobject(_npobj); -} - -/** - * - */ -PPBrowserObject:: -~PPBrowserObject() { - assert(_ref_count == 0); - browser->releaseobject(_npobj); -} - -/** - * Returns a user-friendly representation of the object, similar to - * get_string(), above. - */ -int PPBrowserObject:: -get_repr(char *buffer, int buffer_length) const { - std::ostringstream strm; - strm << "NPObject " << _npobj; - string result = strm.str(); - strncpy(buffer, result.c_str(), buffer_length); - return (int)result.size(); -} - -/** - * Returns the named property element in the object. The return value is a - * freshly-allocated PPBrowserObject object that must be deleted by the - * caller, or NULL on error. - */ -P3D_object *PPBrowserObject:: -get_property(const string &property) const { - NPIdentifier property_name = browser->getstringidentifier(property.c_str()); - if (!browser->hasproperty(_instance->get_npp_instance(), _npobj, - property_name)) { - // No such property. - return nullptr; - } - - NPVariant result; - if (!browser->getproperty(_instance->get_npp_instance(), _npobj, - property_name, &result)) { - // Failed to retrieve property. - return nullptr; - } - - P3D_object *object = _instance->variant_to_p3dobj(&result); - browser->releasevariantvalue(&result); - return object; -} - -/** - * Modifies (or deletes, if value is NULL) the named property element in the - * object. Returns true on success, false on failure. - */ -bool PPBrowserObject:: -set_property(const string &property, bool needs_response, P3D_object *value) { - NPIdentifier property_name = browser->getstringidentifier(property.c_str()); - bool result; - if (value != nullptr) { - // Set the property. - NPVariant npvalue; - _instance->p3dobj_to_variant(&npvalue, value); - result = browser->setproperty(_instance->get_npp_instance(), _npobj, - property_name, &npvalue); - browser->releasevariantvalue(&npvalue); - - } else { - // Delete the property. - result = browser->removeproperty(_instance->get_npp_instance(), _npobj, - property_name); - } - - return result; -} - -/** - * Invokes the named method on the object, passing the indicated parameters. - * If the method name is empty, invokes the object itself. Returns the return - * value on success, NULL on error. - */ -P3D_object *PPBrowserObject:: -call(const string &method_name, P3D_object *params[], int num_params) const { - // First, convert all of the parameters. - NPVariant *npparams = new NPVariant[num_params]; - for (int i = 0; i < num_params; ++i) { - _instance->p3dobj_to_variant(&npparams[i], params[i]); - } - - NPVariant result; - if (method_name.empty()) { - // Call the default method. - if (!browser->invokeDefault(_instance->get_npp_instance(), _npobj, - npparams, num_params, &result)) { - // Failed to invoke. - delete[] npparams; - return nullptr; - } - } else { - // Call the named method. - - NPIdentifier method_id = browser->getstringidentifier(method_name.c_str()); - if (!browser->invoke(_instance->get_npp_instance(), _npobj, method_id, - npparams, num_params, &result)) { - // Failed to invoke. - delete[] npparams; - return nullptr; - } - } - - delete[] npparams; - - P3D_object *object = _instance->variant_to_p3dobj(&result); - browser->releasevariantvalue(&result); - return object; -} - -/** - * Evaluates the indicated JavaScript expression in the context of the object. - */ -P3D_object *PPBrowserObject:: -eval(const string &expression) const { - NPString npexpr = { expression.c_str(), (uint32_t)expression.length() }; - - NPVariant result; - if (!browser->evaluate(_instance->get_npp_instance(), _npobj, - &npexpr, &result)) { - // Failed to eval. - return nullptr; - } - - P3D_object *object = _instance->variant_to_p3dobj(&result); - browser->releasevariantvalue(&result); - return object; -} - -/** - * Should be called when the core API is unloaded, and the associated class - * definition object is therefore invalidated. - */ -void PPBrowserObject:: -clear_class_definition() { - _browser_object_class = nullptr; -} - -/** - * Returns a pointer to the P3D_class_definition object that lists all of the - * C-style method pointers for this class object. - */ -P3D_class_definition *PPBrowserObject:: -get_class_definition() { - if (_browser_object_class == nullptr) { - // Create a default class_definition object, and fill in the appropriate - // pointers. - _browser_object_class = P3D_make_class_definition_ptr(); - _browser_object_class->_finish = &object_finish; - - _browser_object_class->_get_repr = &object_get_repr; - _browser_object_class->_get_property = &object_get_property; - _browser_object_class->_set_property = &object_set_property; - _browser_object_class->_call = &object_call; - _browser_object_class->_eval = &object_eval; - } - - return _browser_object_class; -} diff --git a/direct/src/plugin_npapi/ppBrowserObject.h b/direct/src/plugin_npapi/ppBrowserObject.h deleted file mode 100644 index 3b0835b450..0000000000 --- a/direct/src/plugin_npapi/ppBrowserObject.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppBrowserObject.h - * @author drose - * @date 2009-07-05 - */ - -#ifndef PPBROWSEROBJECT_H -#define PPBROWSEROBJECT_H - -#include "nppanda3d_common.h" - -class PPInstance; - -/** - * This is the interface layer between an NPObject and a P3D_object. It maps - * calls from P3D_object into the NPObject system, thus allowing Panda to view - * and operate on a browser object. - * - * Also see PPPandaObject, which maps calls the other way. - */ -class PPBrowserObject : public P3D_object { -public: - PPBrowserObject(PPInstance *inst, NPObject *npobj); - PPBrowserObject(const PPBrowserObject ©); - ~PPBrowserObject(); - - int get_repr(char *buffer, int buffer_length) const; - P3D_object *get_property(const std::string &property) const; - bool set_property(const std::string &property, bool needs_response, - P3D_object *value); - - P3D_object *call(const std::string &method_name, - P3D_object *params[], int num_params) const; - P3D_object *eval(const std::string &expression) const; - - static void clear_class_definition(); - -private: - static P3D_class_definition *get_class_definition(); - -private: - PPInstance *_instance; - NPObject *_npobj; - static P3D_class_definition *_browser_object_class; -}; - -#include "ppBrowserObject.I" - -#endif diff --git a/direct/src/plugin_npapi/ppDownloadRequest.I b/direct/src/plugin_npapi/ppDownloadRequest.I deleted file mode 100644 index d0610db522..0000000000 --- a/direct/src/plugin_npapi/ppDownloadRequest.I +++ /dev/null @@ -1,23 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppDownloadRequest.I - * @author drose - * @date 2009-06-23 - */ - -/** - * - */ -inline PPDownloadRequest:: -PPDownloadRequest(RequestType rtype, int user_id) : - _rtype(rtype), - _user_id(user_id), - _notified_done(false) -{ -} diff --git a/direct/src/plugin_npapi/ppDownloadRequest.cxx b/direct/src/plugin_npapi/ppDownloadRequest.cxx deleted file mode 100644 index 81e0605c27..0000000000 --- a/direct/src/plugin_npapi/ppDownloadRequest.cxx +++ /dev/null @@ -1,14 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppDownloadRequest.cxx - * @author drose - * @date 2009-06-23 - */ - -#include "ppDownloadRequest.h" diff --git a/direct/src/plugin_npapi/ppDownloadRequest.h b/direct/src/plugin_npapi/ppDownloadRequest.h deleted file mode 100644 index 55fe0f60fa..0000000000 --- a/direct/src/plugin_npapi/ppDownloadRequest.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppDownloadRequest.h - * @author drose - * @date 2009-06-23 - */ - -#ifndef PPDOWNLOADREQUEST_H -#define PPDOWNLOADREQUEST_H - -#include "nppanda3d_common.h" - -/** - * An instance of this object is assigned as the notifyData for URL requests, - * to help the plugin associate streams with requests. - */ -class PPDownloadRequest { -public: - enum RequestType { - RT_contents_file, - RT_core_dll, - RT_user, - RT_instance_data - }; - - inline PPDownloadRequest(RequestType rtype, int user_id = 0); - -public: - RequestType _rtype; - int _user_id; - - // This is sent true when we have notified the plugin that the stream is - // done. - bool _notified_done; -}; - -#include "ppDownloadRequest.I" - -#endif diff --git a/direct/src/plugin_npapi/ppInstance.I b/direct/src/plugin_npapi/ppInstance.I deleted file mode 100644 index 1c929d849b..0000000000 --- a/direct/src/plugin_npapi/ppInstance.I +++ /dev/null @@ -1,31 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppInstance.I - * @author drose - * @date 2009-06-19 - */ - -/** - * Returns the NPP object corresponding to this particular instance. - */ -inline NPP PPInstance:: -get_npp_instance() const { - return _npp_instance; -} - -/** - * Returns the current window parameters. - */ -const NPWindow *PPInstance:: -get_window() const { - if (_got_window) { - return &_window; - } - return nullptr; -} diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx deleted file mode 100644 index 6a3d961e32..0000000000 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ /dev/null @@ -1,3129 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppInstance.cxx - * @author drose - * @date 2009-06-19 - */ - -#include "ppInstance.h" -#include "ppPandaObject.h" -#include "ppToplevelObject.h" -#include "ppBrowserObject.h" -#include "startup.h" -#include "p3d_plugin_config.h" -#include "mkdir_complete.h" -#include "parse_color.h" -#include "nppanda3d_common.h" - -// We can include this header file to get the DTOOL_PLATFORM definition, even -// though we don't link with dtool. -#include "dtool_platform.h" -#include "pandaVersion.h" - -#include -#include -#include // strcmp() -#include - -#ifndef _WIN32 -#include -#include -#endif // _WIN32 - -#ifdef HAVE_X11 -#include -#include -#endif // HAVE_X11 - -using std::ios; -using std::ostream; -using std::ostringstream; -using std::string; -using std::vector; - - -PPInstance::FileDatas PPInstance::_file_datas; - -/** - * Creates a new instance of a Panda3D plugin window. The create_data - * structure is supplied from NPAPI, and defines the initial parameters - * specified in the HTML document. - */ -PPInstance:: -PPInstance(NPMIMEType pluginType, NPP instance, uint16_t mode, - int16_t argc, char *argn[], char *argv[], NPSavedData *saved, - P3D_window_handle_type window_handle_type, - P3D_event_type event_type) { - _p3d_inst = nullptr; - - _npp_instance = instance; - _npp_mode = mode; - _window_handle_type = window_handle_type; - _event_type = event_type; - _script_object = nullptr; - _contents_expiration = 0; - _failed = false; - _started = false; - - // Copy the tokens and save them within this object. - _tokens.reserve(argc); - for (int i = 0; i < argc; ++i) { - if (argn[i] != nullptr) { - const char *v = argv[i]; - if (v == nullptr) { - // Firefox might give us a NULL argv[i] in some cases. - v = ""; - } - - // Make the token lowercase, since HTML is case-insensitive but we're - // not. - string keyword; - for (const char *p = argn[i]; *p; ++p) { - keyword += tolower(*p); - } - - P3D_token token; - token._keyword = strdup(keyword.c_str()); - token._value = strdup(v); - _tokens.push_back(token); - } - } - - _root_dir = global_root_dir; - - _got_instance_url = false; - _p3d_instance_id = 0; - - // fgcolor and bgcolor are useful to know here (in case we have to draw a - // twirling icon). - - // The default bgcolor is white. - _bgcolor_r = _bgcolor_g = _bgcolor_b = 0xff; - if (has_token("bgcolor")) { - int r, g, b; - if (parse_color(r, g, b, lookup_token("bgcolor"))) { - _bgcolor_r = r; - _bgcolor_g = g; - _bgcolor_b = b; - } - } - - // The default fgcolor is either black or white, according to the brightness - // of the bgcolor. - if (_bgcolor_r + _bgcolor_g + _bgcolor_b > 0x80 + 0x80 + 0x80) { - _fgcolor_r = _fgcolor_g = _fgcolor_b = 0x00; - } else { - _fgcolor_r = _fgcolor_g = _fgcolor_b = 0xff; - } - if (has_token("fgcolor")) { - int r, g, b; - if (parse_color(r, g, b, lookup_token("fgcolor"))) { - _fgcolor_r = r; - _fgcolor_g = g; - _fgcolor_b = b; - } - } - - _use_xembed = false; - _got_window = false; - _python_window_open = false; -#ifdef HAVE_X11 - _twirl_subprocess_pid = -1; -#ifdef HAVE_GTK - _plug = nullptr; -#endif // HAVE_GTK -#endif // HAVE_X11 - -#ifdef _WIN32 - _hwnd = nullptr; - _bg_brush = nullptr; -#endif // _WIN32 - -#ifndef _WIN32 - // Save the startup time to improve precision of gettimeofday(). We also - // use this to measure elapsed time from the window parameters having been - // received. - struct timeval tv; - gettimeofday(&tv, nullptr); - _init_sec = tv.tv_sec; - _init_usec = tv.tv_usec; -#endif // !_WIN32 - -#ifdef __APPLE__ - // Get the run loop in the browser thread. (CFRunLoopGetMain() is only 10.5 - // or higher. Plus, the browser thread is not necessarily the "main" - // thread.) - _run_loop_main = CFRunLoopGetCurrent(); - CFRetain(_run_loop_main); - _request_timer = nullptr; - INIT_LOCK(_timer_lock); - - // Also set up a timer to twirl the icon until the instance loads. - _twirl_timer = nullptr; - CFRunLoopTimerContext timer_context; - memset(&timer_context, 0, sizeof(timer_context)); - timer_context.info = this; - _twirl_timer = CFRunLoopTimerCreate - (nullptr, 0, 0.1, 0, 0, st_twirl_timer_callback, &timer_context); - CFRunLoopAddTimer(_run_loop_main, _twirl_timer, kCFRunLoopCommonModes); -#endif // __APPLE__ - -#ifdef MACOSX_HAS_EVENT_MODELS - _got_twirl_images = false; -#endif // MACOSX_HAS_EVENT_MODELS -} - -/** - * - */ -PPInstance:: -~PPInstance() { - cleanup_window(); - -#ifdef __APPLE__ - if (_twirl_timer != nullptr) { - CFRunLoopTimerInvalidate(_twirl_timer); - CFRelease(_twirl_timer); - _twirl_timer = nullptr; - } - if (_request_timer != nullptr) { - CFRunLoopTimerInvalidate(_request_timer); - CFRelease(_request_timer); - _request_timer = nullptr; - } - _run_loop_main = CFRunLoopGetCurrent(); - CFRelease(_run_loop_main); - DESTROY_LOCK(_timer_lock); -#endif // __APPLE__ - -#ifdef MACOSX_HAS_EVENT_MODELS - osx_release_twirl_images(); -#endif // MACOSX_HAS_EVENT_MODELS - - if (_p3d_inst != nullptr) { - P3D_instance_finish_ptr(_p3d_inst); - _p3d_inst = nullptr; - } - - assert(_streams.empty()); - assert(_file_datas.empty()); - - if (_script_object != nullptr) { - browser->releaseobject(_script_object); - } - - // Free the tokens we allocated. - Tokens::iterator ti; - for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) { - free((char *)(*ti)._keyword); - free((char *)(*ti)._value); - } - _tokens.clear(); -} - -/** - * Begins the initial download of the core API. This should be called after - * constructing the PPInstance. It is a separate method than the constructor, - * because it initiates some callbacks that might rely on the object having - * been fully constructed and its pointer stored. - */ -void PPInstance:: -begin() { - // On Windows and Linux, we must insist on having this call. OSX doesn't - // necessarily require it (which is lucky, since it appears that Safari - // doesn't necessarily provide it!) -#ifndef __APPLE__ - if (!has_plugin_thread_async_call) { - nout << "Browser version insufficient: we require at least NPAPI version 0.19.\n"; - set_failed(); - } -#else - // While Safari 5 on Mac claims to provide this function, it doesn't appear - // to work. (!) So we pretend we never have it on Mac. Fortunately, this - // hack does us no harm because the _request_timer hack works fine on OSX. - has_plugin_thread_async_call = false; -#endif // __APPLE__ - - string url = PANDA_PACKAGE_HOST_URL; - if (!url.empty() && url[url.length() - 1] != '/') { - url += '/'; - } - _download_url_prefix = url; - _standard_url_prefix = url; - nout << "Plugin is built with " << PANDA_PACKAGE_HOST_URL << "\n"; - - if (!is_plugin_loaded() && !_failed) { - // We need to read the contents.xml file. First, check to see if the - // version on disk is already current enough. - bool success = false; - - string contents_filename = _root_dir + "/contents.xml"; - if (read_contents_file(contents_filename, false)) { - if (time(nullptr) < _contents_expiration) { - // Got the file, and it's good. - get_core_api(); - success = true; - } - } - - if (!success) { - // Go download the latest contents.xml file. - _download_url_prefix = _standard_url_prefix; - _mirrors.clear(); - ostringstream strm; - strm << _download_url_prefix << "contents.xml"; - - // Append a uniquifying query string to the URL to force the download to - // go all the way through any caches. We use the time in seconds; - // that's unique enough. - strm << "?" << time(nullptr); - url = strm.str(); - - PPDownloadRequest *req = new PPDownloadRequest(PPDownloadRequest::RT_contents_file); - start_download(url, req); - } - } - - handle_request_loop(); -} - -/** - * Stores or updates the window parameters. - */ -void PPInstance:: -set_window(NPWindow *window) { - if (_got_window && - window->x == _window.x && - window->y == _window.y && - window->width == _window.width && - window->height == _window.height) { - // No changes. - return; - } - - if (_got_window) { - // We don't expect the browser to change the window's parent on-the-fly. - assert(_window.window == window->window); - } - - if (!_got_window) { -#ifdef _WIN32 - _orig_window_proc = nullptr; - if (window->type == NPWindowTypeWindow) { - // Save the window handle. - _hwnd = (HWND)window->window; - - // Now that we've got a window handle, we can go get the twirling icon - // images. - win_get_twirl_bitmaps(); - - _bg_brush = CreateSolidBrush(RGB(_bgcolor_r, _bgcolor_g, _bgcolor_b)); - - // Subclass the window to make it call our own window_proc instead of - // whatever window_proc it has already. This is mainly just a dopey - // trick to allow us to poll events in the main thread, but we also rely - // on this to paint the twirling icon into the browser window. - SetWindowLongPtr(_hwnd, GWLP_USERDATA, (LONG_PTR)this); - _orig_window_proc = SetWindowLongPtr(_hwnd, GWLP_WNDPROC, (LONG_PTR)st_window_proc); - - // Also set a timer to go off every once in a while, to update the - // twirling icon, and also to catch events in case something slips - // through. - _init_time = GetTickCount(); - SetTimer(_hwnd, 1, 100, nullptr); - } -#endif // _WIN32 -#ifdef MACOSX_HAS_EVENT_MODELS - osx_get_twirl_images(); -#endif // MACOSX_HAS_EVENT_MODELS - } - -#if defined(HAVE_GTK) && defined(HAVE_X11) - if (_use_xembed) { - if (!_got_window || _window.window != window->window) { - // The window has changed. Destroy the old GtkPlug. - if (_plug != nullptr) { - gtk_widget_destroy(_plug); - _plug = nullptr; - } - - // Create a new GtkPlug to bind to the XEmbed socket. - _plug = gtk_plug_new((GdkNativeWindow) reinterpret_cast(window->window)); - gtk_widget_show(_plug); - - nout << "original XID is " << window->window << ", created X11 window " - << GDK_DRAWABLE_XID(_plug->window) << "\n"; - } - } -#endif // HAVE_GTK && HAVE_X11 - - _window = *window; - _got_window = true; - -#ifdef HAVE_X11 - if (!_failed && !_started) { - x11_start_twirl_subprocess(); - } -#endif // HAVE_X11 - - if (!_failed) { - if (_p3d_inst == nullptr) { - create_instance(); - } else { - send_window(); - } - } -} - -/** - * Receives notification of a new stream object, e.g. a url request. - */ -NPError PPInstance:: -new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16_t *stype) { - assert(find(_streams.begin(), _streams.end(), stream) == _streams.end()); - if (_failed) { - return NPERR_GENERIC_ERROR; - } - - if (stream->notifyData == nullptr) { - // This is an unsolicited stream. Assume the first unsolicited stream we - // receive is the instance data; any other unsolicited stream is an error. - - if (!_got_instance_url && stream->url != nullptr) { - _got_instance_url = true; - _instance_url = stream->url; - stream->notifyData = new PPDownloadRequest(PPDownloadRequest::RT_instance_data); - - if (_p3d_inst != nullptr) { - // If we already have an instance by the time we get this stream, - // start sending the data to the instance (instead of having to mess - // around with a temporary file). - _p3d_instance_id = P3D_instance_start_stream_ptr(_p3d_inst, _instance_url.c_str()); - nout << "p3d instance to stream " << _p3d_instance_id << "\n"; - } - - *stype = NP_NORMAL; - _streams.push_back(stream); - return NPERR_NO_ERROR; - } - - // Don't finish downloading the unsolicited stream. - return NPERR_GENERIC_ERROR; - } - - PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData); - switch (req->_rtype) { - case PPDownloadRequest::RT_contents_file: - // This is the initial contents.xml file. We used to download this via - // NP_ASFILEONLY, but that option doesn't work on Windows within a Unicode - // user directory. So we use NP_NORMAL instead. - *stype = NP_NORMAL; - _streams.push_back(stream); - return NPERR_NO_ERROR; - - case PPDownloadRequest::RT_core_dll: - // This is the core API DLL (or dylib or whatever). Again, we have to use - // NP_NORMAL. - *stype = NP_NORMAL; - _streams.push_back(stream); - return NPERR_NO_ERROR; - - case PPDownloadRequest::RT_user: - // This is a request from the plugin. We'll receive this as a stream. - *stype = NP_NORMAL; - _streams.push_back(stream); - return NPERR_NO_ERROR; - - default: - // Don't know what this is. - nout << "Unexpected request " << (int)req->_rtype << "\n"; - } - - return NPERR_GENERIC_ERROR; -} - - -/** - * Stops any download streams that are currently active on the instance. It - * is necessary to call this explicitly before destroying the instance, at - * least for Safari. - */ -void PPInstance:: -stop_outstanding_streams() { - Streams::iterator si; - Streams streams; - streams.swap(_streams); - for (si = streams.begin(); si != streams.end(); ++si) { - NPStream *stream = (*si); - nout << "Stopping stream " << (void *)stream << "\n"; - browser->destroystream(_npp_instance, stream, NPRES_USER_BREAK); - destroy_stream(stream, NPRES_USER_BREAK); - } - - assert(_streams.empty()); - - // Also stop any currently pending _file_datas; these are locally- - // implemented streams. - FileDatas::iterator fi; - for (fi = _file_datas.begin(); fi != _file_datas.end(); ++fi) { - delete (*fi); - } - _file_datas.clear(); -} - -/** - * Called by the browser to ask how much data is ready to be received for the - * indicated stream. - */ -int32_t PPInstance:: -write_ready(NPStream *stream) { - // We're supposed to return the maximum amount of data the plugin is - // prepared to handle. Gee, I don't know. As much as you can give me, I - // guess. - return 0x7fffffff; -} - -/** - * Called by the browser to feed data read from a URL or whatever. - */ -int PPInstance:: -write_stream(NPStream *stream, int offset, int len, void *buffer) { - if (stream->notifyData == nullptr) { - nout << "Unexpected write_stream on " << stream->url << "\n"; - browser->destroystream(_npp_instance, stream, NPRES_USER_BREAK); - return 0; - } - - if (_failed) { - // We're done; stop this. - browser->destroystream(_npp_instance, stream, NPRES_USER_BREAK); - return 0; - } - - PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData); - switch (req->_rtype) { - case PPDownloadRequest::RT_user: - P3D_instance_feed_url_stream_ptr(_p3d_inst, req->_user_id, - P3D_RC_in_progress, 0, - stream->end, buffer, len); - return len; - - case PPDownloadRequest::RT_instance_data: - // There's a special case for the RT_instance_data stream. This is the - // first, unsolicited stream that indicates the p3d instance data. We - // have to send this stream into the instance, but we can only do this - // once the instance itself has been created. - - // We used to get away with returning 0 in write_ready until the instance - // was ready, but that turns out to fail under Safari Snow Leopard, which - // it seems will hold up every other download until the p3d file has been - // retrieved. Sigh. So we must start accepting the data even before the - // instance has been created, or we'll never get our contents.xml or any - // other important bits of data. - - // Nowadays we solve this problem by writing the data to a temporary file - // until the instance is ready for it. - if (_p3d_inst == nullptr) { - // The instance isn't ready, so stuff it in a temporary file. - if (!_p3d_temp_file.feed(stream->end, buffer, len)) { - set_failed(); - } - return len; - - } else { - // The instance has been created. Redirect the stream into the - // instance. - assert(!_p3d_temp_file._opened); - req->_rtype = PPDownloadRequest::RT_user; - req->_user_id = _p3d_instance_id; - P3D_instance_feed_url_stream_ptr(_p3d_inst, req->_user_id, - P3D_RC_in_progress, 0, - stream->end, buffer, len); - return len; - } - break; - - case PPDownloadRequest::RT_contents_file: - if (!_contents_temp_file.feed(stream->end, buffer, len)) { - set_failed(); - } - return len; - - case PPDownloadRequest::RT_core_dll: - if (!_core_dll_temp_file.feed(stream->end, buffer, len)) { - set_failed(); - } - return len; - - default: - nout << "Unexpected write_stream on " << stream->url << "\n"; - break; - } - - browser->destroystream(_npp_instance, stream, NPRES_USER_BREAK); - return 0; -} - -/** - * Called by the browser to mark the end of a stream; the file has either been - * successfully downloaded or failed. - */ -NPError PPInstance:: -destroy_stream(NPStream *stream, NPReason reason) { - Streams::iterator si = find(_streams.begin(), _streams.end(), stream); - if (si != _streams.end()) { - _streams.erase(si); - } - - if (stream->notifyData == nullptr) { - nout << "Unexpected destroy_stream on " << stream->url << "\n"; - return NPERR_NO_ERROR; - } - - PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData); - - P3D_result_code result_code = P3D_RC_done; - if (reason != NPRES_DONE) { - if (reason == NPRES_USER_BREAK) { - result_code = P3D_RC_shutdown; - } else { - result_code = P3D_RC_generic_error; - } - } - - switch (req->_rtype) { - case PPDownloadRequest::RT_user: - if (!req->_notified_done) { - P3D_instance_feed_url_stream_ptr(_p3d_inst, req->_user_id, - result_code, 0, stream->end, nullptr, 0); - req->_notified_done = true; - } - break; - - case PPDownloadRequest::RT_instance_data: - if (!req->_notified_done) { - if (_p3d_inst == nullptr) { - // The instance still isn't ready; just mark the data done. We'll - // send the entire file to the instance when it is ready. - _p3d_temp_file.finish(); - if (result_code != P3D_RC_done) { - set_failed(); - } - - } else { - // The instance has (only just) been created. Tell it we've sent it - // all the data it will get. - P3D_instance_feed_url_stream_ptr(_p3d_inst, _p3d_instance_id, - result_code, 0, stream->end, nullptr, 0); - } - req->_notified_done = true; - } - break; - - case PPDownloadRequest::RT_contents_file: - if (!req->_notified_done) { - _contents_temp_file.finish(); - if (result_code != P3D_RC_done) { - set_failed(); - } - req->_notified_done = true; - } - break; - - case PPDownloadRequest::RT_core_dll: - if (!req->_notified_done) { - _core_dll_temp_file.finish(); - if (result_code != P3D_RC_done) { - set_failed(); - } - req->_notified_done = true; - } - break; - - default: - nout << "Unexpected destroy_stream on " << stream->url << "\n"; - break; - } - - return NPERR_NO_ERROR; -} - -/** - * Called by the browser to announce the end of a stream. This normally - * follows destroy_stream(), unless the stream was never created in the first - * place. - */ -void PPInstance:: -url_notify(const char *url, NPReason reason, void *notifyData) { - if (notifyData == nullptr) { - return; - } - - PPDownloadRequest *req = (PPDownloadRequest *)notifyData; - if (_failed) { - // We're done; ignore this. - delete req; - return; - } - - switch (req->_rtype) { - case PPDownloadRequest::RT_user: - if (!req->_notified_done) { - // We shouldn't have gotten here without notifying the stream unless the - // stream never got started (and hence we never called destroy_stream(). - nout << "Failure starting stream\n"; - assert(reason != NPRES_DONE); - - P3D_instance_feed_url_stream_ptr(_p3d_inst, req->_user_id, - P3D_RC_generic_error, 0, 0, nullptr, 0); - req->_notified_done = true; - } - break; - - case PPDownloadRequest::RT_contents_file: - if (reason == NPRES_DONE) { - downloaded_contents_file(_contents_temp_file._filename); - } else { - nout << "Failure downloading " << url << "\n"; - - if (reason == NPRES_USER_BREAK) { - nout << "Failure due to user break\n"; - } else { - // Couldn't download a fresh contents.xml for some reason. If there's - // an outstanding contents.xml file on disk, try to load that one as a - // fallback. - string contents_filename = _root_dir + "/contents.xml"; - if (read_contents_file(contents_filename, false)) { - get_core_api(); - } else { - nout << "Unable to read contents file " << contents_filename << "\n"; - set_failed(); - } - } - } - break; - - case PPDownloadRequest::RT_core_dll: - if (reason == NPRES_DONE) { - downloaded_plugin(_core_dll_temp_file._filename); - - } else { - nout << "Failure downloading " << url << "\n"; - - if (reason == NPRES_USER_BREAK) { - nout << "Failure due to user break\n"; - } else { - // Couldn't download from this mirror. Try the next one. - if (!_core_urls.empty()) { - string url = _core_urls.back(); - _core_urls.pop_back(); - - PPDownloadRequest *req2 = new PPDownloadRequest(PPDownloadRequest::RT_core_dll); - start_download(url, req2); - } - } - } - break; - - default: - nout << "Unexpected url_notify on stream type " << req->_rtype << "\n"; - break; - } - - delete req; -} - -/** - * Called by the browser to report the filename that contains the fully- - * downloaded stream contents. - */ -void PPInstance:: -stream_as_file(NPStream *stream, const char *fname) { - if (stream->notifyData == nullptr) { - nout << "Unexpected stream_as_file on " << stream->url << "\n"; - return; - } - - string filename = fname; -#ifdef __APPLE__ - // Safari seems to want to report the filename in the old-style form - // "Macintosh HD:blah:blah:blah" instead of the new-style form - // "blahblahblah". How annoying. - - size_t colon = filename.find(':'); - size_t slash = filename.find('/'); - if (colon < slash) { - // This might be such a filename. - - string fname2 = "/Volumes/"; - for (size_t p = 0; p < filename.size(); ++p) { - if (filename[p] == ':') { - fname2 += '/'; - } else { - fname2 += filename[p]; - } - } - - if (access(fname2.c_str(), R_OK) == 0) { - // Looks like we've converted it successfully. - filename = fname2; - - // Here's another crazy hack. In addition to the weird filename format, - // the file that Safari tells us about appears to be a temporary file - // that Safari's about to delete. In order to protect ourselves from - // this, we need to temporarily copy the file somewhere else. - char *name = tempnam(nullptr, "p3d_"); - - // We prefer just making a hard link; it's quick and easy. - if (link(filename.c_str(), name) != 0) { - // But sometimes the hard link might fail, particularly if these are - // two different file systems. In this case we have to open the files - // and copy the data by hand. - copy_file(filename, name); - } - - filename = name; - free(name); - - // TODO: remove this temporary file when we're done with it. - } - } - -#endif // __APPLE__ - - PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData); - downloaded_file(req, filename); -} - -/** - * Handles a request from the Core API or the application, forwarding it to - * the browser as appropriate. Returns true if we should continue the request - * loop, or false to return (temporarily) to JavaScript. - */ -bool PPInstance:: -handle_request(P3D_request *request) { - if (_p3d_inst == nullptr || _failed) { - return false; - } - assert(request->_instance == _p3d_inst); - bool handled = false; - bool continue_loop = true; - - switch (request->_request_type) { - case P3D_RT_stop: - if (_p3d_inst != nullptr) { - P3D_instance_finish_ptr(_p3d_inst); - _p3d_inst = nullptr; - } - cleanup_window(); - // Guess the browser doesn't really care. - handled = true; - break; - - case P3D_RT_get_url: - { - PPDownloadRequest *req = - new PPDownloadRequest(PPDownloadRequest::RT_user, - request->_request._get_url._unique_id); - start_download(request->_request._get_url._url, req); - } - break; - - case P3D_RT_notify: - // We mostly ignore notifies, since these are handled by the core API. - // But we do check for the "onwindowopen" notify, at which point we start - // spamming the refresh requests. - if (strcmp(request->_request._notify._message, "onwindowopen") == 0) { - _python_window_open = true; - if (_got_window) { - NPRect rect = { 0, 0, (unsigned short)_window.height, (unsigned short)_window.width }; - browser->invalidaterect(_npp_instance, &rect); - } - } - break; - - case P3D_RT_refresh: - if (_got_window) { - NPRect rect = { 0, 0, (unsigned short)_window.height, (unsigned short)_window.width }; - browser->invalidaterect(_npp_instance, &rect); - } - break; - - case P3D_RT_callback: - // In the case of a callback, yield control temporarily to JavaScript. - continue_loop = false; - break; - - default: - // Some request types are not handled. - nout << "Unhandled request: " << request->_request_type << "\n"; - break; - }; - - P3D_request_finish_ptr(request, handled); - return continue_loop; -} - -/** - * This method is called from strategically-chosen browser callback functions. - * Its purpose is to provide another hook into the main thread callback, - * particularly if the PluginAsyncCall function isn't available. - */ -void PPInstance:: -generic_browser_call() { - /* - if (!has_plugin_thread_async_call) { - // If we can't ask Mozilla to call us back using - // NPN_PluginThreadAsyncCall(), then we'll do it explicitly now, since we - // know we're in the main thread here. - handle_request_loop(); - } - */ -} - -/** - * Called by the browser as new window events are generated. Returns true if - * the event is handled, false if ignored. - */ -bool PPInstance:: -handle_event(void *event) { - bool retval = false; - - P3D_event_data edata; - memset(&edata, 0, sizeof(edata)); - edata._event_type = _event_type; - EventAuxData aux_data; - if (_event_type == P3D_ET_osx_event_record) { -#ifdef __APPLE__ - edata._event._osx_event_record._event = (EventRecord *)event; -#endif // __APPLE__ - -#ifdef MACOSX_HAS_EVENT_MODELS - } else if (_event_type == P3D_ET_osx_cocoa) { - // Copy the NPCocoaEvent structure componentwise into a P3DCocoaEvent - // structure. - NPCocoaEvent *np_event = (NPCocoaEvent *)event; - P3DCocoaEvent *p3d_event = &edata._event._osx_cocoa._event; - copy_cocoa_event(p3d_event, np_event, aux_data); - if (_got_window) { - handle_cocoa_event(p3d_event); - } -#endif // MACOSX_HAS_EVENT_MODELS - } - - if (_p3d_inst != nullptr) { - if (P3D_instance_handle_event_ptr(_p3d_inst, &edata)) { - retval = true; - } - } - - return retval; -} - -/** - * Returns a toplevel object that JavaScript or whatever can read and/or - * modify to control the instance. - */ -NPObject *PPInstance:: -get_panda_script_object() { - if (_script_object != nullptr) { - // NPRuntime "steals" a reference to this object. - browser->retainobject(_script_object); - return _script_object; - } - - P3D_object *main = nullptr; - - if (_p3d_inst != nullptr) { - main = P3D_instance_get_panda_script_object_ptr(_p3d_inst); - } - nout << "get_panda_script_object, main = " << main << "\n"; - - _script_object = PPToplevelObject::make_new(this); - _script_object->set_main(main); - - browser->retainobject(_script_object); - return _script_object; -} - -/** - * Sets the use_xembed flag, telling the instance what kind of window object - * to expect from NPAPI. If this is true, the window object is an XID - * following the XEmbed specification; if false, it is a normal window handle. - */ -void PPInstance:: -set_xembed(bool use_xembed) { - _use_xembed = use_xembed; -} - -/** - * Converts the indicated P3D_object to the equivalent NPVariant, and stores - * it in result. - */ -void PPInstance:: -p3dobj_to_variant(NPVariant *result, P3D_object *object) { - switch (P3D_OBJECT_GET_TYPE(object)) { - case P3D_OT_undefined: - VOID_TO_NPVARIANT(*result); - break; - - case P3D_OT_none: - NULL_TO_NPVARIANT(*result); - break; - - case P3D_OT_bool: - BOOLEAN_TO_NPVARIANT(P3D_OBJECT_GET_BOOL(object), *result); - break; - - case P3D_OT_int: - INT32_TO_NPVARIANT(P3D_OBJECT_GET_INT(object), *result); - break; - - case P3D_OT_float: - DOUBLE_TO_NPVARIANT(P3D_OBJECT_GET_FLOAT(object), *result); - break; - - case P3D_OT_string: - { - int size = P3D_OBJECT_GET_STRING(object, nullptr, 0); - char *buffer = (char *)browser->memalloc(size); - P3D_OBJECT_GET_STRING(object, buffer, size); - STRINGN_TO_NPVARIANT(buffer, size, *result); - } - break; - - case P3D_OT_object: - { - PPPandaObject *ppobj = PPPandaObject::make_new(this, object); - OBJECT_TO_NPVARIANT(ppobj, *result); - } - break; - } -} - -/** - * Converts the indicated NPVariant to the equivalent P3D_object, and returns - * it (newly-allocated). The caller is responsible for freeing the returned - * object later. - */ -P3D_object *PPInstance:: -variant_to_p3dobj(const NPVariant *variant) { - if (NPVARIANT_IS_VOID(*variant)) { - return P3D_new_undefined_object_ptr(); - } else if (NPVARIANT_IS_NULL(*variant)) { - return P3D_new_none_object_ptr(); - } else if (NPVARIANT_IS_BOOLEAN(*variant)) { - return P3D_new_bool_object_ptr(NPVARIANT_TO_BOOLEAN(*variant)); - } else if (NPVARIANT_IS_INT32(*variant)) { - return P3D_new_int_object_ptr(NPVARIANT_TO_INT32(*variant)); - } else if (NPVARIANT_IS_DOUBLE(*variant)) { - return P3D_new_float_object_ptr(NPVARIANT_TO_DOUBLE(*variant)); - } else if (NPVARIANT_IS_STRING(*variant)) { - NPString str = NPVARIANT_TO_STRING(*variant); - const UC_NPString &uc_str = *(UC_NPString *)(&str); - return P3D_new_string_object_ptr(uc_str.UTF8Characters, uc_str.UTF8Length); - } else if (NPVARIANT_IS_OBJECT(*variant)) { - NPObject *object = NPVARIANT_TO_OBJECT(*variant); - if (object->_class == &PPPandaObject::_object_class) { - // This is really a PPPandaObject. - PPPandaObject *ppobject = (PPPandaObject *)object; - P3D_object *obj = ppobject->get_p3d_object(); - return obj; - } - - // It's a generic NPObject of some kind. - return new PPBrowserObject(this, object); - } - - // Hmm, none of the above? - return P3D_new_none_object_ptr(); -} - -/** - * Outputs the variant value. - */ -void PPInstance:: -output_np_variant(ostream &out, const NPVariant &result) { - if (NPVARIANT_IS_NULL(result)) { - out << "null"; - } else if (NPVARIANT_IS_VOID(result)) { - out << "void"; - } else if (NPVARIANT_IS_BOOLEAN(result)) { - out << "bool " << NPVARIANT_TO_BOOLEAN(result); - } else if (NPVARIANT_IS_INT32(result)) { - out << "int " << NPVARIANT_TO_INT32(result); - } else if (NPVARIANT_IS_DOUBLE(result)) { - out << "double " << NPVARIANT_TO_DOUBLE(result); - } else if (NPVARIANT_IS_STRING(result)) { - NPString str = NPVARIANT_TO_STRING(result); - const UC_NPString &uc_str = *(UC_NPString *)(&str); - out << "string " << string(uc_str.UTF8Characters, uc_str.UTF8Length); - } else if (NPVARIANT_IS_OBJECT(result)) { - NPObject *child = NPVARIANT_TO_OBJECT(result); - out << "object " << child; - } -} - -/** - * Scans the element for the matching element. - */ -void PPInstance:: -find_host(TiXmlElement *xcontents) { - string host_url = PANDA_PACKAGE_HOST_URL; - TiXmlElement *xhost = xcontents->FirstChildElement("host"); - if (xhost != nullptr) { - const char *url = xhost->Attribute("url"); - if (url != nullptr && host_url == string(url)) { - // We're the primary host. This is the normal case. - read_xhost(xhost); - return; - - } else { - // We're not the primary host; perhaps we're an alternate host. - TiXmlElement *xalthost = xhost->FirstChildElement("alt_host"); - while (xalthost != nullptr) { - const char *url = xalthost->Attribute("url"); - if (url != nullptr && host_url == string(url)) { - // Yep, we're this alternate host. - read_xhost(xhost); - return; - } - xalthost = xalthost->NextSiblingElement("alt_host"); - } - } - - // Hmm, didn't find the URL we used mentioned. Assume we're the primary - // host. - read_xhost(xhost); - } -} - -/** - * Reads the host data from the (or ) entry in the - * contents.xml file. - */ -void PPInstance:: -read_xhost(TiXmlElement *xhost) { - // Get the "download" URL, which is the source from which we download - // everything other than the contents.xml file. - const char *download_url = xhost->Attribute("download_url"); - if (download_url != nullptr) { - _download_url_prefix = download_url; - } else { - _download_url_prefix = PANDA_PACKAGE_HOST_URL; - } - if (!_download_url_prefix.empty()) { - if (_download_url_prefix[_download_url_prefix.size() - 1] != '/') { - _download_url_prefix += "/"; - } - } - - TiXmlElement *xmirror = xhost->FirstChildElement("mirror"); - while (xmirror != nullptr) { - const char *url = xmirror->Attribute("url"); - if (url != nullptr) { - add_mirror(url); - } - xmirror = xmirror->NextSiblingElement("mirror"); - } -} - -/** - * Adds a new URL to serve as a mirror for this host. The mirrors will be - * consulted first, before consulting the host directly. - */ -void PPInstance:: -add_mirror(string mirror_url) { - // Ensure the URL ends in a slash. - if (!mirror_url.empty() && mirror_url[mirror_url.size() - 1] != '/') { - mirror_url += '/'; - } - - // Add it to the _mirrors list, but only if it's not already there. - if (find(_mirrors.begin(), _mirrors.end(), mirror_url) == _mirrors.end()) { - _mirrors.push_back(mirror_url); - } -} - -/** - * Selects num_mirrors elements, chosen at random, from the _mirrors list. - * Adds the selected mirrors to result. If there are fewer than num_mirrors - * elements in the list, adds only as many mirrors as we can get. - */ -void PPInstance:: -choose_random_mirrors(vector &result, int num_mirrors) { - vector selected; - - size_t num_to_select = std::min(_mirrors.size(), (size_t)num_mirrors); - while (num_to_select > 0) { - size_t i = (size_t)(((double)rand() / (double)RAND_MAX) * _mirrors.size()); - while (find(selected.begin(), selected.end(), i) != selected.end()) { - // Already found this i, find a new one. - i = (size_t)(((double)rand() / (double)RAND_MAX) * _mirrors.size()); - } - selected.push_back(i); - result.push_back(_mirrors[i]); - --num_to_select; - } -} - -/** - * This function is attached as an asynchronous callback to each instance; it - * will be notified when the instance has a request ready. This function may - * be called in a sub-thread. - */ -void PPInstance:: -request_ready(P3D_instance *instance) { - PPInstance *inst = (PPInstance *)(instance->_user_data); - assert(inst != nullptr); - - if (has_plugin_thread_async_call) { -#ifdef HAS_PLUGIN_THREAD_ASYNC_CALL - // Since we are running at least Gecko 1.9, and we have this very useful - // function, let's use it to ask the browser to call us back in the main - // thread. - assert((void *)browser->pluginthreadasynccall != nullptr); - browser->pluginthreadasynccall(inst->_npp_instance, browser_sync_callback, nullptr); -#endif // HAS_PLUGIN_THREAD_ASYNC_CALL - - } else { - // If we're using an older version of Gecko, we have to do this some - // other, OS-dependent way. - -#ifdef _WIN32 - // Use a Windows message to forward this event to the main thread. - - // Get the window handle for the window associated with this instance. - const NPWindow *win = inst->get_window(); - if (win != nullptr && win->type == NPWindowTypeWindow) { - PostMessage((HWND)(win->window), WM_USER, 0, 0); - } -#endif // _WIN32 - -#ifdef __APPLE__ - // Use an OSX timer to forward this event to the main thread. - - // Only set a new timer if we don't have one already started. - ACQUIRE_LOCK(inst->_timer_lock); - if (inst->_request_timer == nullptr) { - CFRunLoopTimerContext timer_context; - memset(&timer_context, 0, sizeof(timer_context)); - timer_context.info = inst; - inst->_request_timer = CFRunLoopTimerCreate - (nullptr, 0, 0, 0, 0, timer_callback, &timer_context); - CFRunLoopAddTimer(inst->_run_loop_main, inst->_request_timer, kCFRunLoopCommonModes); - } - RELEASE_LOCK(inst->_timer_lock); -#endif // __APPLE__ - - // Doesn't appear to be a reliable way to simulate this in Linux. - } -} - -/** - * Initiates a download request. - */ -void PPInstance:: -start_download(const string &url, PPDownloadRequest *req) { - nout << "start_download: " << url << "\n"; - if (url.substr(0, 7) == "file://") { - // If we're "downloading" a file URL, just go read the file directly. - downloaded_file(req, get_filename_from_url(url)); - delete req; - } else { - // Otherwise, ask the browser to download it. - browser->geturlnotify(_npp_instance, url.c_str(), nullptr, req); - } -} - -/** - * The contents.xml file has been successfully downloaded; copy it into place. - */ -void PPInstance:: -downloaded_contents_file(const string &filename) { - // Now we have the contents.xml file. Read this to get the filename and md5 - // hash of our core API DLL. - if (read_contents_file(filename, true)) { - // Successfully downloaded and read, and it has been written into its - // normal place. - get_core_api(); - - } else { - // Error reading the contents.xml file, or in loading the core API that it - // references. - nout << "Unable to read contents file " << filename << "\n"; - - // If there's an outstanding contents.xml file on disk, try to load that - // one as a fallback. - string contents_filename = _root_dir + "/contents.xml"; - if (read_contents_file(contents_filename, false)) { - get_core_api(); - } else { - nout << "Unable to read contents file " << contents_filename << "\n"; - set_failed(); - } - } -} - -/** - * Attempts to open and read the contents.xml file on disk. Copies the file - * to its standard location on success. Returns true on success, false on - * failure. - */ -bool PPInstance:: -read_contents_file(const string &contents_filename, bool fresh_download) { - _download_url_prefix = _standard_url_prefix; - _mirrors.clear(); - - TiXmlDocument doc(contents_filename.c_str()); - if (!doc.LoadFile()) { - return false; - } - - bool found_core_package = false; - - TiXmlElement *xcontents = doc.FirstChildElement("contents"); - if (xcontents != nullptr) { - int max_age = P3D_CONTENTS_DEFAULT_MAX_AGE; - xcontents->Attribute("max_age", &max_age); - - // Get the latest possible expiration time, based on the max_age - // indication. Any expiration time later than this is in error. - time_t now = time(nullptr); - _contents_expiration = now + (time_t)max_age; - - if (fresh_download) { - // Update the XML with the new download information. - TiXmlElement *xorig = xcontents->FirstChildElement("orig"); - while (xorig != nullptr) { - xcontents->RemoveChild(xorig); - xorig = xcontents->FirstChildElement("orig"); - } - - xorig = new TiXmlElement("orig"); - xcontents->LinkEndChild(xorig); - - xorig->SetAttribute("expiration", (int)_contents_expiration); - - } else { - // Read the expiration time from the XML. - int expiration = 0; - TiXmlElement *xorig = xcontents->FirstChildElement("orig"); - if (xorig != nullptr) { - xorig->Attribute("expiration", &expiration); - } - - _contents_expiration = std::min(_contents_expiration, (time_t)expiration); - } - - nout << "read contents.xml, max_age = " << max_age - << ", expires in " << std::max(_contents_expiration, now) - now - << " s\n"; - - // Look for the entry; it might point us at a different download - // URL, and it might mention some mirrors. - find_host(xcontents); - - // Now look for the core API package. - _coreapi_set_ver = ""; - TiXmlElement *xpackage = xcontents->FirstChildElement("package"); - while (xpackage != nullptr) { - const char *name = xpackage->Attribute("name"); - if (name != nullptr && strcmp(name, "coreapi") == 0) { - const char *platform = xpackage->Attribute("platform"); - if (platform != nullptr && strcmp(platform, DTOOL_PLATFORM) == 0) { - _coreapi_dll.load_xml(xpackage); - const char *set_ver = xpackage->Attribute("set_ver"); - if (set_ver != nullptr) { - _coreapi_set_ver = set_ver; - } - found_core_package = true; - break; - } - } - - xpackage = xpackage->NextSiblingElement("package"); - } - } - - if (!found_core_package) { - // Couldn't find the coreapi package description. - nout << "No coreapi package defined in contents file for " - << DTOOL_PLATFORM << "\n"; - return false; - } - - // Check the coreapi_set_ver token. If it is given, it specifies a minimum - // Core API version number we expect to find. If we didn't find that - // number, perhaps our contents.xml is out of date. - string coreapi_set_ver = lookup_token("coreapi_set_ver"); - if (!coreapi_set_ver.empty()) { - nout << "Instance asked for Core API set_ver " << coreapi_set_ver - << ", we found " << _coreapi_set_ver << "\n"; - // But don't bother if we just freshly downloaded it. - if (!fresh_download) { - if (compare_seq(coreapi_set_ver, _coreapi_set_ver) > 0) { - // The requested set_ver value is higher than the one we have on file; - // our contents.xml file must be out of date after all. - nout << "expiring contents.xml\n"; - _contents_expiration = 0; - } - } - } - - // Success. Now save the file in its proper place. - string standard_filename = _root_dir + "/contents.xml"; - - mkfile_complete(standard_filename, nout); - if (!doc.SaveFile(standard_filename.c_str())) { - nout << "Couldn't rewrite " << standard_filename << "\n"; - return false; - } - - return true; -} - -/** - * Returns the actual filename referenced by a file: url. - */ -string PPInstance:: -get_filename_from_url(const string &url) { - string filename = url.substr(7); - - // Strip off a trailing query string. - size_t query = filename.find('?'); - if (query != string::npos) { - filename = filename.substr(0, query); - } - -#ifdef _WIN32 - // On Windows, we have to munge the filename specially, because it's been - // URL-munged. It might begin with a leading slash as well as a drive - // letter. Clean up that nonsense. - if (filename.length() >= 3 && - (filename[0] == '/' || filename[0] == '\\') && - isalpha(filename[1]) && filename[2] == ':') { - filename = filename.substr(1); - } -#endif // _WIN32 - - return filename; -} - -/** - * Called to receive the fully-downloaded contents of a URL. - */ -void PPInstance:: -downloaded_file(PPDownloadRequest *req, const string &filename) { - // Since we're no longer using NP_ASFILEONLY, none of these URL requests - // will normally come through this codepath (they'll go through url_notify() - // above, instead), unless we short-circuited the browser by "downloading" a - // file: url. - switch (req->_rtype) { - case PPDownloadRequest::RT_contents_file: - // The contents.xml file that gets things going. - downloaded_contents_file(filename); - break; - - case PPDownloadRequest::RT_core_dll: - // This is the core API DLL (or dylib or whatever). Now that we've - // downloaded it, we can load it. - downloaded_plugin(filename); - break; - - case PPDownloadRequest::RT_user: - // Here's the user-requested file. It needs to be streamed to the user, - // so we'll open the file and feed it to the user. - feed_file(req, filename); - break; - - default: - // Don't know what this is. - nout << "Unexpected downloaded file, type " << (int)req->_rtype << "\n"; - } -} - -/** - * Opens the named file (extracted from a file:// URL) and feeds its contents - * to the core API. - */ -void PPInstance:: -feed_file(PPDownloadRequest *req, const string &filename) { - StreamingFileData *file_data = new StreamingFileData(req, filename, _p3d_inst); - _file_datas.push_back(file_data); -} - -/** - * Once the instance has been created, sends it all of the data we have saved - * up for it while we were waiting. - */ -void PPInstance:: -send_p3d_temp_file_data() { - assert(_p3d_temp_file._opened); - - nout << "Sending " << _p3d_temp_file._current_size - << " preliminary bytes of " << _p3d_temp_file._total_size - << " total p3d data\n"; - - static const size_t buffer_size = 4096; - char buffer[buffer_size]; - - _p3d_temp_file.close(); - - ifstream in(_p3d_temp_file._filename.c_str(), ios::binary); - in.read(buffer, buffer_size); - size_t total = 0; - size_t count = in.gcount(); - while (count != 0) { - P3D_instance_feed_url_stream_ptr(_p3d_inst, _p3d_instance_id, - P3D_RC_in_progress, 0, - _p3d_temp_file._total_size, buffer, count); - total += count; - - in.read(buffer, buffer_size); - count = in.gcount(); - } - nout << "sent " << count << " bytes.\n"; - - in.close(); - - if (_p3d_temp_file._finished) { - // If we'd already finished the stream earlier, tell the plugin. - P3D_instance_feed_url_stream_ptr(_p3d_inst, _p3d_instance_id, - P3D_RC_done, 0, _p3d_temp_file._total_size, - nullptr, 0); - } - _p3d_temp_file.cleanup(); -} - -/** - * Checks the core API DLL file against the specification in the contents - * file, and downloads it if necessary. - */ -void PPInstance:: -get_core_api() { - if (_coreapi_dll.quick_verify(_root_dir)) { - // The DLL file is good. Just load it. - do_load_plugin(); - - } else { - // The DLL file needs to be downloaded. Build up our list of URL's to - // attempt to download it from, in reverse order. - string url; - - // Our last act of desperation: hit the original host, with a query - // uniquifier, to break through any caches. - ostringstream strm; - strm << _download_url_prefix << _coreapi_dll.get_filename() - << "?" << time(nullptr); - url = strm.str(); - _core_urls.push_back(url); - - // Before we try that, we'll hit the original host, without a uniquifier. - url = _download_url_prefix; - url += _coreapi_dll.get_filename(); - _core_urls.push_back(url); - - // And before we try that, we'll try two mirrors, at random. - vector mirrors; - choose_random_mirrors(mirrors, 2); - for (vector::iterator si = mirrors.begin(); - si != mirrors.end(); - ++si) { - url = (*si) + _coreapi_dll.get_filename(); - _core_urls.push_back(url); - } - - // Now pick the first URL off the list, and try it. - assert(!_core_urls.empty()); - url = _core_urls.back(); - _core_urls.pop_back(); - - PPDownloadRequest *req = new PPDownloadRequest(PPDownloadRequest::RT_core_dll); - start_download(url, req); - } -} - -/** - * The core API DLL has been successfully downloaded; copy it into place. - */ -void PPInstance:: -downloaded_plugin(const string &filename) { - // We could have been downloading this file as a stream, but that would - // cause problems with multiple instances downloading the plugin at the same - // time. Instead, we let them all download the file asfile, and then only - // one of them is allowed to copy it into place. - - if (is_plugin_loaded()) { - // Some other instance got there first. Just get started. - create_instance(); - return; - } - - // Make sure the DLL was correctly downloaded before continuing. - if (!_coreapi_dll.quick_verify_pathname(filename)) { - nout << "After download, " << _coreapi_dll.get_filename() << " is no good.\n"; - nout << "Expected:\n"; - _coreapi_dll.write(nout); - const FileSpec *actual = _coreapi_dll.force_get_actual_file(filename); - if (actual != nullptr) { - nout << "Found:\n"; - actual->write(nout); - } - - // That DLL came out wrong. Try the next URL. - if (!_core_urls.empty()) { - string url = _core_urls.back(); - _core_urls.pop_back(); - - _core_dll_temp_file.cleanup(); - PPDownloadRequest *req = new PPDownloadRequest(PPDownloadRequest::RT_core_dll); - start_download(url, req); - return; - } - - set_failed(); - return; - } - - // Copy the file onto the target. - string pathname = _coreapi_dll.get_pathname(_root_dir); - if (!copy_file(filename, pathname)) { - nout << "Couldn't copy " << pathname << "\n"; - set_failed(); - return; - } - - if (!_coreapi_dll.quick_verify(_root_dir)) { - nout << "After copying, " << pathname << " is no good.\n"; - set_failed(); - return; - } - - // We downloaded and installed it successfully. Now load it. - do_load_plugin(); - return; -} - - -/** - * Once the core API DLL has been downloaded, loads it into memory and starts - * the instance. - */ -void PPInstance:: -do_load_plugin() { - string pathname = _coreapi_dll.get_pathname(_root_dir); - -#ifdef P3D_PLUGIN_P3D_PLUGIN - // This is a convenience macro for development. If defined and nonempty, it - // indicates the name of the plugin DLL that we will actually run, even - // after downloading a possibly different (presumably older) version. Its - // purpose is to simplify iteration on the plugin DLL. - string override_filename = P3D_PLUGIN_P3D_PLUGIN; - if (!override_filename.empty()) { - pathname = override_filename; - } -#endif // P3D_PLUGIN_P3D_PLUGIN - - nout << "Attempting to load core API from " << pathname << "\n"; - string contents_filename = _root_dir + "/contents.xml"; - if (!load_plugin(pathname, contents_filename, PANDA_PACKAGE_HOST_URL, - P3D_VC_normal, "", "", "", false, false, - _root_dir, "", "", nout)) { - nout << "Unable to launch core API in " << pathname << "\n"; - set_failed(); - return; - } - - // Format the coreapi_timestamp as a string, for passing as a parameter. - ostringstream stream; - stream << _coreapi_dll.get_timestamp(); - string coreapi_timestamp = stream.str(); - -#ifdef PANDA_OFFICIAL_VERSION - static const bool official = true; -#else - static const bool official = false; -#endif - P3D_set_plugin_version_ptr(P3D_PLUGIN_MAJOR_VERSION, P3D_PLUGIN_MINOR_VERSION, - P3D_PLUGIN_SEQUENCE_VERSION, official, - PANDA_DISTRIBUTOR, - PANDA_PACKAGE_HOST_URL, coreapi_timestamp.c_str(), - _coreapi_set_ver.c_str()); - - create_instance(); -} - -/** - * Actually creates the internal P3D_instance object, if possible and needed. - */ -void PPInstance:: -create_instance() { - if (_started) { - // Already created. - return; - } - - if (!is_plugin_loaded()) { - // Plugin is not loaded yet. - return; - } - -#ifdef __APPLE__ - // We no longer need to twirl the icon. Stop the timer. - if (_twirl_timer != nullptr) { - CFRunLoopTimerInvalidate(_twirl_timer); - CFRelease(_twirl_timer); - _twirl_timer = nullptr; - } -#endif // __APPLE__ - -#ifdef HAVE_X11 - x11_stop_twirl_subprocess(); -#endif // HAVE_X11 - - // In the Windows case, we let the timer keep running, because it also - // checks for wayward messages. - - P3D_token *tokens = nullptr; - if (!_tokens.empty()) { - tokens = &_tokens[0]; - } - _started = true; - _p3d_inst = P3D_new_instance_ptr(request_ready, tokens, _tokens.size(), - 0, nullptr, this); - if (_p3d_inst == nullptr) { - set_failed(); - return; - } - - // Now get the browser's toplevel DOM object (called the "window" object in - // JavaScript), to pass to the plugin. - NPObject *window_object = nullptr; - if (browser->getvalue(_npp_instance, NPNVWindowNPObject, - &window_object) == NPERR_NO_ERROR) { - PPBrowserObject *pobj = new PPBrowserObject(this, window_object); - P3D_instance_set_browser_script_object_ptr(_p3d_inst, pobj); - browser->releaseobject(window_object); - } else { - nout << "Couldn't get window_object\n"; - } - - if (_script_object != nullptr) { - // Now that we have a true instance, initialize our script_object with the - // proper P3D_object pointer. - P3D_object *main = P3D_instance_get_panda_script_object_ptr(_p3d_inst); - nout << "new instance, setting main = " << main << "\n"; - _script_object->set_main(main); - } - - if (_got_instance_url) { - // Create the user_id for streaming the p3d data into the instance. - _p3d_instance_id = P3D_instance_start_stream_ptr(_p3d_inst, _instance_url.c_str()); - nout << "p3d instance to stream " << _p3d_instance_id << "\n"; - - // If we have already started to receive any instance data, send it to the - // plugin now. - if (_p3d_temp_file._opened) { - send_p3d_temp_file_data(); - } - } - - if (_got_window) { - send_window(); - } -} - - -/** - * Actually issues the window parameters to the internal P3D_instance object. - */ -void PPInstance:: -send_window() { - assert(_p3d_inst != nullptr); - - int x = _window.x; - int y = _window.y; - - P3D_window_handle parent_window; - memset(&parent_window, 0, sizeof(parent_window)); - parent_window._window_handle_type = P3D_WHT_none; - - if (_window.type == NPWindowTypeWindow) { - // We have a "windowed" plugin. Parent our window to the one we were - // given. In this case, we should also reset the offset to (0, 0), since - // the window we were given is already placed in the right spot. -#ifdef _WIN32 - assert(!_use_xembed); - parent_window._window_handle_type = P3D_WHT_win_hwnd; - parent_window._handle._win_hwnd._hwnd = (HWND)(_window.window); - x = 0; - y = 0; - -#elif defined(__APPLE__) - assert(!_use_xembed); - parent_window._window_handle_type = _window_handle_type; - if (_window_handle_type == P3D_WHT_osx_port) { -#if !__LP64__ - NP_Port *port = (NP_Port *)_window.window; - parent_window._handle._osx_port._port = port->port; -#endif - } else if (_window_handle_type == P3D_WHT_osx_cgcontext) { - NP_CGContext *context = (NP_CGContext *)_window.window; - if (context != nullptr) { - parent_window._handle._osx_cgcontext._context = context->context; - parent_window._handle._osx_cgcontext._window = (WindowRef)context->window; - } - } - -#elif defined(HAVE_X11) - if (_use_xembed) { - // If we're using the XEmbed model, we've actually received an XID for a - // GtkSocket. -#ifdef HAVE_GTK - // If we're using XEmbed, pass the X11 Window pointer of our plug down - // to Panda. (Hmm, it would be nice to pass the XID object and use this - // system in general within Panda, but that's for the future, I think.) - assert(_plug != nullptr); - parent_window._window_handle_type = P3D_WHT_x11_window; - parent_window._handle._x11_window._xwindow = GDK_DRAWABLE_XID(_plug->window); -#endif // HAVE_GTK - } else { - // If we're not using XEmbed, this is just a standard X11 Window - // pointer. - parent_window._window_handle_type = P3D_WHT_x11_window; - parent_window._handle._x11_window._xwindow = (X11_Window)(_window.window); - } - x = 0; - y = 0; -#endif - - } else { - // We have a "windowless" plugin. Parent our window directly to the - // browser window. -#ifdef _WIN32 - HWND hwnd; - if (browser->getvalue(_npp_instance, NPNVnetscapeWindow, - &hwnd) == NPERR_NO_ERROR) { - parent_window._window_handle_type = P3D_WHT_win_hwnd; - parent_window._handle._win_hwnd._hwnd = hwnd; - } - -#elif defined(__APPLE__) - parent_window._window_handle_type = _window_handle_type; - if (_window_handle_type == P3D_WHT_osx_port) { -#if !__LP64__ - NP_Port *port = (NP_Port *)_window.window; - parent_window._handle._osx_port._port = port->port; -#endif - } else if (_window_handle_type == P3D_WHT_osx_cgcontext) { - NP_CGContext *context = (NP_CGContext *)_window.window; - if (context != nullptr) { - parent_window._handle._osx_cgcontext._context = context->context; - parent_window._handle._osx_cgcontext._window = (WindowRef)context->window; - } - } - -#elif defined(HAVE_X11) - unsigned long win; - if (browser->getvalue(_npp_instance, NPNVnetscapeWindow, - &win) == NPERR_NO_ERROR) { - parent_window._window_handle_type = P3D_WHT_x11_window; - parent_window._handle._x11_window._xwindow = win; - } -#endif - } - -#ifdef HAVE_X11 - // In the case of X11, grab the display as well. - parent_window._handle._x11_window._xdisplay = 0; - void *disp; - if (browser->getvalue(_npp_instance, NPNVxDisplay, - &disp) == NPERR_NO_ERROR) { - parent_window._handle._x11_window._xdisplay = disp; - } -#endif - - P3D_window_type window_type = P3D_WT_embedded; - if (_window.window == nullptr && _event_type != P3D_ET_osx_cocoa) { - // No parent window: it must be a hidden window. - window_type = P3D_WT_hidden; - } else if (_window.width == 0 || _window.height == 0) { - // No size: hidden. - window_type = P3D_WT_hidden; - } - - P3D_instance_setup_window_ptr - (_p3d_inst, window_type, - x, y, _window.width, _window.height, - &parent_window); -} - -/** - * Called at instance shutdown, this restores the parent window to its - * original state. - */ -void PPInstance:: -cleanup_window() { - if (_got_window) { -#ifdef _WIN32 - // Restore the parent window to its own window handler. - HWND hwnd = (HWND)_window.window; - SetWindowLongPtr(hwnd, GWLP_WNDPROC, _orig_window_proc); - InvalidateRect(hwnd, nullptr, true); - - if (_bg_brush != nullptr) { - DeleteObject(_bg_brush); - _bg_brush = nullptr; - } - for (int step = 0; step < twirl_num_steps + 1; ++step) { - if (_twirl_bitmaps[step] != nullptr) { - DeleteObject(_twirl_bitmaps[step]); - _twirl_bitmaps[step] = nullptr; - } - } -#endif // _WIN32 - -#ifdef HAVE_X11 - x11_stop_twirl_subprocess(); - -#ifdef HAVE_GTK - if (_plug != nullptr) { - gtk_widget_destroy(_plug); - _plug = nullptr; - } -#endif // HAVE_GTK -#endif // HAVE_X11 - - _got_window = false; - } -} - -/** - * Copies the data in the file named by from_filename into the file named by - * to_filename. - */ -bool PPInstance:: -copy_file(const string &from_filename, const string &to_filename) { - mkfile_complete(to_filename, nout); - ifstream in(from_filename.c_str(), ios::in | ios::binary); - ofstream out(to_filename.c_str(), ios::out | ios::binary); - - static const size_t buffer_size = 4096; - char buffer[buffer_size]; - - in.read(buffer, buffer_size); - size_t count = in.gcount(); - while (count != 0) { - out.write(buffer, count); - if (out.fail()) { - return false; - } - in.read(buffer, buffer_size); - count = in.gcount(); - } - - if (!in.eof()) { - return false; - } - - return true; -} - -/** - * Returns the value associated with the first appearance of the named token, - * or empty string if the token does not appear. - */ -string PPInstance:: -lookup_token(const string &keyword) const { - Tokens::const_iterator ti; - for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) { - if (keyword == (*ti)._keyword) { - return (*ti)._value; - } - } - - return string(); -} - -/** - * Returns true if the named token appears in the list, false otherwise. - */ -bool PPInstance:: -has_token(const string &keyword) const { - Tokens::const_iterator ti; - for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) { - if ((*ti)._keyword == keyword) { - return true; - } - } - - return false; -} - - -/** - * Compares the two dotted-integer sequence values numerically. Returns -1 if - * seq_a sorts first, 1 if seq_b sorts first, 0 if they are equivalent. - */ -int PPInstance:: -compare_seq(const string &seq_a, const string &seq_b) { - const char *num_a = seq_a.c_str(); - const char *num_b = seq_b.c_str(); - int comp = compare_seq_int(num_a, num_b); - while (comp == 0) { - if (*num_a != '.') { - if (*num_b != '.') { - // Both strings ran out together. - return 0; - } - // a ran out first. - return -1; - } else if (*num_b != '.') { - // b ran out first. - return 1; - } - - // Increment past the dot. - ++num_a; - ++num_b; - comp = compare_seq(num_a, num_b); - } - - return comp; -} - -/** - * Numerically compares the formatted integer value at num_a with num_b. - * Increments both num_a and num_b to the next character following the valid - * integer. - */ -int PPInstance:: -compare_seq_int(const char *&num_a, const char *&num_b) { - long int a; - char *next_a; - long int b; - char *next_b; - - a = strtol((char *)num_a, &next_a, 10); - b = strtol((char *)num_b, &next_b, 10); - - num_a = next_a; - num_b = next_b; - - if (a < b) { - return -1; - } else if (b < a) { - return 1; - } else { - return 0; - } -} - -/** - * Called when something has gone wrong that prevents the plugin instance from - * running. Specifically, this means it failed to load the core API. - */ -void PPInstance:: -set_failed() { - if (!_failed) { - _failed = true; - - nout << "Plugin failed.\n"; - stop_outstanding_streams(); - - // Look for the "onpluginfail" token. - string expression = lookup_token("onpluginfail"); - - if (!expression.empty()) { - // Now attempt to evaluate the expression. - NPObject *window_object = nullptr; - if (browser->getvalue(_npp_instance, NPNVWindowNPObject, - &window_object) == NPERR_NO_ERROR) { - NPString npexpr = { expression.c_str(), (uint32_t)expression.length() }; - NPVariant result; - if (browser->evaluate(_npp_instance, window_object, - &npexpr, &result)) { - nout << "Eval " << expression << "\n"; - browser->releasevariantvalue(&result); - } else { - nout << "Unable to eval " << expression << "\n"; - } - - browser->releaseobject(window_object); - } - } - - if (_p3d_inst != nullptr) { - P3D_instance_finish_ptr(_p3d_inst); - _p3d_inst = nullptr; - } - cleanup_window(); - } -} - -/** - * Checks for any new requests from the plugin, and dispatches them to the - * appropriate PPInstance. This function is called only in the main thread. - */ -void PPInstance:: -handle_request_loop() { - if (!is_plugin_loaded()) { - return; - } - - P3D_instance *p3d_inst = P3D_check_request_ptr(0.0); - while (p3d_inst != nullptr) { - P3D_request *request = P3D_instance_get_request_ptr(p3d_inst); - if (request != nullptr) { - PPInstance *inst = (PPInstance *)(p3d_inst->_user_data); - assert(inst != nullptr); - if (!inst->handle_request(request)) { - // If handling the request is meant to yield control temporarily to - // JavaScript (e.g. P3D_RT_callback), then do so now. - return; - } - - if (!is_plugin_loaded()) { - // Oops, we may have unloaded the plugin as an indirect effect of - // handling the request. If so, get out of here. - return; - } - } - p3d_inst = P3D_check_request_ptr(0.0); - } - - // Also check to see if we have any file_data objects that have finished and - // may be deleted. - size_t num_file_datas = _file_datas.size(); - size_t i = 0; - while (i < num_file_datas) { - if (!_file_datas[i]->is_done()) { - // This one keeps going. - ++i; - } else { - // This one is done. - delete _file_datas[i]; - _file_datas.erase(_file_datas.begin() + i); - --num_file_datas; - } - } -} - -/** - * This callback hook is passed to NPN_PluginThreadAsyncCall() (if that - * function is available) to forward a request to the main thread. The - * callback is actually called in the main thread. - */ -void PPInstance:: -browser_sync_callback(void *) { - handle_request_loop(); -} - - -#ifdef _WIN32 -/** - * We bind this function to the parent window we were given in set_window, so - * we can spin the request_loop when needed. This is only in the Windows - * case; other platforms rely on explicit windows events. - */ -LONG PPInstance:: -st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - LONG_PTR self = GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (self == nullptr) { - // We haven't assigned the pointer yet (!?) - return DefWindowProc(hwnd, msg, wparam, lparam); - } - - return ((PPInstance *)self)->window_proc(hwnd, msg, wparam, lparam); -} -#endif // _WIN32 - -#ifdef _WIN32 -/** - * The non-static window_proc() function. - * - * We bind this function to the parent window we were given in set_window, so - * we can spin the request_loop when needed. This is only in the Windows - * case; other platforms rely on explicit windows events. - */ -LONG PPInstance:: -window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - if (!has_plugin_thread_async_call) { - // Since we're here in the main thread, call handle_request_loop() to see - // if there are any new requests to be serviced by the main thread. - handle_request_loop(); - } - - switch (msg) { - case WM_ERASEBKGND: - // Eat the WM_ERASEBKGND message, so the browser's intervening window - // won't overdraw on top of our own window. - return true; - - case WM_PAINT: - if (!_started) { - // If we haven't yet loaded the instance, we can paint a twirling icon - // in the window. - PAINTSTRUCT ps; - HDC dc = BeginPaint(hwnd, &ps); - win_paint_twirl(hwnd, dc); - EndPaint(hwnd, &ps); - } - return true; - - case WM_TIMER: - if (!_started) { - InvalidateRect(_hwnd, nullptr, FALSE); - } - break; - - case WM_USER: - break; - } - - return DefWindowProc(hwnd, msg, wparam, lparam); -} -#endif // _WIN32 - - -#ifdef _WIN32 -/** - * Fills _twirl_bitmaps with an array of bitmaps for drawing the twirling icon - * while we're waiting for the instance to load. - */ -void PPInstance:: -win_get_twirl_bitmaps() { - BITMAPINFOHEADER bmih; - bmih.biSize = sizeof(bmih); - bmih.biWidth = twirl_width; - bmih.biHeight = -twirl_height; - bmih.biPlanes = 1; - bmih.biBitCount = 32; - bmih.biCompression = BI_RGB; - bmih.biSizeImage = 0; - bmih.biXPelsPerMeter = 0; - bmih.biYPelsPerMeter = 0; - bmih.biClrUsed = 0; - bmih.biClrImportant = 0; - - BITMAPINFO bmi; - memcpy(&bmi, &bmih, sizeof(bmih)); - - HDC dc = GetDC(_hwnd); - - static const size_t twirl_size = twirl_width * twirl_height; - unsigned char twirl_data[twirl_size * 3]; - unsigned char new_data[twirl_size * 4]; - - for (int step = 0; step < twirl_num_steps + 1; ++step) { - get_twirl_data(twirl_data, twirl_size, step, - _fgcolor_r, _fgcolor_g, _fgcolor_b, - _bgcolor_r, _bgcolor_g, _bgcolor_b); - - // Expand out the RGB channels into RGBA. - for (int yi = 0; yi < twirl_height; ++yi) { - const unsigned char *sp = twirl_data + yi * twirl_width * 3; - unsigned char *dp = new_data + yi * twirl_width * 4; - for (int xi = 0; xi < twirl_width; ++xi) { - // RGB <= BGR. - dp[0] = sp[2]; - dp[1] = sp[1]; - dp[2] = sp[0]; - dp[3] = (unsigned char)0xff; - sp += 3; - dp += 4; - } - } - - // Now load the image. - _twirl_bitmaps[step] = CreateDIBitmap(dc, &bmih, CBM_INIT, (const char *)new_data, &bmi, 0); - } - - ReleaseDC(_hwnd, dc); -} -#endif // _WIN32 - -#ifdef _WIN32 -/** - * Paints the twirling icon into the browser window before the instance has - * started. - */ -void PPInstance:: -win_paint_twirl(HWND hwnd, HDC dc) { - RECT rect; - GetClientRect(_hwnd, &rect); - int width = rect.right - rect.left; - int height = rect.bottom - rect.top; - - // Double-buffer with an offscreen bitmap first. - HDC bdc = CreateCompatibleDC(dc); - HBITMAP buffer = CreateCompatibleBitmap(dc, width, height); - SelectObject(bdc, buffer); - - // Start by painting the background color. - FillRect(bdc, &rect, _bg_brush); - - if (!_started) { - DWORD now = GetTickCount(); - // Don't draw the twirling icon until at least half a second has passed, - // so we don't distract people by drawing it unnecessarily. - if (_failed || (now - _init_time) >= 500) { - // Which frame are we drawing? - int step = (now / 100) % twirl_num_steps; - if (_failed) { - step = twirl_num_steps; - } - - HBITMAP twirl = _twirl_bitmaps[step]; - - int left = rect.left + (width - twirl_width) / 2; - int top = rect.top + (height - twirl_height) / 2; - - HDC mem_dc = CreateCompatibleDC(bdc); - SelectObject(mem_dc, twirl); - - BitBlt(bdc, left, top, twirl_width, twirl_height, - mem_dc, 0, 0, SRCCOPY); - - SelectObject(mem_dc, nullptr); - DeleteDC(mem_dc); - } - } - - // Now blit the buffer to the window. - BitBlt(dc, 0, 0, width, height, bdc, 0, 0, SRCCOPY); -} -#endif // _WIN32 - -#ifdef MACOSX_HAS_EVENT_MODELS -/** - * Copies the NPCocoaEvent structure componentwise into a P3DCocoaEvent - * structure, for passing into the core API. - * - * The aux_data object is used to manage temporary storage on the strings - * created for the event. - */ -void PPInstance:: -copy_cocoa_event(P3DCocoaEvent *p3d_event, NPCocoaEvent *np_event, - EventAuxData &aux_data) { - p3d_event->version = np_event->version; - - switch (np_event->type) { - case NPCocoaEventDrawRect: - p3d_event->type = P3DCocoaEventDrawRect; - break; - case NPCocoaEventMouseDown: - p3d_event->type = P3DCocoaEventMouseDown; - break; - case NPCocoaEventMouseUp: - p3d_event->type = P3DCocoaEventMouseUp; - break; - case NPCocoaEventMouseMoved: - p3d_event->type = P3DCocoaEventMouseMoved; - break; - case NPCocoaEventMouseEntered: - p3d_event->type = P3DCocoaEventMouseEntered; - break; - case NPCocoaEventMouseExited: - p3d_event->type = P3DCocoaEventMouseExited; - break; - case NPCocoaEventMouseDragged: - p3d_event->type = P3DCocoaEventMouseDragged; - break; - case NPCocoaEventKeyDown: - p3d_event->type = P3DCocoaEventKeyDown; - break; - case NPCocoaEventKeyUp: - p3d_event->type = P3DCocoaEventKeyUp; - break; - case NPCocoaEventFlagsChanged: - p3d_event->type = P3DCocoaEventFlagsChanged; - break; - case NPCocoaEventFocusChanged: - p3d_event->type = P3DCocoaEventFocusChanged; - break; - case NPCocoaEventWindowFocusChanged: - p3d_event->type = P3DCocoaEventWindowFocusChanged; - break; - case NPCocoaEventScrollWheel: - p3d_event->type = P3DCocoaEventScrollWheel; - break; - case NPCocoaEventTextInput: - p3d_event->type = P3DCocoaEventTextInput; - break; - } - - switch (np_event->type) { - case NPCocoaEventDrawRect: - p3d_event->data.draw.context = np_event->data.draw.context; - p3d_event->data.draw.x = np_event->data.draw.x; - p3d_event->data.draw.y = np_event->data.draw.y; - p3d_event->data.draw.width = np_event->data.draw.width; - p3d_event->data.draw.height = np_event->data.draw.height; - break; - - case NPCocoaEventMouseDown: - case NPCocoaEventMouseUp: - case NPCocoaEventMouseMoved: - case NPCocoaEventMouseEntered: - case NPCocoaEventMouseExited: - case NPCocoaEventMouseDragged: - case NPCocoaEventScrollWheel: - p3d_event->data.mouse.modifierFlags = np_event->data.mouse.modifierFlags; - p3d_event->data.mouse.pluginX = np_event->data.mouse.pluginX; - p3d_event->data.mouse.pluginY = np_event->data.mouse.pluginY; - p3d_event->data.mouse.buttonNumber = np_event->data.mouse.buttonNumber; - p3d_event->data.mouse.clickCount = np_event->data.mouse.clickCount; - p3d_event->data.mouse.deltaX = np_event->data.mouse.deltaX; - p3d_event->data.mouse.deltaY = np_event->data.mouse.deltaY; - p3d_event->data.mouse.deltaZ = np_event->data.mouse.deltaZ; - break; - - case NPCocoaEventKeyDown: - case NPCocoaEventKeyUp: - case NPCocoaEventFlagsChanged: - p3d_event->data.key.modifierFlags = np_event->data.key.modifierFlags; - p3d_event->data.key.characters = - make_ansi_string(aux_data._characters, np_event->data.key.characters); - p3d_event->data.key.charactersIgnoringModifiers = - make_ansi_string(aux_data._characters_im, np_event->data.key.charactersIgnoringModifiers); - p3d_event->data.key.isARepeat = np_event->data.key.isARepeat; - p3d_event->data.key.keyCode = np_event->data.key.keyCode; - break; - - case NPCocoaEventFocusChanged: - case NPCocoaEventWindowFocusChanged: - p3d_event->data.focus.hasFocus = np_event->data.focus.hasFocus; - break; - - case NPCocoaEventTextInput: - p3d_event->data.text.text = - make_ansi_string(aux_data._text, np_event->data.text.text); - break; - } -} -#endif // MACOSX_HAS_EVENT_MODELS - -#ifdef MACOSX_HAS_EVENT_MODELS -/** - * OSX only: Fills result with the unicode characters in the NPNSString. Also - * returns result.c_str(). - */ -const wchar_t *PPInstance:: -make_ansi_string(std::wstring &result, NPNSString *ns_string) { - result.clear(); - - if (ns_string != nullptr) { - // An NPNSString is really just an NSString, which is itself just a - // CFString. - CFStringRef cfstr = (CFStringRef)ns_string; - CFIndex length = CFStringGetLength(cfstr); - - for (CFIndex i = 0; i < length; ++i) { - result += (wchar_t)CFStringGetCharacterAtIndex(cfstr, i); - } - } - - return result.c_str(); -} -#endif // MACOSX_HAS_EVENT_MODELS - -#ifdef MACOSX_HAS_EVENT_MODELS -/** - * Locally processes a Cocoa event for the window before sending it down to - * the Core API. This is used for drawing a twirling icon in the window while - * the Core API is downloading. - */ -void PPInstance:: -handle_cocoa_event(const P3DCocoaEvent *p3d_event) { - switch (p3d_event->type) { - case P3DCocoaEventDrawRect: - if (!_started) { - CGContextRef context = p3d_event->data.draw.context; - paint_twirl_osx_cgcontext(context); - } - break; - - default: - break; - } -} -#endif // MACOSX_HAS_EVENT_MODELS - -#ifdef MACOSX_HAS_EVENT_MODELS -/** - * Fills _twirl_images with an array of images for drawing the twirling icon - * while we're waiting for the instance to load. - */ -void PPInstance:: -osx_get_twirl_images() { - if (_got_twirl_images) { - return; - } - _got_twirl_images = true; - - static const size_t twirl_size = twirl_width * twirl_height; - unsigned char twirl_data[twirl_size * 3]; - - for (int step = 0; step < twirl_num_steps + 1; ++step) { - get_twirl_data(twirl_data, twirl_size, step, - _fgcolor_r, _fgcolor_g, _fgcolor_b, - _bgcolor_r, _bgcolor_g, _bgcolor_b); - - unsigned char *new_data = new unsigned char[twirl_size * 4]; - - // Expand the RGB channels into RGBA. Flip upside-down too. - for (int yi = 0; yi < twirl_height; ++yi) { - const unsigned char *sp = twirl_data + (twirl_height - 1 - yi) * twirl_width * 3; - unsigned char *dp = new_data + yi * twirl_width * 4; - for (int xi = 0; xi < twirl_width; ++xi) { - // RGB <= BGR. - dp[0] = sp[2]; - dp[1] = sp[1]; - dp[2] = sp[0]; - dp[3] = (unsigned char)0xff; - sp += 3; - dp += 4; - } - } - - OsxImageData &image = _twirl_images[step]; - image._raw_data = new_data; - - image._data = - CFDataCreateWithBytesNoCopy(nullptr, (const UInt8 *)image._raw_data, - twirl_size * 4, kCFAllocatorNull); - image._provider = CGDataProviderCreateWithCFData(image._data); - image._color_space = CGColorSpaceCreateDeviceRGB(); - - image._image = - CGImageCreate(twirl_width, twirl_height, 8, 32, - twirl_width * 4, image._color_space, - kCGImageAlphaFirst | kCGBitmapByteOrder32Little, - image._provider, nullptr, false, kCGRenderingIntentDefault); - } -} -#endif // MACOSX_HAS_EVENT_MODELS - -#ifdef MACOSX_HAS_EVENT_MODELS -/** - * Frees the twirl_images array. - */ -void PPInstance:: -osx_release_twirl_images() { - if (!_got_twirl_images) { - return; - } - _got_twirl_images = false; - - for (int step = 0; step < twirl_num_steps + 1; ++step) { - OsxImageData &image = _twirl_images[step]; - - if (image._image != nullptr) { - CGImageRelease(image._image); - image._image = nullptr; - } - if (image._color_space != nullptr) { - CGColorSpaceRelease(image._color_space); - image._color_space = nullptr; - } - if (image._provider != nullptr) { - CGDataProviderRelease(image._provider); - image._provider = nullptr; - } - if (image._data != nullptr) { - CFRelease(image._data); - image._data = nullptr; - } - if (image._raw_data != nullptr) { - delete[] image._raw_data; - image._raw_data = nullptr; - } - } -} -#endif // MACOSX_HAS_EVENT_MODELS - -#ifdef MACOSX_HAS_EVENT_MODELS -/** - * Actually paints the twirling icon in the OSX window, using Core Graphics. - * (We don't bother painting it in the older Cocoa interface.) - */ -void PPInstance:: -paint_twirl_osx_cgcontext(CGContextRef context) { - // Clear the whole region to the bgcolor before beginning. - float bg_components[] = { _bgcolor_r / 255.0f, _bgcolor_g / 255.0f, _bgcolor_b / 255.0f, 1 }; - CGColorSpaceRef rgb_space = CGColorSpaceCreateDeviceRGB(); - CGColorRef bg = CGColorCreate(rgb_space, bg_components); - - CGRect region = { { 0, 0 }, { _window.width, _window.height } }; - CGContextBeginPath(context); - CGContextSetFillColorWithColor(context, bg); - CGContextAddRect(context, region); - CGContextFillPath(context); - - CGColorRelease(bg); - CGColorSpaceRelease(rgb_space); - - if (_failed) { - // Draw the failed icon if something went wrong. - osx_paint_image(context, _twirl_images[twirl_num_steps]); - - } else { - struct timeval tv; - gettimeofday(&tv, nullptr); - double now = (double)(tv.tv_sec - _init_sec) + (double)(tv.tv_usec - _init_usec) / 1000000.0; - - // Don't draw the twirling icon until at least half a second has passed, - // so we don't distract people by drawing it unnecessarily. - if (now >= 0.5) { - int step = ((int)(now * 10.0)) % twirl_num_steps; - osx_paint_image(context, _twirl_images[step]); - } - } -} -#endif // MACOSX_HAS_EVENT_MODELS - -#ifdef MACOSX_HAS_EVENT_MODELS -/** - * Draws the indicated image, centered within the window. Returns true on - * success, false if the image is not defined. - */ -bool PPInstance:: -osx_paint_image(CGContextRef context, const OsxImageData &image) { - if (image._image == nullptr) { - return false; - } - - // Determine the relative size of image and window. - int win_cx = _window.width / 2; - int win_cy = _window.height / 2; - - CGRect rect = { { 0, 0 }, { 0, 0 } }; - - // The bitmap fits within the window; center it. - - // This is the top-left corner of the bitmap in window coordinates. - int p_x = win_cx - twirl_width / 2; - int p_y = win_cy - twirl_height / 2; - - rect.origin.x += p_x; - rect.origin.y += p_y; - rect.size.width = twirl_width; - rect.size.height = twirl_height; - - CGContextDrawImage(context, rect, image._image); - - return true; -} -#endif // MACOSX_HAS_EVENT_MODELS - -#ifdef __APPLE__ -/** - * OSX only: this callback is associated with a CFRunLoopTimer; it's used to - * forward request messages to the main thread. - */ -void PPInstance:: -timer_callback(CFRunLoopTimerRef timer, void *info) { - PPInstance *self = (PPInstance *)info; - ACQUIRE_LOCK(self->_timer_lock); - if (self->_request_timer != nullptr) { - CFRunLoopTimerInvalidate(self->_request_timer); - CFRelease(self->_request_timer); - self->_request_timer = nullptr; - } - RELEASE_LOCK(self->_timer_lock); - - self->handle_request_loop(); -} -#endif // __APPLE__ - -#ifdef __APPLE__ -/** - * OSX only: this callback is used to twirl the icon before the instance - * loads. - */ -void PPInstance:: -st_twirl_timer_callback(CFRunLoopTimerRef timer, void *info) { - PPInstance *self = (PPInstance *)info; - self->twirl_timer_callback(); -} -#endif // __APPLE__ - -#ifdef __APPLE__ -/** - * OSX only: this callback is used to twirl the icon before the instance - * loads. - */ -void PPInstance:: -twirl_timer_callback() { - if (_got_window) { - NPRect rect = { 0, 0, (unsigned short)_window.height, (unsigned short)_window.width }; - browser->invalidaterect(_npp_instance, &rect); - } -} -#endif // __APPLE__ - -#ifdef HAVE_X11 -/** - * Spawns a separate process to twirl the loading icon in the X11 browser - * window. - */ -void PPInstance:: -x11_start_twirl_subprocess() { - if (_twirl_subprocess_pid != -1) { - // Already started. - return; - } - - // Fork and exec. - pid_t child = fork(); - if (child < 0) { - perror("fork"); - return; - } - - if (child == 0) { - // Here we are in the child process. - x11_twirl_subprocess_run(); - _exit(99); - } - - // In the parent process. - _twirl_subprocess_pid = child; - nout << "Started twirl subprocess, pid " << _twirl_subprocess_pid - << "\n"; -} -#endif // HAVE_X11 - -#ifdef HAVE_X11 -/** - * Kills the twirl process that was started earlier. - */ -void PPInstance:: -x11_stop_twirl_subprocess() { - if (_twirl_subprocess_pid == -1) { - // Already stopped. - return; - } - - kill(_twirl_subprocess_pid, SIGKILL); - - int status; - pid_t result = waitpid(_twirl_subprocess_pid, &status, 0); - - nout << "Twirl window process has successfully stopped.\n"; - if (WIFEXITED(status)) { - nout << " exited normally, status = " - << WEXITSTATUS(status) << "\n"; - } else if (WIFSIGNALED(status)) { - nout << " signalled by " << WTERMSIG(status) << ", core = " - << WCOREDUMP(status) << "\n"; - } else if (WIFSTOPPED(status)) { - nout << " stopped by " << WSTOPSIG(status) << "\n"; - } - _twirl_subprocess_pid = -1; -} -#endif // HAVE_X11 - -#ifdef HAVE_X11 -/** - * The code that is run within a subprocess. This code is responsible for - * twirling the loading icon endlessly. - */ -void PPInstance:: -x11_twirl_subprocess_run() { - // Since everything within this function happens within a subprocess that - // will just exit, we can be a little sloppy with our resource allocation. - // It is all done directly within this function, and we don't need to worry - // about freeing stuff. - - // First, sleep for 0.5 seconds, so we don't start twirling right away (to - // avoid distracting the user unnecessarily). - - struct timespec req; - req.tv_sec = 0; - req.tv_nsec = 500000000; // 500 ms - nanosleep(&req, nullptr); - - // We haven't been killed yet, so the plugin is still loading. Start - // twirling. - - // First, embed a window. - X11_Display *display = XOpenDisplay(nullptr); - assert(display != nullptr); - int screen = DefaultScreen(display); - - int depth = DefaultDepth(display, screen); - Visual *dvisual = DefaultVisual(display, screen); - - long event_mask = ExposureMask; - - // Allocate the foreground and background colors. - Colormap colormap = DefaultColormap(display, screen); - - XColor fg; - fg.red = _fgcolor_r * 0x101; - fg.green = _fgcolor_g * 0x101; - fg.blue = _fgcolor_b * 0x101; - fg.flags = DoRed | DoGreen | DoBlue; - unsigned long fg_pixel = -1; - if (XAllocColor(display, colormap, &fg)) { - fg_pixel = fg.pixel; - } - - XColor bg; - bg.red = _bgcolor_r * 0x101; - bg.green = _bgcolor_g * 0x101; - bg.blue = _bgcolor_b * 0x101; - bg.flags = DoRed | DoGreen | DoBlue; - unsigned long bg_pixel = -1; - if (XAllocColor(display, colormap, &bg)) { - bg_pixel = bg.pixel; - } - - // Initialize window attributes - XSetWindowAttributes wa; - wa.background_pixel = XWhitePixel(display, screen); - if (bg_pixel != -1) { - wa.background_pixel = bg_pixel; - } - wa.border_pixel = 0; - wa.event_mask = event_mask; - - unsigned long attrib_mask = CWBackPixel | CWBorderPixel | CWEventMask; - - X11_Window parent = 0; - if (_use_xembed) { -#ifdef HAVE_GTK - assert(_plug != nullptr); - parent = GDK_DRAWABLE_XID(_plug->window); -#endif // HAVE_GTK - } else { - parent = (X11_Window)(_window.window); - } - - X11_Window window = XCreateWindow - (display, parent, 0, 0, _window.width, _window.height, - 0, depth, InputOutput, dvisual, attrib_mask, &wa); - XMapWindow(display, window); - - // Create a graphics context. - XGCValues gcval; - gcval.function = GXcopy; - gcval.plane_mask = AllPlanes; - gcval.foreground = BlackPixel(display, screen); - if (fg_pixel != -1) { - gcval.foreground = fg_pixel; - } - gcval.background = WhitePixel(display, screen); - if (bg_pixel != -1) { - gcval.background = bg_pixel; - } - GC graphics_context = XCreateGC(display, window, - GCFunction | GCPlaneMask | GCForeground | GCBackground, &gcval); - - // Load up the twirling images. - XImage *images[twirl_num_steps]; - double r_ratio = dvisual->red_mask / 255.0; - double g_ratio = dvisual->green_mask / 255.0; - double b_ratio = dvisual->blue_mask / 255.0; - - static const size_t twirl_size = twirl_width * twirl_height; - unsigned char twirl_data[twirl_size * 3]; - - for (int step = 0; step < twirl_num_steps; ++step) { - get_twirl_data(twirl_data, twirl_size, step, - _fgcolor_r, _fgcolor_g, _fgcolor_b, - _bgcolor_r, _bgcolor_g, _bgcolor_b); - uint32_t *new_data = new uint32_t[twirl_size]; - int j = 0; - for (int i = 0; i < twirl_size * 3; i += 3) { - unsigned int r, g, b; - r = (unsigned int)(twirl_data[i+0] * r_ratio); - g = (unsigned int)(twirl_data[i+1] * g_ratio); - b = (unsigned int)(twirl_data[i+2] * b_ratio); - new_data[j++] = ((r & dvisual->red_mask) | - (g & dvisual->green_mask) | - (b & dvisual->blue_mask)); - } - - // Now load the image. - images[step] = XCreateImage(display, CopyFromParent, DefaultDepth(display, screen), - ZPixmap, 0, (char *)new_data, twirl_width, twirl_height, 32, 0); - } - - // Now twirl indefinitely, until our parent process kills us. - bool needs_redraw = true; - int last_step = -1; - while (true) { - // First, scan for X events. - XEvent event; - while (XCheckWindowEvent(display, window, ~0, &event)) { - switch (event.type) { - case Expose: - case GraphicsExpose: - needs_redraw = true; - break; - } - - // We should probably track the resize event, but this window will be - // short-lived (and probably won't have an opportunity to resize anyway) - // so we don't bother. - } - - // What step are we on now? - struct timeval tv; - gettimeofday(&tv, nullptr); - double now = (double)(tv.tv_sec - _init_sec) + (double)(tv.tv_usec - _init_usec) / 1000000.0; - int step = ((int)(now * 10.0)) % twirl_num_steps; - if (step != last_step) { - needs_redraw = true; - } - - if (needs_redraw) { - XClearWindow(display, window); - int xo = (_window.width - twirl_width) / 2; - int yo = (_window.height - twirl_height) / 2; - XPutImage(display, window, graphics_context, images[step], 0, 0, - xo, yo, twirl_width, twirl_height); - - XFlush(display); - needs_redraw = false; - last_step = step; - } - - struct timespec req; - req.tv_sec = 0; - req.tv_nsec = 100000000; // 100 ms - nanosleep(&req, nullptr); - } -} -#endif // HAVE_X11 - -/** - * - */ -PPInstance::StreamingFileData:: -StreamingFileData(PPDownloadRequest *req, const string &filename, - P3D_instance *p3d_inst) : - _p3d_inst(p3d_inst), - _user_id(req->_user_id), - _filename(filename), - _file(filename.c_str(), ios::in | ios::binary) -{ - // First, seek to the end to get the file size. - _file.seekg(0, ios::end); - _file_size = _file.tellg(); - _total_count = 0; - - // Then return to the beginning to read the data. - _file.seekg(0, ios::beg); - - // Now start up the thread. - _thread_done = false; - _thread_continue = true; - INIT_THREAD(_thread); - - SPAWN_THREAD(_thread, thread_run, this); -} - -/** - * - */ -PPInstance::StreamingFileData:: -~StreamingFileData() { - // Time to stop. - _thread_continue = false; - - JOIN_THREAD(_thread); -} - -/** - * Returns true if the file has been fully read and this object is ready to be - * deleted, or false if there is more work to do. - */ -bool PPInstance::StreamingFileData:: -is_done() const { - return _thread_done; -} - -/** - * The main function of the file thread. This reads the file contents and - * feeds it to the core API. - */ -void PPInstance::StreamingFileData:: -thread_run() { - static const size_t buffer_size = 81920; - // static const size_t buffer_size = 512; - char buffer[buffer_size]; - - _file.read(buffer, buffer_size); - size_t count = _file.gcount(); - while (count != 0) { - _total_count += count; - bool download_ok = P3D_instance_feed_url_stream_ptr - (_p3d_inst, _user_id, P3D_RC_in_progress, - 0, _file_size, (const unsigned char *)buffer, count); - - if (!download_ok) { - // Never mind. - _thread_done = true; - return; - } - - if (!_thread_continue) { - // Interrupted by the main thread. Presumably we're being shut down. - _thread_done = true; - return; - } - - // So far, so good. Read some more. - _file.read(buffer, buffer_size); - count = _file.gcount(); - - // This is useful for development, to slow things down enough to see the - // progress bar move. -#ifdef _WIN32 - Sleep(10); -#else - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 10000; - select(0, nullptr, nullptr, nullptr, &tv); -#endif - } - - // End of file. - P3D_result_code result = P3D_RC_done; - if (_file.fail() && !_file.eof()) { - // Got an error while reading. - result = P3D_RC_generic_error; - } - - P3D_instance_feed_url_stream_ptr - (_p3d_inst, _user_id, result, 0, _total_count, nullptr, 0); - - // All done. - _thread_done = true; -} - - -/** - * - */ -PPInstance::StreamTempFile:: -StreamTempFile() { - _opened = false; - _finished = false; - _current_size = 0; - _total_size = 0; -} - -/** - * - */ -PPInstance::StreamTempFile:: -~StreamTempFile() { - cleanup(); -} - -/** - * Creates the temp file and prepares to write to it. It is not normally - * necessary to call this explicitly; it will be called automatically on the - * first call to feed(). - */ -void PPInstance::StreamTempFile:: -open() { - assert(!_opened); - _opened = true; - _finished = false; - _current_size = 0; - _total_size = 0; - - char *name = tempnam(nullptr, "p3d_"); - _filename = name; - free(name); - - _stream.clear(); - _stream.open(_filename.c_str(), ios::binary); - if (!_stream) { - nout << "Unable to open temp file " << _filename << "\n"; - } else { - nout << "Opening " << _filename << "\n"; - } -} - -/** - * Receives new data from the URL and writes it to the temp file. Returns - * true on success, false on failure. - */ -bool PPInstance::StreamTempFile:: -feed(size_t total_expected_data, const void *this_data, - size_t this_data_size) { - if (_finished) { - nout << "feed(" << total_expected_data << ", " << (void *)this_data - << ", " << this_data_size << ") to " << _filename - << ", but already finished at " << _current_size << "\n"; - return false; - } - - if (!_opened) { - open(); - } - - _stream.write((const char *)this_data, this_data_size); - _current_size += this_data_size; - _total_size = total_expected_data; - - if (!_stream) { - return false; - } - return true; -} - -/** - * Marks the end of the data received from the URL. The file is closed but - * not yet deleted; it remains on disk and may be read at leisure. - */ -void PPInstance::StreamTempFile:: -finish() { - if (!_finished) { - _finished = true; - _total_size = _current_size; - } - - _stream.close(); -} - -/** - * Closes the stream for more data. The file is not yet deleted; it remains - * on disk and may be read at leisure. - */ -void PPInstance::StreamTempFile:: -close() { - _stream.close(); -} - -/** - * Closes all open processes and removes the temp file from disk. - */ -void PPInstance::StreamTempFile:: -cleanup() { - finish(); - - if (!_filename.empty()) { - nout << "Deleting " << _filename << "\n"; - unlink(_filename.c_str()); - _filename.clear(); - } - - _opened = false; - _finished = false; -} diff --git a/direct/src/plugin_npapi/ppInstance.h b/direct/src/plugin_npapi/ppInstance.h deleted file mode 100644 index f24ebb6443..0000000000 --- a/direct/src/plugin_npapi/ppInstance.h +++ /dev/null @@ -1,302 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppInstance.h - * @author drose - * @date 2009-06-19 - */ - -#ifndef PPINSTANCE_H -#define PPINSTANCE_H - -#include "nppanda3d_common.h" -#include "fileSpec.h" -#include "get_tinyxml.h" -#include "p3d_lock.h" -#include "get_twirl_data.h" -#include "p3d_plugin_config.h" -#include "plugin_get_x11.h" - -#if defined(HAVE_X11) && defined(HAVE_GTK) -#include "pre_x11_include.h" -#include -#include -#include "post_x11_include.h" -#endif // HAVE_X11 && HAVE_GTK - -#include - -class PPToplevelObject; -class PPDownloadRequest; - -/** - * This represents a single instance of the Panda3D plugin, via the NPAPI - * interface. This instance brokers the communication with the P3D Core API, - * as defined in the plugin directory. - */ -class PPInstance { -public: - PPInstance(NPMIMEType pluginType, NPP instance, uint16_t mode, - int16_t argc, char *argn[], char *argv[], NPSavedData *saved, - P3D_window_handle_type window_handle_type, - P3D_event_type event_type); - ~PPInstance(); - - void begin(); - - inline NPP get_npp_instance() const; - - inline const NPWindow *get_window() const; - void set_window(NPWindow *window); - NPError new_stream(NPMIMEType type, NPStream *stream, - bool seekable, uint16_t *stype); - void stop_outstanding_streams(); - - int32_t write_ready(NPStream *stream); - int write_stream(NPStream *stream, int offset, int len, void *buffer); - NPError destroy_stream(NPStream *stream, NPReason reason); - void url_notify(const char *url, NPReason reason, void *notifyData); - void stream_as_file(NPStream *stream, const char *fname); - - bool handle_request(P3D_request *request); - static void generic_browser_call(); - - bool handle_event(void *event); - - NPObject *get_panda_script_object(); - void set_xembed(bool use_xembed); - - void p3dobj_to_variant(NPVariant *result, P3D_object *object); - P3D_object *variant_to_p3dobj(const NPVariant *variant); - - static void output_np_variant(std::ostream &out, const NPVariant &result); - -private: - void find_host(TiXmlElement *xcontents); - void read_xhost(TiXmlElement *xhost); - void add_mirror(std::string mirror_url); - void choose_random_mirrors(std::vector &result, int num_mirrors); - - static void request_ready(P3D_instance *instance); - - void start_download(const std::string &url, PPDownloadRequest *req); - void downloaded_file(PPDownloadRequest *req, const std::string &filename); - static std::string get_filename_from_url(const std::string &url); - void feed_file(PPDownloadRequest *req, const std::string &filename); - - void open_p3d_temp_file(); - void send_p3d_temp_file_data(); - - void downloaded_contents_file(const std::string &filename); - bool read_contents_file(const std::string &contents_filename, bool fresh_download); - void get_core_api(); - void downloaded_plugin(const std::string &filename); - void do_load_plugin(); - - void create_instance(); - void send_window(); - void cleanup_window(); - bool copy_file(const std::string &from_filename, const std::string &to_filename); - - std::string lookup_token(const std::string &keyword) const; - bool has_token(const std::string &keyword) const; - static int compare_seq(const std::string &seq_a, const std::string &seq_b); - static int compare_seq_int(const char *&num_a, const char *&num_b); - - void set_failed(); - - static void handle_request_loop(); - static void browser_sync_callback(void *); - -#ifdef _WIN32 - static LONG - st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); - LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); - void win_get_twirl_bitmaps(); - void win_paint_twirl(HWND hwnd, HDC dc); -#endif // _WIN32 - - class EventAuxData { - public: - std::wstring _characters; - std::wstring _characters_im; - std::wstring _text; - }; -#ifdef MACOSX_HAS_EVENT_MODELS - static void copy_cocoa_event(P3DCocoaEvent *p3d_event, - NPCocoaEvent *np_event, - EventAuxData &aux_data); - static const wchar_t *make_ansi_string(std::wstring &result, NPNSString *ns_string); - void handle_cocoa_event(const P3DCocoaEvent *p3d_event); - void osx_get_twirl_images(); - void osx_release_twirl_images(); - void paint_twirl_osx_cgcontext(CGContextRef context); - class OsxImageData; - bool osx_paint_image(CGContextRef context, const OsxImageData &image); -#endif // MACOSX_HAS_EVENT_MODELS - -#ifdef __APPLE__ - static void timer_callback(CFRunLoopTimerRef timer, void *info); - static void st_twirl_timer_callback(CFRunLoopTimerRef timer, void *info); - void twirl_timer_callback(); -#endif // __APPLE__ - -#ifdef HAVE_X11 - void x11_start_twirl_subprocess(); - void x11_stop_twirl_subprocess(); - void x11_twirl_subprocess_run(); -#endif // HAVE_X11 - -private: - NPP _npp_instance; - unsigned int _npp_mode; - P3D_window_handle_type _window_handle_type; - P3D_event_type _event_type; - typedef std::vector Tokens; - Tokens _tokens; - - // Set from fgcolor & bgcolor. - int _fgcolor_r, _fgcolor_b, _fgcolor_g; - int _bgcolor_r, _bgcolor_b, _bgcolor_g; - - std::string _root_dir; - std::string _standard_url_prefix; - std::string _download_url_prefix; - typedef std::vector Mirrors; - Mirrors _mirrors; - - // A list of URL's that we will attempt to download the core API from. - typedef std::vector CoreUrls; - CoreUrls _core_urls; - - std::string _coreapi_set_ver; - FileSpec _coreapi_dll; - time_t _contents_expiration; - bool _failed; - bool _started; - - // This class is used to stream data from some URL into a temporary local - // file. - class StreamTempFile { - public: - StreamTempFile(); - ~StreamTempFile(); - - void open(); - bool feed(size_t total_expected_data, const void *this_data, - size_t this_data_size); - void finish(); - void close(); - void cleanup(); - - bool _opened; - bool _finished; - size_t _current_size; - size_t _total_size; - ofstream _stream; - std::string _filename; - }; - - bool _got_instance_url; - std::string _instance_url; - int _p3d_instance_id; - StreamTempFile _p3d_temp_file; - StreamTempFile _contents_temp_file; - StreamTempFile _core_dll_temp_file; - - // We need to keep a list of the NPStream objects that the instance owns, - // because Safari (at least) won't automatically delete all of the - // outstanding streams when the instance is destroyed. - typedef std::vector Streams; - Streams _streams; - - // This class is used for feeding local files (accessed via a "file:" url) - // into the core API. - class StreamingFileData { - public: - StreamingFileData(PPDownloadRequest *req, const std::string &filename, - P3D_instance *p3d_inst); - ~StreamingFileData(); - - bool is_done() const; - - private: - void thread_run(); - THREAD_CALLBACK_DECLARATION(PPInstance::StreamingFileData, thread_run); - - private: - bool _thread_done; - bool _thread_continue; - - P3D_instance *_p3d_inst; - int _user_id; - std::string _filename; - ifstream _file; - size_t _file_size; - size_t _total_count; - - THREAD _thread; - }; - - typedef std::vector FileDatas; - static FileDatas _file_datas; - - bool _use_xembed; - bool _got_window; - NPWindow _window; -#if defined(HAVE_X11) && defined(HAVE_GTK) - GtkWidget *_plug; -#endif // HAVE_X11 && HAVE_GTK - -#ifdef _WIN32 - LONG_PTR _orig_window_proc; - HWND _hwnd; - HBITMAP _twirl_bitmaps[twirl_num_steps + 1]; - HBRUSH _bg_brush; - DWORD _init_time; -#endif // _WIN32 - -#ifdef __APPLE__ - CFRunLoopRef _run_loop_main; - CFRunLoopTimerRef _request_timer; - LOCK _timer_lock; - CFRunLoopTimerRef _twirl_timer; -#endif // __APPLE__ - -#ifdef MACOSX_HAS_EVENT_MODELS - class OsxImageData { - public: - unsigned char *_raw_data; - CFDataRef _data; - CGDataProviderRef _provider; - CGColorSpaceRef _color_space; - CGImageRef _image; - }; - OsxImageData _twirl_images[twirl_num_steps + 1]; - bool _got_twirl_images; -#endif // MACOSX_HAS_EVENT_MODELS - -#ifdef HAVE_X11 - pid_t _twirl_subprocess_pid; -#endif // HAVE_X11 - -#ifndef _WIN32 - long _init_sec; - long _init_usec; -#endif // _WIN32 - - bool _python_window_open; - - PPToplevelObject *_script_object; - - P3D_instance *_p3d_inst; -}; - -#include "ppInstance.I" - -#endif diff --git a/direct/src/plugin_npapi/ppPandaObject.I b/direct/src/plugin_npapi/ppPandaObject.I deleted file mode 100644 index eafcfbd83c..0000000000 --- a/direct/src/plugin_npapi/ppPandaObject.I +++ /dev/null @@ -1,25 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppPandaObject.I - * @author drose - * @date 2009-07-03 - */ - -/** - * Returns the p3d_object this PPPandaObject maps to. This may be NULL if the - * object is not fully initialized. If not NULL, this returns a new - * reference. - */ -inline P3D_object *PPPandaObject:: -get_p3d_object() const { - if (_p3d_object != nullptr) { - P3D_OBJECT_INCREF(_p3d_object); - } - return _p3d_object; -} diff --git a/direct/src/plugin_npapi/ppPandaObject.cxx b/direct/src/plugin_npapi/ppPandaObject.cxx deleted file mode 100644 index e4e4854c3f..0000000000 --- a/direct/src/plugin_npapi/ppPandaObject.cxx +++ /dev/null @@ -1,428 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppPandaObject.cxx - * @author drose - * @date 2009-07-03 - */ - -#include "ppPandaObject.h" - -using std::string; - -NPClass PPPandaObject::_object_class = { - NP_CLASS_STRUCT_VERSION, - &PPPandaObject::NPAllocate, - &PPPandaObject::NPDeallocate, - &PPPandaObject::NPInvalidate, - &PPPandaObject::NPHasMethod, - &PPPandaObject::NPInvoke, - &PPPandaObject::NPInvokeDefault, - &PPPandaObject::NPHasProperty, - &PPPandaObject::NPGetProperty, - &PPPandaObject::NPSetProperty, - &PPPandaObject::NPRemoveProperty, -#if defined(NP_CLASS_STRUCT_VERSION_ENUM) && NP_CLASS_STRUCT_VERSION >= NP_CLASS_STRUCT_VERSION_ENUM - &PPPandaObject::NPEnumerate, -#endif -#if defined(NP_CLASS_STRUCT_VERSION_CTOR) && NP_CLASS_STRUCT_VERSION >= NP_CLASS_STRUCT_VERSION_CTOR - &PPPandaObject::NPConstruct, -#endif -}; - - -/** - * Use this call to construct a new PPPandaObject. - */ -PPPandaObject *PPPandaObject:: -make_new(PPInstance *inst, P3D_object *p3d_object) { - NPObject *npobj = - browser->createobject(inst->get_npp_instance(), &_object_class); - PPPandaObject *ppobj = (PPPandaObject *)npobj; - ppobj->construct(inst, p3d_object); - return ppobj; -} - -/** - * Changes the p3d_object this PPPandaObject maps to. The new object's - * reference count is incremented, and the previous object's is decremented. - */ -void PPPandaObject:: -set_p3d_object(P3D_object *p3d_object) { - if (p3d_object != nullptr) { - P3D_OBJECT_INCREF(p3d_object); - } - P3D_OBJECT_XDECREF(_p3d_object); - _p3d_object = p3d_object; -} - -/** - * Stands in for the C++ constructor. We can't have a true constructor - * because of the C-style interface in NPN_CreateObject(). This must be - * called explicitly following NPN_CreateObject(). - */ -void PPPandaObject:: -construct(PPInstance *inst, P3D_object *p3d_object) { - _instance = inst; - _p3d_object = nullptr; - set_p3d_object(p3d_object); -} - -/** - * This "destructor" is called by NPInvalidate(). - */ -void PPPandaObject:: -invalidate() { - _instance = nullptr; - set_p3d_object(nullptr); -} - -/** - * Returns true if the object has the named method, false otherwise. - */ -bool PPPandaObject:: -has_method(NPIdentifier name) { - string method_name = identifier_to_string(name); - // nout << this << ".has_method(" << method_name << ")\n"; - if (_p3d_object == nullptr) { - // Not powered up yet. - return false; - } - - // Unlike has_property(), below, it turns out that we really do need to - // honestly answer whether there is a method by this name, because if there - // is, then Firefox won't query the property in a meaningful fashion. - - // Of course, in Python the distinction between property and method is a - // little looser than Firefox seems to want to make it, and sometimes you - // have an object which is both. This could become problematic in obscure - // situations. Too bad, say I. Mozilla's bug, not mine. - - bool result = P3D_OBJECT_HAS_METHOD(_p3d_object, method_name.c_str()); - return result; -} - -/** - * Calls the named method on the object, storing the return value into result. - * Returns true on success, false on failure. - */ -bool PPPandaObject:: -invoke(NPIdentifier name, const NPVariant *args, uint32_t argCount, - NPVariant *result) { - string method_name = identifier_to_string(name); - // nout << this << ".invoke(" << method_name << ")\n"; - if (_p3d_object == nullptr) { - // Not powered up yet. - return false; - } - - P3D_object **p3dargs = new P3D_object *[argCount]; - unsigned int i; - for (i = 0; i < argCount; ++i) { - p3dargs[i] = _instance->variant_to_p3dobj(&args[i]); - } - - P3D_object *value = P3D_OBJECT_CALL(_p3d_object, method_name.c_str(), - true, p3dargs, argCount); - for (i = 0; i < argCount; ++i) { - P3D_OBJECT_DECREF(p3dargs[i]); - } - delete[] p3dargs; - - if (value == nullptr) { - // No such method, or some problem with the parameters. - return false; - } - - // We have the return value, and its value is stored in value. - _instance->p3dobj_to_variant(result, value); - P3D_OBJECT_DECREF(value); - return true; -} - -/** - * Calls the default method on the object, storing the return value into - * result. Returns true on success, false on failure. - */ -bool PPPandaObject:: -invoke_default(const NPVariant *args, uint32_t argCount, - NPVariant *result) { - // nout << this << ".invoke_default()\n"; - if (_p3d_object == nullptr) { - // Not powered up yet. - return false; - } - - P3D_object **p3dargs = new P3D_object *[argCount]; - unsigned int i; - for (i = 0; i < argCount; ++i) { - p3dargs[i] = _instance->variant_to_p3dobj(&args[i]); - } - - P3D_object *value = P3D_OBJECT_CALL(_p3d_object, "", true, - p3dargs, argCount); - for (i = 0; i < argCount; ++i) { - P3D_OBJECT_DECREF(p3dargs[i]); - } - delete[] p3dargs; - - if (value == nullptr) { - // No such method, or some problem with the parameters. - return false; - } - - // We have the return value, and its value is stored in value. - _instance->p3dobj_to_variant(result, value); - P3D_OBJECT_DECREF(value); - return true; -} - -/** - * Returns true if the object has the named property, false otherwise. - */ -bool PPPandaObject:: -has_property(NPIdentifier name) { - string property_name = identifier_to_string(name); - // nout << this << ".has_property(" << property_name << ")\n"; - if (_p3d_object == nullptr) { - // Not powered up yet. - return false; - } - - // If we say we don't have a given property, then set_property() will never - // be called. So we always say we *do* have any particular property, - // whether we currently have it right now or not (since we *could* have it - // if you call set_property()). - - // On the other hand, Firefox gets confused about methods that are also - // properties. So you have to say there's *no* property if there is in fact - // a callable method by that name, or Firefox will never call the method. - bool result = P3D_OBJECT_HAS_METHOD(_p3d_object, property_name.c_str()); - return !result; -} - -/** - * Retrieves the named property value from the object and stores it in result. - * Returns true on success, false on failure. - */ -bool PPPandaObject:: -get_property(NPIdentifier name, NPVariant *result) { - // Actually, we never return false. If the property doesn't exist, we - // return undefined, to be consistent with JavaScript (and with IE). - - string property_name = identifier_to_string(name); - // nout << this << ".get_property(" << property_name << ")\n"; - if (_p3d_object == nullptr) { - // Not powered up yet. - VOID_TO_NPVARIANT(*result); - return true; - } - - P3D_object *value = P3D_OBJECT_GET_PROPERTY(_p3d_object, property_name.c_str()); - if (value == nullptr) { - // No such property. - VOID_TO_NPVARIANT(*result); - return true; - } - - // We have the property, and its value is stored in value. - _instance->p3dobj_to_variant(result, value); - P3D_OBJECT_DECREF(value); - return true; -} - -/** - * Replaces the named property value on the object. Returns true on success, - * false on failure. - */ -bool PPPandaObject:: -set_property(NPIdentifier name, const NPVariant *value) { - string property_name = identifier_to_string(name); - // nout << this << ".set_property(" << property_name << ")\n"; - if (_p3d_object == nullptr) { - // Not powered up yet. - return false; - } - - P3D_object *object = _instance->variant_to_p3dobj(value); - bool result = P3D_OBJECT_SET_PROPERTY(_p3d_object, property_name.c_str(), - true, object); - P3D_OBJECT_DECREF(object); - return result; -} - -/** - * Deletes the named property value from the object. Returns true on success, - * false on failure. - */ -bool PPPandaObject:: -remove_property(NPIdentifier name) { - string property_name = identifier_to_string(name); - // nout << this << ".remove_property(" << property_name << ")\n"; - if (_p3d_object == nullptr) { - // Not powered up yet. - return false; - } - - bool result = P3D_OBJECT_SET_PROPERTY(_p3d_object, property_name.c_str(), - true, nullptr); - return result; -} - -/** - * Constructs a list of available properties on this object. Returns true on - * success, false on failure. - */ -bool PPPandaObject:: -enumerate(NPIdentifier **value, uint32_t *count) { - // nout << this << ".enumerate()\n"; TODO: Not implemented yet. - - // Note that the array of values must be allocated here with NPN_MemAlloc(). - *value = nullptr; - *count = 0; - return false; -} - -/** - * Gets the string equivalent of the indicated identifier, whether it is an - * integer identifier or a string identifier. - */ -string PPPandaObject:: -identifier_to_string(NPIdentifier ident) { - if (browser->identifierisstring(ident)) { - NPUTF8 *result = browser->utf8fromidentifier(ident); - if (result != nullptr) { - string strval(result); - browser->memfree(result); - return strval; - } - } else { - // An integer identifier. We could treat this as a special case, like - // Firefox does, but Safari doesn't appear to use integer identifiers and - // just sends everything as a string identifier. So to make things - // consistent internally, we also send everything as a string. - std::ostringstream strm; - strm << browser->intfromidentifier(ident); - return strm.str(); - } - - return string(); -} - - -// The remaining function bodies are the C-style function wrappers that are -// called directly by NPAPI, and which redirect into the above C++-style -// methods. - -/** - * Called by NPN_CreateObject() to allocate space for this object. - */ -NPObject *PPPandaObject:: -NPAllocate(NPP npp, NPClass *aClass) { - assert(aClass == &_object_class); - return (PPPandaObject *)malloc(sizeof(PPPandaObject)); -} - -/** - * Called to delete the space allocated by NPAllocate, above. - */ -void PPPandaObject:: -NPDeallocate(NPObject *npobj) { - ((PPPandaObject *)npobj)->invalidate(); - free(npobj); -} - -/** - * Called to destruct the object. - */ -void PPPandaObject:: -NPInvalidate(NPObject *npobj) { - // It turns out that this method isn't actually called by Safari's - // implementation of NPAPI, so we'll move the actual destructor call into - // NPDeallocate, above. -} - -/** - * - */ -bool PPPandaObject:: -NPHasMethod(NPObject *npobj, NPIdentifier name) { - return ((PPPandaObject *)npobj)->has_method(name); -} - -/** - * - */ -bool PPPandaObject:: -NPInvoke(NPObject *npobj, NPIdentifier name, - const NPVariant *args, uint32_t argCount, - NPVariant *result) { - return ((PPPandaObject *)npobj)->invoke(name, args, argCount, result); -} - -/** - * - */ -bool PPPandaObject:: -NPInvokeDefault(NPObject *npobj, const NPVariant *args, uint32_t argCount, - NPVariant *result) { - return ((PPPandaObject *)npobj)->invoke_default(args, argCount, result); -} - -/** - * - */ -bool PPPandaObject:: -NPHasProperty(NPObject *npobj, NPIdentifier name) { - return ((PPPandaObject *)npobj)->has_property(name); -} - -/** - * - */ -bool PPPandaObject:: -NPGetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result) { - return ((PPPandaObject *)npobj)->get_property(name, result); -} - -/** - * - */ -bool PPPandaObject:: -NPSetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) { - return ((PPPandaObject *)npobj)->set_property(name, value); -} - -/** - * - */ -bool PPPandaObject:: -NPRemoveProperty(NPObject *npobj, NPIdentifier name) { - return ((PPPandaObject *)npobj)->remove_property(name); -} - -/** - * - */ -bool PPPandaObject:: -NPEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count) { - return ((PPPandaObject *)npobj)->enumerate(value, count); -} - -/** - * - */ -bool PPPandaObject:: -NPConstruct(NPObject *npobj, const NPVariant *args, - uint32_t argCount, NPVariant *result) { - // Not implemented. We don't use this constructor mechanism because it - // wasn't supported on earlier versions of Gecko. Instead, we use - // make_new() to construct PPPandaObjects via an explicit call to - // construct(). - return true; -} diff --git a/direct/src/plugin_npapi/ppPandaObject.h b/direct/src/plugin_npapi/ppPandaObject.h deleted file mode 100644 index 89a87d02af..0000000000 --- a/direct/src/plugin_npapi/ppPandaObject.h +++ /dev/null @@ -1,91 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppPandaObject.h - * @author drose - * @date 2009-07-03 - */ - -#ifndef PPPANDAOBJECT_H -#define PPPANDAOBJECT_H - -#include "nppanda3d_common.h" - -/** - * This is the interface layer between an NPObject and a P3D_object. It maps - * calls from NPAPI into the P3D_object system, thus allowing the browser to - * view and operate on a Panda object. - * - * Also see PPBrowserObject, which maps calls the other way. - */ -class PPPandaObject : public NPObject { -public: - static PPPandaObject *make_new(PPInstance *inst, P3D_object *p3d_object); - - inline P3D_object *get_p3d_object() const; - void set_p3d_object(P3D_object *p3d_object); - -private: - void construct(PPInstance *inst, P3D_object *p3d_object); - void invalidate(); - - bool has_method(NPIdentifier name); - bool invoke(NPIdentifier name, - const NPVariant *args, uint32_t argCount, - NPVariant *result); - bool invoke_default(const NPVariant *args, uint32_t argCount, - NPVariant *result); - bool has_property(NPIdentifier name); - bool get_property(NPIdentifier name, - NPVariant *result); - bool set_property(NPIdentifier name, - const NPVariant *value); - bool remove_property(NPIdentifier name); - bool enumerate(NPIdentifier **value, uint32_t *count); - -private: - static std::string identifier_to_string(NPIdentifier ident); - - -private: - static NPObject *NPAllocate(NPP npp, NPClass *aClass); - static void NPDeallocate(NPObject *npobj); - static void NPInvalidate(NPObject *npobj); - static bool NPHasMethod(NPObject *npobj, NPIdentifier name); - static bool NPInvoke(NPObject *npobj, NPIdentifier name, - const NPVariant *args, uint32_t argCount, - NPVariant *result); - static bool NPInvokeDefault(NPObject *npobj, - const NPVariant *args, - uint32_t argCount, - NPVariant *result); - static bool NPHasProperty(NPObject *npobj, NPIdentifier name); - static bool NPGetProperty(NPObject *npobj, NPIdentifier name, - NPVariant *result); - static bool NPSetProperty(NPObject *npobj, NPIdentifier name, - const NPVariant *value); - static bool NPRemoveProperty(NPObject *npobj, - NPIdentifier name); - static bool NPEnumerate(NPObject *npobj, NPIdentifier **value, - uint32_t *count); - static bool NPConstruct(NPObject *npobj, - const NPVariant *args, - uint32_t argCount, - NPVariant *result); - -private: - PPInstance *_instance; - P3D_object *_p3d_object; - -public: - static NPClass _object_class; -}; - -#include "ppPandaObject.I" - -#endif diff --git a/direct/src/plugin_npapi/ppToplevelObject.I b/direct/src/plugin_npapi/ppToplevelObject.I deleted file mode 100644 index f9972f68dd..0000000000 --- a/direct/src/plugin_npapi/ppToplevelObject.I +++ /dev/null @@ -1,12 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppToplevelObject.I - * @author drose - * @date 2009-08-21 - */ diff --git a/direct/src/plugin_npapi/ppToplevelObject.cxx b/direct/src/plugin_npapi/ppToplevelObject.cxx deleted file mode 100644 index a3790d5039..0000000000 --- a/direct/src/plugin_npapi/ppToplevelObject.cxx +++ /dev/null @@ -1,232 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppToplevelObject.cxx - * @author drose - * @date 2009-08-21 - */ - -#include "ppToplevelObject.h" - -NPClass PPToplevelObject::_object_class = { - NP_CLASS_STRUCT_VERSION, - &PPToplevelObject::NPAllocate, - &PPToplevelObject::NPDeallocate, - &PPToplevelObject::NPInvalidate, - &PPToplevelObject::NPHasMethod, - &PPToplevelObject::NPInvoke, - &PPToplevelObject::NPInvokeDefault, - &PPToplevelObject::NPHasProperty, - &PPToplevelObject::NPGetProperty, - &PPToplevelObject::NPSetProperty, - &PPToplevelObject::NPRemoveProperty, -#if defined(NP_CLASS_STRUCT_VERSION_ENUM) && NP_CLASS_STRUCT_VERSION >= NP_CLASS_STRUCT_VERSION_ENUM - &PPToplevelObject::NPEnumerate, -#endif -#if defined(NP_CLASS_STRUCT_VERSION_CTOR) && NP_CLASS_STRUCT_VERSION >= NP_CLASS_STRUCT_VERSION_CTOR - &PPToplevelObject::NPConstruct, -#endif -}; - - -/** - * Use this call to construct a new PPToplevelObject. - */ -PPToplevelObject *PPToplevelObject:: -make_new(PPInstance *inst) { - NPObject *npobj = - browser->createobject(inst->get_npp_instance(), &_object_class); - PPToplevelObject *ppobj = (PPToplevelObject *)npobj; - ppobj->construct(inst); - return ppobj; -} - -/** - * Changes the "main" object this PPToplevelObject maps to. The new object's - * reference count is incremented, and the previous object's is decremented. - */ -void PPToplevelObject:: -set_main(P3D_object *p3d_object) { - if (p3d_object != nullptr) { - P3D_OBJECT_INCREF(p3d_object); - } - P3D_OBJECT_XDECREF(_main); - _main = p3d_object; -} - -/** - * Stands in for the C++ constructor. We can't have a true constructor - * because of the C-style interface in NPN_CreateObject(). This must be - * called explicitly following NPN_CreateObject(). - */ -void PPToplevelObject:: -construct(PPInstance *inst) { - _instance = inst; - _main = nullptr; - - // Get our one property name as an identifier, so we can look for it. - _main_id = browser->getstringidentifier("main"); -} - -/** - * This "destructor" is called by NPInvalidate(). - */ -void PPToplevelObject:: -invalidate() { - _instance = nullptr; - set_main(nullptr); -} - -/** - * Returns true if the object has the named property, false otherwise. - */ -bool PPToplevelObject:: -has_property(NPIdentifier name) { - if (_main == nullptr) { - // Not powered up yet. - return false; - } - - if (name == _main_id) { - return true; - } - - return false; -} - -/** - * Retrieves the named property value from the object and stores it in result. - * Returns true on success, false on failure. - */ -bool PPToplevelObject:: -get_property(NPIdentifier name, NPVariant *result) { - if (_main == nullptr) { - // Not powered up yet. - return false; - } - - if (name == _main_id) { - _instance->p3dobj_to_variant(result, _main); - return true; - } - - return false; -} - - -// The remaining function bodies are the C-style function wrappers that are -// called directly by NPAPI, and which redirect into the above C++-style -// methods. - -/** - * Called by NPN_CreateObject() to allocate space for this object. - */ -NPObject *PPToplevelObject:: -NPAllocate(NPP npp, NPClass *aClass) { - assert(aClass == &_object_class); - return (PPToplevelObject *)malloc(sizeof(PPToplevelObject)); -} - -/** - * Called to delete the space allocated by NPAllocate, above. - */ -void PPToplevelObject:: -NPDeallocate(NPObject *npobj) { - ((PPToplevelObject *)npobj)->invalidate(); - free(npobj); -} - -/** - * Called to destruct the object. - */ -void PPToplevelObject:: -NPInvalidate(NPObject *npobj) { - // It turns out that this method isn't actually called by Safari's - // implementation of NPAPI, so we'll move the actual destructor call into - // NPDeallocate, above. -} - -/** - * - */ -bool PPToplevelObject:: -NPHasMethod(NPObject *npobj, NPIdentifier name) { - return false; -} - -/** - * - */ -bool PPToplevelObject:: -NPInvoke(NPObject *npobj, NPIdentifier name, - const NPVariant *args, uint32_t argCount, - NPVariant *result) { - return false; -} - -/** - * - */ -bool PPToplevelObject:: -NPInvokeDefault(NPObject *npobj, const NPVariant *args, uint32_t argCount, - NPVariant *result) { - return false; -} - -/** - * - */ -bool PPToplevelObject:: -NPHasProperty(NPObject *npobj, NPIdentifier name) { - return ((PPToplevelObject *)npobj)->has_property(name); -} - -/** - * - */ -bool PPToplevelObject:: -NPGetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result) { - return ((PPToplevelObject *)npobj)->get_property(name, result); -} - -/** - * - */ -bool PPToplevelObject:: -NPSetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) { - return false; -} - -/** - * - */ -bool PPToplevelObject:: -NPRemoveProperty(NPObject *npobj, NPIdentifier name) { - return false; -} - -/** - * - */ -bool PPToplevelObject:: -NPEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count) { - return false; -} - -/** - * - */ -bool PPToplevelObject:: -NPConstruct(NPObject *npobj, const NPVariant *args, - uint32_t argCount, NPVariant *result) { - // Not implemented. We don't use this constructor mechanism because it - // wasn't supported on earlier versions of Gecko. Instead, we use - // make_new() to construct PPToplevelObjects via an explicit call to - // construct(). - return true; -} diff --git a/direct/src/plugin_npapi/ppToplevelObject.h b/direct/src/plugin_npapi/ppToplevelObject.h deleted file mode 100644 index ad9130c9d1..0000000000 --- a/direct/src/plugin_npapi/ppToplevelObject.h +++ /dev/null @@ -1,76 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file ppToplevelObject.h - * @author drose - * @date 2009-08-21 - */ - -#ifndef PPTOPLEVELOBJECT_H -#define PPTOPLEVELOBJECT_H - -#include "nppanda3d_common.h" - -/** - * This is a special object fed to Mozilla as the toplevel scripting object - * for the instance. It has only one property, "main", which corresponds to - * the appRunner.main object from Python. - */ -class PPToplevelObject : public NPObject { -public: - static PPToplevelObject *make_new(PPInstance *inst); - - inline P3D_object *get_main() const; - void set_main(P3D_object *main); - -private: - void construct(PPInstance *inst); - void invalidate(); - - bool has_property(NPIdentifier name); - bool get_property(NPIdentifier name, - NPVariant *result); - -private: - static NPObject *NPAllocate(NPP npp, NPClass *aClass); - static void NPDeallocate(NPObject *npobj); - static void NPInvalidate(NPObject *npobj); - static bool NPHasMethod(NPObject *npobj, NPIdentifier name); - static bool NPInvoke(NPObject *npobj, NPIdentifier name, - const NPVariant *args, uint32_t argCount, - NPVariant *result); - static bool NPInvokeDefault(NPObject *npobj, - const NPVariant *args, - uint32_t argCount, - NPVariant *result); - static bool NPHasProperty(NPObject *npobj, NPIdentifier name); - static bool NPGetProperty(NPObject *npobj, NPIdentifier name, - NPVariant *result); - static bool NPSetProperty(NPObject *npobj, NPIdentifier name, - const NPVariant *value); - static bool NPRemoveProperty(NPObject *npobj, - NPIdentifier name); - static bool NPEnumerate(NPObject *npobj, NPIdentifier **value, - uint32_t *count); - static bool NPConstruct(NPObject *npobj, - const NPVariant *args, - uint32_t argCount, - NPVariant *result); - -private: - PPInstance *_instance; - P3D_object *_main; - NPIdentifier _main_id; - -public: - static NPClass _object_class; -}; - -#include "ppToplevelObject.I" - -#endif diff --git a/direct/src/plugin_npapi/startup.cxx b/direct/src/plugin_npapi/startup.cxx deleted file mode 100644 index 315a21f8cc..0000000000 --- a/direct/src/plugin_npapi/startup.cxx +++ /dev/null @@ -1,590 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file startup.cxx - * @author drose - * @date 2009-06-17 - */ - -#include "startup.h" -#include "p3d_plugin_config.h" -#include "p3d_lock.h" -#include "ppBrowserObject.h" -#include "wstring_encode.h" -#include "find_root_dir.h" - -#ifdef _WIN32 -#include -#include -#endif - -using std::string; - -static ofstream logfile; -std::ostream *nout_stream = &logfile; - -string global_root_dir; -bool has_plugin_thread_async_call; - -NPNetscapeFuncs *browser; - -// These function prototypes changed slightly (but insignificantly) between -// releases of NPAPI. To avoid compilation errors, we use our own name, and -// cast it to the correct type. -static int32_t -NPP_WriteReady_x(NPP instance, NPStream *stream); -static int32_t -NPP_Write_x(NPP instance, NPStream *stream, int32_t offset, - int32_t len, void *buffer); - -// open_logfile() also assigns global_root_dir. -static bool logfile_is_open = false; -static void -open_logfile() { - if (!logfile_is_open) { - global_root_dir = find_root_dir(); - - // Note that this logfile name may not be specified at runtime. It must - // be compiled in if it is specified at all. - - string log_directory; - // Allow the developer to compile in the log directory. -#ifdef P3D_PLUGIN_LOG_DIRECTORY - if (log_directory.empty()) { - log_directory = P3D_PLUGIN_LOG_DIRECTORY; - } -#endif - - // Failing that, we write logfiles to Panda3Dlog. - if (log_directory.empty()) { - log_directory = global_root_dir + "/log"; - } - mkdir_complete(log_directory, std::cerr); - - // Ensure that the log directory ends with a slash. - if (!log_directory.empty() && log_directory[log_directory.size() - 1] != '/') { -#ifdef _WIN32 - if (log_directory[log_directory.size() - 1] != '\\') -#endif - log_directory += "/"; - } - - // Construct the logfile pathname. - - string log_basename; -#ifdef P3D_PLUGIN_LOG_BASENAME1 - if (log_basename.empty()) { - log_basename = P3D_PLUGIN_LOG_BASENAME1; - } -#endif - if (log_basename.empty()) { - log_basename = "p3dplugin"; - } - - if (!log_basename.empty()) { - string log_pathname = log_directory; - log_pathname += log_basename; - log_pathname += ".log"; - - logfile.close(); - logfile.clear(); -#ifdef _WIN32 - std::wstring log_pathname_w; - string_to_wstring(log_pathname_w, log_pathname); - logfile.open(log_pathname_w.c_str(), std::ios::out | std::ios::trunc); -#else - logfile.open(log_pathname.c_str(), std::ios::out | std::ios::trunc); -#endif // _WIN32 - logfile.setf(std::ios::unitbuf); - } - - // If we didn't have a logfile name compiled in, we throw away log output - // by the simple expedient of never actually opening the ofstream. - logfile_is_open = true; - } -} - - -/** - * On Unix, this function is called by the browser to get the mimetypes and - * extensions this plugin is supposed to handle. - */ -#if NP_VERSION_MAJOR == 0 && NP_VERSION_MINOR <= 22 -char * -#else -const char * -#endif -NP_GetMIMEDescription(void) { - return "application/x-panda3d:p3d:Panda3D applet;"; -} - -/** - * On Unix, this function is called by the browser to get some information - * like the name and description. - */ -NPError -NP_GetValue(void*, NPPVariable variable, void* value) { - if (value == nullptr) { - return NPERR_INVALID_PARAM; - } - - switch (variable) { - case NPPVpluginNameString: - *(const char **)value = "Panda3D Game Engine Plug-In"; - break; - case NPPVpluginDescriptionString: - *(const char **)value = "Runs 3-D games and interactive applets"; - break; - default: - nout << "Ignoring GetValue request " << variable << "\n"; - return NPERR_INVALID_PARAM; - } - - return NPERR_NO_ERROR; -} - -/** - * This function is called (almost) before any other function, to ask the - * plugin to initialize itself and to send the pointers to the browser control - * functions. Also see NP_GetEntryPoints. - */ -#ifdef _WIN32 -NPError OSCALL -NP_Initialize(NPNetscapeFuncs *browserFuncs) -#else -// On Mac, the API specifies this second parameter is included, but it lies. -// We actually don't get a second parameter there, but we have to put it here -// to make the compiler happy. -NPError OSCALL -NP_Initialize(NPNetscapeFuncs *browserFuncs, - NPPluginFuncs *pluginFuncs) -#endif -{ - // save away browser functions - browser = browserFuncs; - - // open_logfile() also assigns global_root_dir. - open_logfile(); - nout << "Initializing Panda3D plugin version " << P3D_PLUGIN_VERSION_STR << "\n"; - - nout << "browserFuncs = " << browserFuncs << "\n"; - - // On Unix, we have to use the pluginFuncs argument to pass our entry - // points. -#if !defined(_WIN32) && !defined(__APPLE__) - if (pluginFuncs != nullptr) { - NP_GetEntryPoints(pluginFuncs); - } -#endif - - int browser_major = (browser->version >> 8) & 0xff; - int browser_minor = browser->version & 0xff; - nout << "Browser NPAPI version " << browser_major << "." << browser_minor << "\n"; - - int expected_major = NP_VERSION_MAJOR; - int expected_minor = NP_VERSION_MINOR; - - nout << "Plugin compiled with NPAPI version " - << expected_major << "." << expected_minor << "\n"; - - has_plugin_thread_async_call = false; -#ifdef HAS_PLUGIN_THREAD_ASYNC_CALL - // Check if the browser offers this very useful call. - if (browser_major > 0 || browser_minor >= NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL) { - if ((void *)browser->pluginthreadasynccall == nullptr) { - nout << "Browser should have PLUGIN_THREAD_ASYNC_CALL, but the pointer is NULL.\n"; - has_plugin_thread_async_call = false; - } else { - has_plugin_thread_async_call = true; - } - } -#endif - - // Seed the lame random number generator in rand(); we use it to select a - // mirror for downloading. - srand((unsigned int)time(nullptr)); - - return NPERR_NO_ERROR; -} - -/** - * This method is extracted directly from the DLL and called at initialization - * time by the browser, either before or after NP_Initialize, to retrieve the - * pointers to the rest of the plugin functions that are not exported from the - * DLL. - */ -NPError OSCALL -NP_GetEntryPoints(NPPluginFuncs *pluginFuncs) { - // open_logfile() also assigns global_root_dir. - open_logfile(); - nout << "NP_GetEntryPoints, pluginFuncs = " << pluginFuncs << "\n"; - if (pluginFuncs->size == 0) { - pluginFuncs->size = sizeof(*pluginFuncs); - } - if (pluginFuncs->size < offsetof(NPPluginFuncs, gotfocus)) { - nout << "Invalid NPPPluginFuncs size\n"; - return NPERR_INVALID_FUNCTABLE_ERROR; - } - - // Not entirely sure what version number we should send back here. Sending - // the verion number of the NPAPI library we're compiled against doesn't - // seem 100% right, because there's no reason to think that *this* code - // knows about all of the functions provided by the particular library - // version it's compiled against. - pluginFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR; - - pluginFuncs->newp = NPP_New; - pluginFuncs->destroy = NPP_Destroy; - pluginFuncs->setwindow = NPP_SetWindow; - pluginFuncs->newstream = NPP_NewStream; - pluginFuncs->destroystream = NPP_DestroyStream; - pluginFuncs->asfile = NPP_StreamAsFile; - - // WebKit's NPAPI defines the wrong prototype for these functions, so we - // have to cast them. But the casting typename isn't consistent between - // WebKit and Mozilla's NPAPI headers. -#ifdef NewNPP_WriteProc - pluginFuncs->writeready = NewNPP_WriteReadyProc(NPP_WriteReady_x); - pluginFuncs->write = NewNPP_WriteProc(NPP_Write_x); -#else - pluginFuncs->writeready = (NPP_WriteReadyProcPtr)NPP_WriteReady_x; - pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write_x; -#endif - - pluginFuncs->print = NPP_Print; - pluginFuncs->event = NPP_HandleEvent; - pluginFuncs->urlnotify = NPP_URLNotify; - pluginFuncs->getvalue = NPP_GetValue; - pluginFuncs->setvalue = NPP_SetValue; - - return NPERR_NO_ERROR; -} - -/** - * This function is called when the browser is done with the plugin; it asks - * the plugin to unload itself and free all used resources. - */ -NPError OSCALL -NP_Shutdown(void) { - nout << "shutdown\n"; - unload_plugin(nout); - PPBrowserObject::clear_class_definition(); - - // Not clear whether there's a return value or not. Some versions of the - // API have different opinions on this. - return NPERR_NO_ERROR; -} - -/** - * Called by the browser to create a new instance of the plugin. - */ -NPError -NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, - int16_t argc, char *argn[], char *argv[], NPSavedData *saved) { - nout << "new instance " << instance << "\n"; - - P3D_window_handle_type window_handle_type = P3D_WHT_none; - P3D_event_type event_type = P3D_ET_none; - -#ifdef __APPLE__ - // The default drawing model for Apple is via the deprecated QuickDraw - // GrafPtr, and the default event model is via the deprecated Carbon - // EventRecord. - window_handle_type = P3D_WHT_osx_port; - event_type = P3D_ET_osx_event_record; - - // But we have to request the CoreGraphics drawing model to be compatible - // with Snow Leopard. - NPBool supports_core_graphics = false; -#ifdef MACOSX_HAS_COREGRAPHICS_DRAWING_MODEL - NPError err = browser->getvalue(instance, - NPNVsupportsCoreGraphicsBool, - &supports_core_graphics); - if (err != NPERR_NO_ERROR) { - supports_core_graphics = false; - } - - if (supports_core_graphics) { - // Set the drawing model - err = browser->setvalue(instance, - (NPPVariable)NPNVpluginDrawingModel, - (void *)NPDrawingModelCoreGraphics); - if (err == NPERR_NO_ERROR) { - window_handle_type = P3D_WHT_osx_cgcontext; - } - } -#endif // MACOSX_HAS_COREGRAPHICS_DRAWING_MODEL - nout << "supports_core_graphics = " << (bool)supports_core_graphics - << " window_handle_type = " << window_handle_type << "\n"; - - // And Snow Leopard also wants the new Cocoa event model. - NPBool supports_cocoa = false; -#ifdef MACOSX_HAS_EVENT_MODELS - err = browser->getvalue(instance, NPNVsupportsCocoaBool, &supports_cocoa); - if (err != NPERR_NO_ERROR) { - supports_cocoa = false; - } - - if (supports_cocoa) { - // Set the event model - err = browser->setvalue(instance, - (NPPVariable)NPPVpluginEventModel, - (void *)NPEventModelCocoa); - if (err == NPERR_NO_ERROR) { - event_type = P3D_ET_osx_cocoa; - } - } -#endif // MACOSX_HAS_EVENT_MODELS - nout << "supports_cocoa = " << (bool)supports_cocoa - << " event_type = " << event_type << "\n"; -#endif // __APPLE__ - - PPInstance *inst = new PPInstance(pluginType, instance, mode, - argc, argn, argv, saved, - window_handle_type, event_type); - instance->pdata = inst; - nout << "new instance->pdata = " << inst << "\n"; - - // To experiment with a "windowless" plugin, which really means we create - // our own window without an intervening window, try this. - // browser->setvalue(instance, NPPVpluginWindowBool, (void *)false); - - // Now that we have stored the pointer, we can call begin(), which starts to - // initiate downloads. - inst->begin(); - - return NPERR_NO_ERROR; -} - -/** - * Called by the browser to destroy an instance of the plugin previously - * created with NPP_New. - */ -NPError -NPP_Destroy(NPP instance, NPSavedData **save) { - nout << "destroy instance " << instance << ", " - << (PPInstance *)instance->pdata << "\n"; - nout << "save = " << (void *)save << "\n"; - // (*save) = NULL; - PPInstance *inst = (PPInstance *)(instance->pdata); - assert(inst != nullptr); - inst->stop_outstanding_streams(); - - delete inst; - instance->pdata = nullptr; - - return NPERR_NO_ERROR; -} - -/** - * Called by the browser to inform the instance of its window size and - * placement. This is called initially to create the window, and may be - * called subsequently when the window needs to be moved. It may be called - * redundantly. - */ -NPError -NPP_SetWindow(NPP instance, NPWindow *window) { - nout << "SetWindow " << window->x << ", " << window->y - << ", " << window->width << ", " << window->height - << "\n"; - - PPInstance *inst = (PPInstance *)(instance->pdata); - assert(inst != nullptr); - inst->set_window(window); - - return NPERR_NO_ERROR; -} - -/** - * Called by the browser when a new data stream is created, usually in - * response to a geturl request; but it is also called initially to supply the - * data in the data or src element. The plugin must specify how it can - * receive the stream. - */ -NPError -NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, - NPBool seekable, uint16_t *stype) { - nout << "NewStream " << type << ": " << (void *)stream - << ", " << stream->url << ", size = " << stream->end - << ", notifyData = " << stream->notifyData - << ", for " << instance - << ", " << (PPInstance *)(instance->pdata) << "\n"; - PPInstance::generic_browser_call(); - PPInstance *inst = (PPInstance *)(instance->pdata); - assert(inst != nullptr); - - return inst->new_stream(type, stream, seekable != 0, stype); -} - -/** - * Called by the browser to mark the end of a stream created with NewStream. - */ -NPError -NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) { - nout << "DestroyStream: " << (void *)stream << ", " << stream->url - << ", notifyData = " << stream->notifyData - << ", reason = " << reason - << ", for " << instance - << ", " << (PPInstance *)(instance->pdata) << "\n"; - - PPInstance::generic_browser_call(); - PPInstance *inst = (PPInstance *)(instance->pdata); - assert(inst != nullptr); - - return inst->destroy_stream(stream, reason); -} - -/** - * Called by the browser to ask how many bytes it can deliver for a stream. - */ -int32_t -NPP_WriteReady_x(NPP instance, NPStream *stream) { - // nout << "WriteReady " << stream->url << " for " << instance << ", " << - // (PPInstance *)(instance->pdata) << "\n"; - PPInstance::generic_browser_call(); - PPInstance *inst = (PPInstance *)(instance->pdata); - assert(inst != nullptr); - - return inst->write_ready(stream); -} - -/** - * Called by the browser to deliver bytes for the stream; the plugin should - * return the number of bytes consumed. - */ -int32_t -NPP_Write_x(NPP instance, NPStream *stream, int32_t offset, - int32_t len, void *buffer) { - // nout << "Write " << stream->url << ", " << offset << ", " << len << " for - // " << instance << ", " << (PPInstance *)(instance->pdata) << "\n"; - PPInstance::generic_browser_call(); - PPInstance *inst = (PPInstance *)(instance->pdata); - assert(inst != nullptr); - - return inst->write_stream(stream, offset, len, buffer); -} - -/** - * Called by the browser to report the filename that contains the fully- - * downloaded stream, if NP_ASFILEONLY was specified by the plugin in - * NPP_NewStream. - */ -void -NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) { - nout << "StreamAsFile " << stream->url - << ", " << stream->end - << ", notifyData = " << stream->notifyData - << "\n"; - - PPInstance::generic_browser_call(); - PPInstance *inst = (PPInstance *)(instance->pdata); - assert(inst != nullptr); - - inst->stream_as_file(stream, fname); -} - -/** - * Called by the browser when the user attempts to print the page containing - * the plugin instance. - */ -void -NPP_Print(NPP instance, NPPrint *platformPrint) { - nout << "Print\n"; -} - -/** - * Called by the browser to inform the plugin of OS window events. - */ -int16_t -NPP_HandleEvent(NPP instance, void *event) { - // nout << "HandleEvent\n"; - PPInstance::generic_browser_call(); - - PPInstance *inst = (PPInstance *)(instance->pdata); - assert(inst != nullptr); - - return inst->handle_event(event); -} - -/** - * Called by the browser to inform the plugin of a completed URL request. - */ -void -NPP_URLNotify(NPP instance, const char *url, - NPReason reason, void *notifyData) { - nout << "URLNotify: " << url - << ", notifyData = " << notifyData - << ", reason = " << reason - << "\n"; - - PPInstance::generic_browser_call(); - PPInstance *inst = (PPInstance *)(instance->pdata); - assert(inst != nullptr); - - inst->url_notify(url, reason, notifyData); -} - -/** - * Called by the browser to query specific information from the plugin. - */ -NPError -NPP_GetValue(NPP instance, NPPVariable variable, void *value) { - nout << "GetValue " << variable << "\n"; - PPInstance::generic_browser_call(); - PPInstance *inst = (PPInstance *)(instance->pdata); - assert(inst != nullptr); - - if (variable == NPPVpluginScriptableNPObject) { - NPObject *obj = inst->get_panda_script_object(); - if (obj != nullptr) { - *(NPObject **)value = obj; - return NPERR_NO_ERROR; - } - - } else if (variable == NPPVpluginNeedsXEmbed) { - // If we have Gtk2 available, we can use it to support the XEmbed - // protocol, which Chromium (at least) requires. - - // In this case, we'll say we can do it, if the browser supports it. - // (Though probably the browser wouldn't be asking if it couldn't.) - - NPBool supports_xembed = false; - NPError err = browser->getvalue(instance, NPNVSupportsXEmbedBool, &supports_xembed); - if (err != NPERR_NO_ERROR) { - supports_xembed = false; - } - nout << "browser supports_xembed: " << (supports_xembed != 0) << "\n"; -#ifdef HAVE_GTK - bool plugin_supports = true; -#else - bool plugin_supports = false; - supports_xembed = false; -#endif // HAVE_GTK - nout << "plugin supports_xembed: " << plugin_supports << "\n"; - - inst->set_xembed(supports_xembed != 0); - *(NPBool *)value = supports_xembed; - - return NPERR_NO_ERROR; - - } else { - return NP_GetValue(nullptr, variable, value); - } - - return NPERR_GENERIC_ERROR; -} - -/** - * Called by the browser to update a scriptable value. - */ -NPError -NPP_SetValue(NPP instance, NPNVariable variable, void *value) { - nout << "SetValue " << variable << "\n"; - PPInstance::generic_browser_call(); - return NPERR_GENERIC_ERROR; -} diff --git a/direct/src/plugin_npapi/startup.h b/direct/src/plugin_npapi/startup.h deleted file mode 100644 index e996f58084..0000000000 --- a/direct/src/plugin_npapi/startup.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file startup.h - * @author drose - * @date 2009-06-19 - */ - -#ifndef STARTUP_H -#define STARTUP_H - -#include "nppanda3d_common.h" - -#ifndef OSCALL -#define OSCALL -#endif - -extern "C" { -#ifdef _WIN32 - NPError OSCALL NP_Initialize(NPNetscapeFuncs *browserFuncs); -#else - NPError OSCALL NP_Initialize(NPNetscapeFuncs *browserFuncs, - NPPluginFuncs *pluginFuncs); -#endif - -#if NP_VERSION_MAJOR == 0 && NP_VERSION_MINOR <= 22 - // Until at least 0.22, this function was declared to return a char *. - char *NP_GetMIMEDescription(void); -#else - // At some point after 0.22, it was corrected to return a const char *. - const char *NP_GetMIMEDescription(void); -#endif - NPError NP_GetValue(void*, NPPVariable variable, void* value); - NPError OSCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs); - NPError OSCALL NP_Shutdown(void); -} - -void request_ready(P3D_instance *instance); - -#endif diff --git a/direct/src/plugin_standalone/make_osx_bundle.py b/direct/src/plugin_standalone/make_osx_bundle.py deleted file mode 100755 index c88ce5ecf7..0000000000 --- a/direct/src/plugin_standalone/make_osx_bundle.py +++ /dev/null @@ -1,97 +0,0 @@ -#! /usr/bin/env python - -""" - -This script constructs the bundle directory structure for the OSX -program panda3d_mac, which is built by the code in this directory. It -takes no parameters, and produces the app bundle in the same place. - -""" - -import getopt -import sys -import os -import glob -import shutil - -import direct -from panda3d.core import Filename, DSearchPath, getModelPath, ExecutionEnvironment - -def usage(code, msg = ''): - sys.stderr.write(__doc__) - sys.stderr.write(msg + '\n') - sys.exit(code) - -def makeBundle(startDir): - fstartDir = Filename.fromOsSpecific(startDir) - - # Search for panda3d_mac along $PATH. - path = DSearchPath() - if 'PATH' in os.environ: - path.appendPath(os.environ['PATH']) - path.appendPath(os.defpath) - panda3d_mac = path.findFile('panda3d_mac') - if not panda3d_mac: - raise Exception("Couldn't find panda3d_mac on path.") - - # Construct a search path to look for the images. - search = DSearchPath() - - # First on the path: an explicit $PLUGIN_IMAGES env var. - if ExecutionEnvironment.hasEnvironmentVariable('PLUGIN_IMAGES'): - search.appendDirectory(Filename.expandFrom('$PLUGIN_IMAGES')) - - # Next on the path: the models/plugin_images directory within the - # current directory. - search.appendDirectory('models/plugin_images') - - # Finally on the path: models/plugin_images within the model - # search path. - for dir in getModelPath().getDirectories(): - search.appendDirectory(Filename(dir, 'plugin_images')) - - # Now find the icon file on the above search path. - icons = search.findFile('panda3d.icns') - if not icons: - raise Exception("Couldn't find panda3d.icns on model-path.") - - # Generate the bundle directory structure - rootFilename = Filename(fstartDir) - bundleFilename = Filename(rootFilename, 'Panda3D.app') - if os.path.exists(bundleFilename.toOsSpecific()): - shutil.rmtree(bundleFilename.toOsSpecific()) - - plistFilename = Filename(bundleFilename, 'Contents/Info.plist') - plistFilename.makeDir() - exeFilename = Filename(bundleFilename, 'Contents/MacOS/panda3d_mac') - exeFilename.makeDir() - iconFilename = Filename(bundleFilename, 'Contents/Resources/panda3d.icns') - iconFilename.makeDir() - - # Copy in Info.plist, the icon file, and the compiled executable. - shutil.copyfile(Filename(fstartDir, "panda3d_mac.plist").toOsSpecific(), plistFilename.toOsSpecific()) - shutil.copyfile(icons.toOsSpecific(), iconFilename.toOsSpecific()) - print('%s %s' % (panda3d_mac, exeFilename)) - shutil.copyfile(panda3d_mac.toOsSpecific(), exeFilename.toOsSpecific()) - os.chmod(exeFilename.toOsSpecific(), 0o755) - - # All done! - bundleFilename.touch() - print(bundleFilename.toOsSpecific()) - -if __name__ == '__main__': - try: - opts, args = getopt.getopt(sys.argv[1:], 'h') - except getopt.error as msg: - usage(1, msg) - - for opt, arg in opts: - if opt == '-h': - usage(0) - - if args: - usage(1, 'No arguments are expected.') - - startDir = os.path.split(sys.argv[0])[0] - makeBundle(startDir) - diff --git a/direct/src/plugin_standalone/p3dEmbed.cxx b/direct/src/plugin_standalone/p3dEmbed.cxx deleted file mode 100644 index 1d191e9c22..0000000000 --- a/direct/src/plugin_standalone/p3dEmbed.cxx +++ /dev/null @@ -1,261 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dEmbed.cxx - * @author rdb - * @date 2009-12-07 - */ - -#define P3D_FUNCTION_PROTOTYPES - -#include "p3dEmbed.h" -#include "load_plugin.h" -#include "find_root_dir.h" - -using std::cerr; -using std::string; - -/** - * - */ -P3DEmbed:: -P3DEmbed(bool console_environment) : Panda3DBase(console_environment) { - // Since the Panda3DBase constructor no longer assigns _root_dir, we have to - // do it here. - _root_dir = find_root_dir(); - - // We should leave the arguments intact, just pass them 1:1 as we've - // received them. - _prepend_filename_to_args = false; -} - -/** - * Runs with the data embedded in the current executable, at the specified - * offset. - */ -int P3DEmbed:: -run_embedded(std::streampos read_offset, int argc, char *argv[]) { - // Check to see if we've actually got an application embedded. If we do, - // read_offset will have been modified to contain a different value than the - // one we compiled in, above. We test against read_offset + 1, because any - // appearances of this exact number within the binary will be replaced - // (including this one). - - // We also have to store this computation in a member variable, to work - // around a compiler optimization that might otherwise remove the + 1 from - // the test. - _read_offset_check = read_offset + (std::streampos)1; - if (_read_offset_check == (std::streampos)0xFF3D3D01) { - cerr << "This program is not intended to be run directly.\nIt is used " - "by pdeploy to construct an embedded Panda3D application.\n"; - return 1; - } - - // Make sure the splash window will be put in the center of the screen - _win_x = -2; - _win_y = -2; - - // Read out some parameters from the binary - pifstream read; - Filename f = ExecutionEnvironment::get_binary_name(); - f.make_absolute(); - f.set_binary(); - if (!f.open_read(read)) { - cerr << "Failed to read from stream. Maybe the binary is corrupt?\n"; - return 1; - } - read.seekg(read_offset); - int curchr = read.get(); - if (curchr == EOF) { - cerr << "Couldn't seek to " << read_offset << "\n"; - return 1; - } - - string curstr; - bool havenull = false; - P3D_token token; - token._keyword = nullptr; - token._value = nullptr; - string keyword; - string value; - string root_dir; - string host_dir; - string start_dir; - - while (true) { - if (curchr == EOF) { - cerr << "Truncated stream\n"; - return 1; - - } else if (curchr == 0) { - // Two null bytes in a row means we've reached the end of the data. - if (havenull) { - break; - } - - // This means we haven't seen an '=' character yet. - if (keyword == "") { - if (curstr != "") { - cerr << "Ignoring token '" << curstr << "' without value\n"; - } - - } else if (keyword == "start_dir") { - // Don't pass this on as a token, since it has slightly different - // semantics when used as an HTML token. - start_dir = curstr; - - } else { - value.assign(curstr); - P3D_token token; - token._keyword = strdup(keyword.c_str()); - token._value = strdup(value.c_str()); - _tokens.push_back(token); - - // Read out the tokens that may interest us - if (keyword == "width") { - _win_width = atoi(value.c_str()); - _got_win_size = true; - } else if (keyword == "height") { - _win_height = atoi(value.c_str()); - _got_win_size = true; - } else if (keyword == "log_basename") { - _log_basename = value; - } else if (keyword == "log_directory") { - _log_dirname = value; - } else if (keyword == "root_dir") { - root_dir = value; - } else if (keyword == "host_dir") { - host_dir = value; - } else if (keyword == "verify_contents") { - if (value == "never") { - _verify_contents = P3D_VC_never; - } else if (value == "force") { - _verify_contents = P3D_VC_force; - } else if (value == "normal") { - _verify_contents = P3D_VC_normal; - } else if (value == "none") { - _verify_contents = P3D_VC_none; - } else { - _verify_contents = (P3D_verify_contents)atoi(value.c_str()); - } - } - } - curstr = ""; - havenull = true; - } else if (curchr == '=') { - keyword.assign(curstr); - curstr = ""; - havenull = false; - } else { - curstr += curchr; - havenull = false; - } - curchr = read.get(); - } - - // Update the offset to the current read pointer. This is where the - // multifile really starts. - read_offset = read.tellg(); - read.close(); - - // Make the root directory absolute - if (!root_dir.empty()) { - Filename root_dir_f(root_dir); - root_dir_f.make_absolute(f.get_dirname()); - _root_dir = root_dir_f.to_os_specific(); - } - - // Make the host directory absolute - if (!host_dir.empty()) { - Filename host_dir_f(host_dir); - host_dir_f.make_absolute(f.get_dirname()); - _host_dir = host_dir_f.to_os_specific(); - } - - // Make the start directory absolute - if (!start_dir.empty()) { - Filename start_dir_f(start_dir); - start_dir_f.make_absolute(f.get_dirname()); - _start_dir = start_dir_f.to_os_specific(); - } - - // Initialize the core API by directly assigning all of the function - // pointers. - P3D_initialize_ptr = &P3D_initialize; - P3D_finalize_ptr = &P3D_finalize; - P3D_set_plugin_version_ptr = &P3D_set_plugin_version; - P3D_set_super_mirror_ptr = &P3D_set_super_mirror; - P3D_new_instance_ptr = &P3D_new_instance; - P3D_instance_start_ptr = &P3D_instance_start; - P3D_instance_start_stream_ptr = &P3D_instance_start_stream; - P3D_instance_finish_ptr = &P3D_instance_finish; - P3D_instance_setup_window_ptr = &P3D_instance_setup_window; - - P3D_object_get_type_ptr = &P3D_object_get_type; - P3D_object_get_bool_ptr = &P3D_object_get_bool; - P3D_object_get_int_ptr = &P3D_object_get_int; - P3D_object_get_float_ptr = &P3D_object_get_float; - P3D_object_get_string_ptr = &P3D_object_get_string; - P3D_object_get_repr_ptr = &P3D_object_get_repr; - P3D_object_get_property_ptr = &P3D_object_get_property; - P3D_object_set_property_ptr = &P3D_object_set_property; - P3D_object_has_method_ptr = &P3D_object_has_method; - P3D_object_call_ptr = &P3D_object_call; - P3D_object_eval_ptr = &P3D_object_eval; - P3D_object_incref_ptr = &P3D_object_incref; - P3D_object_decref_ptr = &P3D_object_decref; - - P3D_make_class_definition_ptr = &P3D_make_class_definition; - P3D_new_undefined_object_ptr = &P3D_new_undefined_object; - P3D_new_none_object_ptr = &P3D_new_none_object; - P3D_new_bool_object_ptr = &P3D_new_bool_object; - P3D_new_int_object_ptr = &P3D_new_int_object; - P3D_new_float_object_ptr = &P3D_new_float_object; - P3D_new_string_object_ptr = &P3D_new_string_object; - P3D_instance_get_panda_script_object_ptr = &P3D_instance_get_panda_script_object; - P3D_instance_set_browser_script_object_ptr = &P3D_instance_set_browser_script_object; - - P3D_instance_get_request_ptr = &P3D_instance_get_request; - P3D_check_request_ptr = &P3D_check_request; - P3D_request_finish_ptr = &P3D_request_finish; - P3D_instance_feed_url_stream_ptr = &P3D_instance_feed_url_stream; - P3D_instance_handle_event_ptr = &P3D_instance_handle_event; - - // Calling the executable with --prep just prepares the directory structure, - // this is usually invoked in the installer. - if (argc == 2 && strcmp(argv[1], "--prep") == 0) { - cerr << "Invoking the prepare step is deprecated, please rebuild the application using a more recent version of pdeploy\n"; - _window_type = P3D_WT_hidden; - _log_basename = "prep"; - P3D_token token; - token._keyword = "stop_on_ready"; - token._value = "1"; - _tokens.push_back(token); - token._keyword = "hidden"; - token._value = "1"; - _tokens.push_back(token); - } - - // Now call init_plugin() to verify that we got all of the required function - // pointers. This will also call P3D_initialize(). - if (!init_plugin("", _host_url, _verify_contents, _this_platform, - _log_dirname, _log_basename, true, _console_environment, - _root_dir, _host_dir, _start_dir, cerr)) { - cerr << "Unable to launch core API\n"; - return 1; - } - - // Create a plugin instance and run the program - P3D_instance *inst = create_instance(f, true, argv, argc, read_offset); - _instances.insert(inst); - - run_main_loop(); - - unload_plugin(cerr); - return 0; -} diff --git a/direct/src/plugin_standalone/p3dEmbed.h b/direct/src/plugin_standalone/p3dEmbed.h deleted file mode 100644 index 7d1da92883..0000000000 --- a/direct/src/plugin_standalone/p3dEmbed.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dEmbed.h - * @author drose - * @date 2010-01-04 - */ - -#ifndef P3DEMBED_H -#define P3DEMBED_H - -#include "dtoolbase.h" -#ifdef _WIN32 -#include -#endif - -#include "panda3dBase.h" -#include "p3d_plugin.h" -#include "httpChannel.h" -#include "ramfile.h" -#include "fileSpec.h" -#include "pset.h" -#include "vector_string.h" - -/** - * This program is constructed to self-embed a p3d file and execute it - * directly. - */ -class P3DEmbed : public Panda3DBase { -public: - P3DEmbed(bool console_environment); - - int run_embedded(std::streampos read_offset, int argc, char *argv[]); - - std::streampos _read_offset_check; -}; - -#endif diff --git a/direct/src/plugin_standalone/p3dEmbedMain.cxx b/direct/src/plugin_standalone/p3dEmbedMain.cxx deleted file mode 100644 index 0aa3d2eb35..0000000000 --- a/direct/src/plugin_standalone/p3dEmbedMain.cxx +++ /dev/null @@ -1,35 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file p3dEmbedMain.cxx - * @author drose - * @date 2010-01-04 - */ - -#include "p3dEmbed.h" - -#ifdef P3DEMBEDW -#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup") -#endif - -#ifdef _WIN32 -volatile unsigned __int32 p3d_offset = 0xFF3D3D00; -#else -#include -volatile uint32_t p3d_offset = 0xFF3D3D00; -#endif - -int -main(int argc, char *argv[]) { -#ifdef P3DEMBEDW - P3DEmbed program(false); -#else - P3DEmbed program(true); -#endif - return program.run_embedded(p3d_offset, argc, argv); -} diff --git a/direct/src/plugin_standalone/panda3d.I b/direct/src/plugin_standalone/panda3d.I deleted file mode 100644 index ba15732f4d..0000000000 --- a/direct/src/plugin_standalone/panda3d.I +++ /dev/null @@ -1,12 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file panda3d.I - * @author drose - * @date 2009-06-30 - */ diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx deleted file mode 100644 index d21933a441..0000000000 --- a/direct/src/plugin_standalone/panda3d.cxx +++ /dev/null @@ -1,942 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file panda3d.cxx - * @author drose - * @date 2009-06-03 - */ - -#include "panda3d.h" -#include "load_plugin.h" -#include "p3d_plugin_config.h" -#include "find_root_dir.h" -#include "pandaSystem.h" -#include "dtool_platform.h" -#include "pandaVersion.h" -#include "panda_getopt.h" - -#include -#include -#include -#ifdef _WIN32 -#include -#else -#include -#endif - -using std::cerr; -using std::cout; -using std::string; - -/** - * - */ -Panda3D:: -Panda3D(bool console_environment) : Panda3DBase(console_environment) { - // We use the runtime PandaSystem setting for this value, rather than the - // hard-compiled-in setting, to allow users to override this with a - // Config.prc variable if needed. - _host_url = PandaSystem::get_package_host_url(); -} - -/** - * Starts the program going, with command-line arguments. Returns 0 on - * success, nonzero on failure. - */ -int Panda3D:: -run_command_line(int argc, char *argv[]) { - extern char *optarg; - extern int optind; - - // We prefix a "+" sign to tell getopt not to parse options following the - // first not-option parameter. (These will be passed into the sub-process.) - const char *optstr = "+mu:M:Sp:nfw:t:s:o:l:iVUPh"; - - bool allow_multiple = false; - - int flag = getopt(argc, argv, optstr); - - while (flag != EOF) { - switch (flag) { - case 'm': - allow_multiple = true; - break; - - case 'u': - _host_url = optarg; - break; - - case 'M': - _super_mirror_url = optarg; - break; - - case 'S': - _enable_security = true; - break; - - case 'p': - _this_platform = optarg; - _coreapi_platform = optarg; - break; - - case 'n': - _verify_contents = P3D_VC_normal; - break; - - case 'f': - _verify_contents = P3D_VC_force; - break; - - case 'w': - if (strcmp(optarg, "toplevel") == 0) { - _window_type = P3D_WT_toplevel; - } else if (strcmp(optarg, "embedded") == 0) { - _window_type = P3D_WT_embedded; - } else if (strcmp(optarg, "fullscreen") == 0) { - _window_type = P3D_WT_fullscreen; - } else if (strcmp(optarg, "hidden") == 0) { - _window_type = P3D_WT_hidden; - } else { - cerr << "Invalid value for -w: " << optarg << "\n"; - return 1; - } - break; - - case 't': - if (!parse_token(optarg)) { - cerr << "Web tokens (-t) must be of the form token=value: " << optarg << "\n"; - return 1; - } - break; - - case 's': - if (!parse_int_pair(optarg, _win_width, _win_height)) { - cerr << "Invalid value for -s: " << optarg << "\n"; - return 1; - } - _got_win_size = true; - break; - - case 'o': - if (!parse_int_pair(optarg, _win_x, _win_y)) { - cerr << "Invalid value for -o: " << optarg << "\n"; - return 1; - } - break; - - case 'l': - _log_dirname = Filename::from_os_specific(optarg).to_os_specific(); - _log_basename = "p3dcore"; - break; - - case 'i': - { - P3D_token token; - token._keyword = "keep_pythonpath"; - token._value = "1"; - _tokens.push_back(token); - token._keyword = "interactive_console"; - token._value = "1"; - _tokens.push_back(token); - - // We should also ignore control-C in this case, so that an interrupt - // will be delivered to the subordinate Python process and return to a - // command shell, and won't just kill the panda3d process. -#ifdef _WIN32 - SetConsoleCtrlHandler(nullptr, true); -#else - struct sigaction ignore; - memset(&ignore, 0, sizeof(ignore)); - ignore.sa_handler = SIG_IGN; - sigaction(SIGINT, &ignore, nullptr); -#endif // _WIN32 - } - break; - - case 'V': - cout << P3D_PLUGIN_MAJOR_VERSION << "." - << P3D_PLUGIN_MINOR_VERSION << "." - << P3D_PLUGIN_SEQUENCE_VERSION; -#ifndef PANDA_OFFICIAL_VERSION - cout << "c"; -#endif - cout << "\n"; - exit(0); - - case 'U': - cout << _host_url << "\n"; - exit(0); - - case 'P': - cout << DTOOL_PLATFORM << "\n"; - exit(0); - - case 'h': - case '?': - case '+': - default: - usage(); - return 1; - } - flag = getopt(argc, argv, optstr); - } - - argc -= (optind-1); - argv += (optind-1); - - if (argc < 2 && _exit_with_last_instance) { - // No instances on the command line--that *might* be an error. - usage(); - return 1; - } - - if (!post_arg_processing()) { - return 1; - } - - int num_instance_filenames, num_instance_args; - char **instance_filenames, **instance_args; - - if (argc > 1) { - if (allow_multiple) { - // With -m, the remaining arguments are all instance filenames. - num_instance_filenames = argc - 1; - instance_filenames = argv + 1; - num_instance_args = 0; - instance_args = argv + argc; - - } else { - // Without -m, there is one instance filename, and everything else gets - // delivered to that instance. - num_instance_filenames = 1; - instance_filenames = argv + 1; - num_instance_args = argc - 2; - instance_args = argv + 2; - } - - if (_window_type == P3D_WT_embedded) { - // The user asked for an embedded window. Create a toplevel window to - // be its parent, of the requested size. - if (_win_width == 0 && _win_height == 0) { - _win_width = 800; - _win_height = 600; - } - - make_parent_window(); - - // Center the child window(s) within the parent window. -#ifdef _WIN32 - assert(_parent_window._window_handle_type == P3D_WHT_win_hwnd); - HWND parent_hwnd = _parent_window._handle._win_hwnd._hwnd; - - RECT rect; - GetClientRect(parent_hwnd, &rect); - - _win_x = (int)(rect.right * 0.1); - _win_y = (int)(rect.bottom * 0.1); - _win_width = (int)(rect.right * 0.8); - _win_height = (int)(rect.bottom * 0.8); -#endif - - // Subdivide the window into num_x_spans * num_y_spans sub-windows. - int num_y_spans = int(sqrt((double)num_instance_filenames)); - int num_x_spans = (num_instance_filenames + num_y_spans - 1) / num_y_spans; - - int origin_x = _win_x; - int origin_y = _win_y; - _win_width = _win_width / num_x_spans; - _win_height = _win_height / num_y_spans; - _got_win_size = true; - - for (int yi = 0; yi < num_y_spans; ++yi) { - for (int xi = 0; xi < num_x_spans; ++xi) { - int i = yi * num_x_spans + xi; - if (i >= num_instance_filenames) { - continue; - } - - // Create instance i at window slot (xi, yi). - _win_x = origin_x + xi * _win_width; - _win_y = origin_y + yi * _win_height; - - P3D_instance *inst = create_instance - (instance_filenames[i], true, - instance_args, num_instance_args); - _instances.insert(inst); - } - } - - } else { - // Not an embedded window. Create each window with the same parameters. - for (int i = 0; i < num_instance_filenames; ++i) { - P3D_instance *inst = create_instance - (instance_filenames[i], true, - instance_args, num_instance_args); - _instances.insert(inst); - } - } - } - - run_main_loop(); - - // All instances have finished; we can exit. - unload_plugin(cerr); - return 0; -} - -/** - * Sets up some internal state after processing the command-line arguments. - * Returns true on success, false on failure. - */ -bool Panda3D:: -post_arg_processing() { - // Now is a good time to assign _root_dir. - _root_dir = find_root_dir(); - - // Set host_url_prefix to end with a slash. - _host_url_prefix = _host_url; - if (!_host_url_prefix.empty() && _host_url_prefix[_host_url_prefix.length() - 1] != '/') { - _host_url_prefix += '/'; - } - _download_url_prefix = _host_url_prefix; - - // If the "super mirror" URL is a filename, convert it to a file: url. - if (!_super_mirror_url.empty()) { - if (!is_url(_super_mirror_url)) { - Filename filename = Filename::from_os_specific(_super_mirror_url); - filename.make_absolute(); - string path = filename.to_os_generic(); - if (!path.empty() && path[0] != '/') { - // On Windows, a leading drive letter must be preceded by an - // additional slash. - path = "/" + path; - } - _super_mirror_url = "file://" + path; - } - - // And make sure the super_mirror_url_prefix ends with a slash. - _super_mirror_url_prefix = _super_mirror_url; - if (!_super_mirror_url_prefix.empty() && _super_mirror_url_prefix[_super_mirror_url_prefix.length() - 1] != '/') { - _super_mirror_url_prefix += '/'; - } - } - - if (!get_plugin()) { - cerr << "Unable to load Panda3D plugin.\n"; - return false; - } - - // Set up the "super mirror" URL, if specified. - if (!_super_mirror_url.empty()) { - P3D_set_super_mirror_ptr(_super_mirror_url.c_str()); - } - - return true; -} - -/** - * Downloads the contents.xml file from the named URL and attempts to use it - * to load the core API. Returns true on success, false on failure. - */ -bool Panda3D:: -get_plugin() { - // First, look for the existing contents.xml file. - bool success = false; - bool is_fresh = false; - - Filename contents_filename = Filename(Filename::from_os_specific(_root_dir), "contents.xml"); - if (_verify_contents != P3D_VC_force) { - if (read_contents_file(contents_filename, false)) { - if (_verify_contents == P3D_VC_none || time(nullptr) < _contents_expiration) { - // Got the file, and it's good. - success = true; - } - } - } - - if (!success) { - // Couldn't read it (or it wasn't current enough), so go get a new one. - if (!download_contents_file(contents_filename)) { - // We don't have a usable contents.xml file. - return false; - } - is_fresh = true; - } - - // Now that we've downloaded the contents file successfully, start the Core - // API. - if (!get_core_api()) { - // We failed. Make sure contents.xml is up-to-date and try again. - if (!is_fresh && download_contents_file(contents_filename) && get_core_api()) { - return true; - } else { - return false; - } - } - - return true; -} - -/** - * Redownloads the contents.xml file from the named URL without first checking - * if it is up to date. Returns true if we have a contents.xml file that - * might be usable, false otherwise. - */ -bool Panda3D:: -download_contents_file(const Filename &contents_filename) { - bool success = false; - HTTPClient *http = HTTPClient::get_global_ptr(); - - // Try the super_mirror first. - if (!_super_mirror_url_prefix.empty()) { - // We don't bother putting a uniquifying query string when we're - // downloading this file from the super_mirror. The super_mirror is by - // definition a cache, so it doesn't make sense to bust caches here. - string url = _super_mirror_url_prefix + "contents.xml"; - PT(HTTPChannel) channel = http->make_channel(false); - channel->get_document(url); - - Filename tempfile = Filename::temporary("", "p3d_"); - if (!channel->download_to_file(tempfile)) { - cerr << "Unable to download " << url << "\n"; - tempfile.unlink(); - } else { - // Successfully downloaded from the super_mirror; try to read it. - success = read_contents_file(tempfile, true); - tempfile.unlink(); - } - } - - if (!success) { - // Go download contents.xml from the actual host. - std::ostringstream strm; - strm << _host_url_prefix << "contents.xml"; - // Append a uniquifying query string to the URL to force the download to - // go all the way through any caches. We use the time in seconds; that's - // unique enough. - strm << "?" << time(nullptr); - string url = strm.str(); - - // We might as well explicitly request the cache to be disabled too, since - // we have an interface for that via HTTPChannel. - DocumentSpec request(url); - request.set_cache_control(DocumentSpec::CC_no_cache); - - PT(HTTPChannel) channel = http->make_channel(false); - channel->get_document(request); - - // Since we have to download some of it, might as well ask the core API to - // check all of it. - if (_verify_contents == P3D_VC_none) { - _verify_contents = P3D_VC_normal; - } - - // First, download it to a temporary file. - Filename tempfile = Filename::temporary("", "p3d_"); - if (!channel->download_to_file(tempfile)) { - cerr << "Unable to download " << url << "\n"; - - // Couldn't download, but try to read the existing contents.xml file - // anyway. Maybe it's good enough. - success = read_contents_file(contents_filename, false); - - } else { - // Successfully downloaded; read it and move it into place. - success = read_contents_file(tempfile, true); - } - - tempfile.unlink(); - } - - return success; -} - -/** - * Attempts to open and read the contents.xml file on disk. Copies the file - * to its standard location on success. Returns true on success, false on - * failure. - */ -bool Panda3D:: -read_contents_file(const Filename &contents_filename, bool fresh_download) { - string os_contents_filename = contents_filename.to_os_specific(); - TiXmlDocument doc(os_contents_filename.c_str()); - if (!doc.LoadFile()) { - return false; - } - - bool found_core_package = false; - - TiXmlElement *xcontents = doc.FirstChildElement("contents"); - if (xcontents != nullptr) { - int max_age = P3D_CONTENTS_DEFAULT_MAX_AGE; - xcontents->Attribute("max_age", &max_age); - - // Get the latest possible expiration time, based on the max_age - // indication. Any expiration time later than this is in error. - time_t now = time(nullptr); - _contents_expiration = now + (time_t)max_age; - - if (fresh_download) { - // Update the XML with the new download information. - TiXmlElement *xorig = xcontents->FirstChildElement("orig"); - while (xorig != nullptr) { - xcontents->RemoveChild(xorig); - xorig = xcontents->FirstChildElement("orig"); - } - - xorig = new TiXmlElement("orig"); - xcontents->LinkEndChild(xorig); - - xorig->SetAttribute("expiration", (int)_contents_expiration); - - } else { - // Read the expiration time from the XML. - int expiration = 0; - TiXmlElement *xorig = xcontents->FirstChildElement("orig"); - if (xorig != nullptr) { - xorig->Attribute("expiration", &expiration); - } - - _contents_expiration = std::min(_contents_expiration, (time_t)expiration); - } - - // Look for the entry; it might point us at a different download - // URL, and it might mention some mirrors. - find_host(xcontents); - - // Now look for the core API package. - _coreapi_set_ver = ""; - TiXmlElement *xpackage = xcontents->FirstChildElement("package"); - while (xpackage != nullptr) { - const char *name = xpackage->Attribute("name"); - if (name != nullptr && strcmp(name, "coreapi") == 0) { - const char *platform = xpackage->Attribute("platform"); - if (platform != nullptr && _coreapi_platform == string(platform)) { - _coreapi_dll.load_xml(xpackage); - const char *set_ver = xpackage->Attribute("set_ver"); - if (set_ver != nullptr) { - _coreapi_set_ver = set_ver; - } - found_core_package = true; - break; - } - } - - xpackage = xpackage->NextSiblingElement("package"); - } - } - - if (!found_core_package) { - // Couldn't find the coreapi package description. - nout << "No coreapi package defined in contents file for " - << _coreapi_platform << "\n"; - return false; - } - - // Check the coreapi_set_ver token. If it is given, it specifies a minimum - // Core API version number we expect to find. If we didn't find that - // number, perhaps our contents.xml is out of date. - string coreapi_set_ver = lookup_token("coreapi_set_ver"); - if (!coreapi_set_ver.empty()) { - nout << "Instance asked for Core API set_ver " << coreapi_set_ver - << ", we found " << _coreapi_set_ver << "\n"; - // But don't bother if we just freshly downloaded it. - if (!fresh_download) { - if (compare_seq(coreapi_set_ver, _coreapi_set_ver) > 0) { - // The requested set_ver value is higher than the one we have on file; - // our contents.xml file must be out of date after all. - nout << "expiring contents.xml\n"; - _contents_expiration = 0; - } - } - } - - // Success. Now copy the file into place. - Filename standard_filename = Filename(Filename::from_os_specific(_root_dir), "contents.xml"); - if (fresh_download) { - Filename tempfile = Filename::temporary("", "p3d_"); - string os_specific = tempfile.to_os_specific(); - if (!doc.SaveFile(os_specific.c_str())) { - nout << "Couldn't write to " << tempfile << "\n"; - tempfile.unlink(); - return false; - } - tempfile.rename_to(standard_filename); - - } else { - if (contents_filename != standard_filename) { - if (!contents_filename.rename_to(standard_filename)) { - nout << "Couldn't move contents.xml to " << standard_filename << "\n"; - contents_filename.unlink(); - return false; - } - } - } - - return true; -} - -/** - * Scans the element for the matching element. - */ -void Panda3D:: -find_host(TiXmlElement *xcontents) { - TiXmlElement *xhost = xcontents->FirstChildElement("host"); - if (xhost != nullptr) { - const char *url = xhost->Attribute("url"); - if (url != nullptr && _host_url == string(url)) { - // We're the primary host. This is the normal case. - read_xhost(xhost); - return; - - } else { - // We're not the primary host; perhaps we're an alternate host. - TiXmlElement *xalthost = xhost->FirstChildElement("alt_host"); - while (xalthost != nullptr) { - const char *url = xalthost->Attribute("url"); - if (url != nullptr && _host_url == string(url)) { - // Yep, we're this alternate host. - read_xhost(xhost); - return; - } - xalthost = xalthost->NextSiblingElement("alt_host"); - } - } - - // Hmm, didn't find the URL we used mentioned. Assume we're the primary - // host. - read_xhost(xhost); - } -} - -/** - * Reads the host data from the (or ) entry in the - * contents.xml file. - */ -void Panda3D:: -read_xhost(TiXmlElement *xhost) { - // Get the "download" URL, which is the source from which we download - // everything other than the contents.xml file. - const char *download_url = xhost->Attribute("download_url"); - if (download_url == nullptr) { - download_url = xhost->Attribute("url"); - } - - if (download_url != nullptr) { - _download_url_prefix = download_url; - } else { - _download_url_prefix = _host_url_prefix; - } - if (!_download_url_prefix.empty()) { - if (_download_url_prefix[_download_url_prefix.size() - 1] != '/') { - _download_url_prefix += "/"; - } - } - - TiXmlElement *xmirror = xhost->FirstChildElement("mirror"); - while (xmirror != nullptr) { - const char *url = xmirror->Attribute("url"); - if (url != nullptr) { - add_mirror(url); - } - xmirror = xmirror->NextSiblingElement("mirror"); - } -} - -/** - * Adds a new URL to serve as a mirror for this host. The mirrors will be - * consulted first, before consulting the host directly. - */ -void Panda3D:: -add_mirror(string mirror_url) { - // Ensure the URL ends in a slash. - if (!mirror_url.empty() && mirror_url[mirror_url.size() - 1] != '/') { - mirror_url += '/'; - } - - // Add it to the _mirrors list, but only if it's not already there. - if (find(_mirrors.begin(), _mirrors.end(), mirror_url) == _mirrors.end()) { - _mirrors.push_back(mirror_url); - } -} - -/** - * Selects num_mirrors elements, chosen at random, from the _mirrors list. - * Adds the selected mirrors to result. If there are fewer than num_mirrors - * elements in the list, adds only as many mirrors as we can get. - */ -void Panda3D:: -choose_random_mirrors(vector_string &result, int num_mirrors) { - pvector selected; - - size_t num_to_select = std::min(_mirrors.size(), (size_t)num_mirrors); - while (num_to_select > 0) { - size_t i = (size_t)(((double)rand() / (double)RAND_MAX) * _mirrors.size()); - while (find(selected.begin(), selected.end(), i) != selected.end()) { - // Already found this i, find a new one. - i = (size_t)(((double)rand() / (double)RAND_MAX) * _mirrors.size()); - } - selected.push_back(i); - result.push_back(_mirrors[i]); - --num_to_select; - } -} - -/** - * Checks the core API DLL file against the specification in the contents - * file, and downloads it if necessary. - */ -bool Panda3D:: -get_core_api() { - bool is_fresh = false; - if (!_coreapi_dll.quick_verify(_root_dir)) { - if (!download_core_api()) { - return false; - } - is_fresh = true; - } - - // Now we've got the DLL. Load it. - string pathname = _coreapi_dll.get_pathname(_root_dir); - -#ifdef P3D_PLUGIN_P3D_PLUGIN - // This is a convenience macro for development. If defined and nonempty, it - // indicates the name of the plugin DLL that we will actually run, even - // after downloading a possibly different (presumably older) version. Its - // purpose is to simplify iteration on the plugin DLL. - string override_filename = P3D_PLUGIN_P3D_PLUGIN; - if (!override_filename.empty()) { - pathname = override_filename; - } -#endif // P3D_PLUGIN_P3D_PLUGIN - - bool trusted_environment = !_enable_security; - - Filename contents_filename = Filename(Filename::from_os_specific(_root_dir), "contents.xml"); - if (!load_plugin(pathname, contents_filename.to_os_specific(), - _host_url, _verify_contents, _this_platform, _log_dirname, - _log_basename, trusted_environment, _console_environment, - _root_dir, _host_dir, _start_dir, cerr)) { - - // If we're not sure this is the latest version, make sure it is up-to- - // date, and then try again. - if (is_fresh || !download_core_api() || - !load_plugin(pathname, contents_filename.to_os_specific(), - _host_url, _verify_contents, _this_platform, _log_dirname, - _log_basename, trusted_environment, _console_environment, - _root_dir, _host_dir, _start_dir, cerr)) { - - cerr << "Unable to launch core API in " << pathname << "\n"; - return false; - } - } - - // Successfully loaded. -#ifdef PANDA_OFFICIAL_VERSION - static const bool official = true; -#else - static const bool official = false; -#endif - - // Format the coreapi_timestamp as a string, for passing as a parameter. - std::ostringstream stream; - stream << _coreapi_dll.get_timestamp(); - string coreapi_timestamp = stream.str(); - - P3D_set_plugin_version_ptr(P3D_PLUGIN_MAJOR_VERSION, P3D_PLUGIN_MINOR_VERSION, - P3D_PLUGIN_SEQUENCE_VERSION, official, - PANDA_DISTRIBUTOR, - _host_url.c_str(), coreapi_timestamp.c_str(), - _coreapi_set_ver.c_str()); - - return true; -} - -/** - * Downloads the latest version of the core API from the plug-in server. - */ -bool Panda3D:: -download_core_api() { - // The DLL file needs to be downloaded. Build up our list of URL's to - // attempt to download it from, in reverse order. - string url; - vector_string core_urls; - - // Our last act of desperation: hit the original host, with a query - // uniquifier, to break through any caches. - std::ostringstream strm; - strm << _download_url_prefix << _coreapi_dll.get_filename() - << "?" << time(nullptr); - url = strm.str(); - core_urls.push_back(url); - - // Before we try that, we'll hit the original host, without a uniquifier. - url = _download_url_prefix; - url += _coreapi_dll.get_filename(); - core_urls.push_back(url); - - // And before we try that, we'll try two mirrors, at random. - vector_string mirrors; - choose_random_mirrors(mirrors, 2); - for (vector_string::iterator si = mirrors.begin(); - si != mirrors.end(); - ++si) { - url = (*si) + _coreapi_dll.get_filename(); - core_urls.push_back(url); - } - - // The very first thing we'll try is the super_mirror, if we have one. - if (!_super_mirror_url_prefix.empty()) { - url = _super_mirror_url_prefix + _coreapi_dll.get_filename(); - core_urls.push_back(url); - } - - // Now pick URL's off the list, and try them, until we have success. - Filename pathname = Filename::from_os_specific(_coreapi_dll.get_pathname(_root_dir)); - pathname.make_dir(); - HTTPClient *http = HTTPClient::get_global_ptr(); - - bool success = false; - while (!core_urls.empty()) { - url = core_urls.back(); - core_urls.pop_back(); - - PT(HTTPChannel) channel = http->get_document(url); - if (!channel->download_to_file(pathname)) { - cerr << "Unable to download " << url << "\n"; - - } else if (!_coreapi_dll.full_verify(_root_dir)) { - cerr << "Mismatched download for " << url << "\n"; - - } else { - // successfully downloaded! - success = true; - break; - } - } - - if (!success) { - return false; - } - - // Since we had to download some of it, might as well ask the core API to - // check all of it. - if (_verify_contents == P3D_VC_none) { - _verify_contents = P3D_VC_normal; - } - return true; -} - -/** - * Reports the available command-line options. - */ -void Panda3D:: -usage() { - cerr - << "\nThis is panda3d version " - << P3D_PLUGIN_MAJOR_VERSION << "." - << P3D_PLUGIN_MINOR_VERSION << "." - << P3D_PLUGIN_SEQUENCE_VERSION; -#ifndef PANDA_OFFICIAL_VERSION - cerr << "c"; -#endif - - cerr - << "\n\nUsage:\n" - << " panda3d [opts] file.p3d [args]\n" - << " panda3d -m [opts] file_a.p3d file_b.p3d [file_c.p3d ...]\n\n" - - << "This program is used to execute a Panda3D application bundle stored\n" - << "in a .p3d file. In the first form, without the -m option, it\n" - << "executes one application; remaining arguments following the\n" - << "application name are passed into the application. In the second\n" - << "form, with the -m option, it can execute multiple applications\n" - << "simultaneously, though in this form arguments cannot be passed into\n" - << "the applications.\n\n" - - << "Options:\n\n" - - << " -m\n" - << " Indicates that multiple application filenames will be passed on\n" - << " the command line. All applications will be run at the same\n" - << " time, but additional arguments may not be passed to any of the\n" - << " applictions.\n\n" - - << " -t token=value\n" - << " Defines a web token or parameter to pass to the application(s).\n" - << " This simulates a entry in an tag.\n\n" - - << " -w [toplevel|embedded|fullscreen|hidden]\n" - << " Specify the type of graphic window to create. If you specify\n" - << " \"embedded\", a new window is created to be the parent.\n\n" - - << " -s width,height\n" - << " Specify the size of the graphic window.\n\n" - - << " -o x,y\n" - << " Specify the position (origin) of the graphic window on the\n" - << " screen, or on the parent window. If you specify -1,-1\n" - << " the default position will be used, and a value of -2,-2\n" - << " means that the window will be centered on the screen.\n\n" - - << " -l log_dirname\n" - << " Specify the full path to the directory in which log files are\n" - << " to be written. If this is not specified, the default is to send\n" - << " the application output to the console.\n\n" - - << " -n\n" - << " Allow a network connect to the Panda3D download server, to check\n" - << " if a new version is available (but only if the current version\n" - << " appears to be out-of-date). The default behavior, if both -n\n" - << " and -f are omitted, is not to contact the server at all, unless\n" - << " the local contents do not exist or cannot be read.\n\n" - - << " -f\n" - << " Force an initial contact of the Panda3D download server, even\n" - << " if the local contents appear to be current. This is mainly\n" - << " useful when testing local republishes.\n\n" - - << " -i\n" - << " Runs the application interactively. This requires that the application\n" - << " was built with -D on the packp3d command line. If so, this option will\n" - << " create an interactive Python prompt after the application has loaded.\n" - << " It will also retain the PYTHONPATH environment variable from the user's\n" - << " environment, allowing Python files on disk to shadow the same-named\n" - << " Python files within the p3d file, for rapid iteration on the Python\n" - << " code.\n\n" - - << " -S\n" - << " Runs the application with security enabled, as if it were embedded in\n" - << " a web page.\n\n" - - << " -u url\n" - - << " Specify the URL of the Panda3D download server. This is the host\n" - << " from which the plugin itself will be downloaded if necessary. The\n" - << " default is \"" << _host_url << "\" .\n\n" - - << " -M super_mirror_url\n" - << " Specifies the \"super mirror\" URL, the special URL that is consulted\n" - << " first before downloading any package file referenced by a p3d file.\n" - << " This is primarily intended to support pre-installing a downloadable\n" - << " Panda3D tree on the local machine, to allow p3d applications to\n" - << " execute without requiring an internet connection.\n\n" - - << " -p platform\n" - << " Specify the platform to masquerade as. The default is \"" - << DTOOL_PLATFORM << "\" .\n\n" - - << " -V\n" - << " Output only the plugin version string and exit immediately.\n\n" - - << " -U\n" - << " Output only the plugin host URL and exit immediately.\n\n" - - << " -P\n" - << " Output only the plugin platform string and exit immediately.\n\n"; -} diff --git a/direct/src/plugin_standalone/panda3d.h b/direct/src/plugin_standalone/panda3d.h deleted file mode 100644 index a9b647fc7d..0000000000 --- a/direct/src/plugin_standalone/panda3d.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file panda3d.h - * @author drose - * @date 2009-06-30 - */ - -#ifndef PANDA3D_H -#define PANDA3D_H - -#include "dtoolbase.h" -#ifdef _WIN32 -#include -#endif - -#include "panda3dBase.h" -#include "p3d_plugin.h" -#include "httpChannel.h" -#include "ramfile.h" -#include "fileSpec.h" -#include "pset.h" -#include "vector_string.h" - -/** - * A standalone program that invokes the Panda3D plugin to launch .p3d files. - */ -class Panda3D : public Panda3DBase { -public: - Panda3D(bool console_environment); - - int run_command_line(int argc, char *argv[]); - -protected: - bool post_arg_processing(); - bool get_plugin(); - bool download_contents_file(const Filename &contents_filename); - bool read_contents_file(const Filename &contents_filename, bool fresh_download); - void find_host(TiXmlElement *xcontents); - void read_xhost(TiXmlElement *xhost); - void add_mirror(std::string mirror_url); - void choose_random_mirrors(vector_string &result, int num_mirrors); - bool get_core_api(); - bool download_core_api(); - - void usage(); - -protected: - std::string _super_mirror_url; - std::string _host_url_prefix; - std::string _download_url_prefix; - std::string _super_mirror_url_prefix; - typedef pvector Mirrors; - Mirrors _mirrors; - - std::string _coreapi_set_ver; - FileSpec _coreapi_dll; -}; - -#include "panda3d.I" - -#endif diff --git a/direct/src/plugin_standalone/panda3d.ico b/direct/src/plugin_standalone/panda3d.ico deleted file mode 100644 index 3a2c1c33d4b3fecfc9b7a8bf0c2230cc3ce774f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147323 zcmeHQ2VB%h7Y}lRr=r-g!jXZ5|zJC3hD>5>2!Pv25Keun+Ue%*V4^{8py;ZnI9?DQh42NKw$HvAETd-h3 zO!MZ=RXca?R6Tq4Ox3n+TUCb+9r)`VJ9em0hB~N=HVn?AM~~*BY~jL%st+GNP?1VC zefo4&v0}yeIAg{PJ`ZK6gSu$L+F!bKDWFfEKC1Wc->a@(y{dZp^r`CM!-uLBD^~E4 z>Z)G6c)^#wefw60x@aSAkG8;BqeczD=W*f(yx7^<@nvVuoYC4IFq$-J!qfBl^Ji7d zmM!CXk!%0@^=p-fhli?o@#1`a&_J?^Z|m;v&hsIppU7)Wd_G1V3$td;QcayYRrT@X zN7a`vUsU)%apFW)%+rrHXuEs&?!%xLuyqZni#BM>+LtI%LgnS<#mh<)9LN!MP?xnQ z{<_YcJ2$pLg9a);Kffpm*e<40TW!ZO|4vq&}IOVsEONlkz-;{SbXo z(C<7^2X)bg>0g{u8SaCH-rn9{5OIw>aXoGS3D+Np+Ug~y9M2hgv~l$K;-5c&rIR5@4O?arxl3@IG{P^(?xL<5+Y*YaO0V-<8-$yfN z&Qz5uRZ8{8AAhK3&z{Zap=|l`<$PVVL0iB8EHNH>j$X$7kM!JTOP3qJ7l?b}!N-+%wbgGXPY=T|&z)JY6{wEz3>zvJPrUAr~` zY^Ct&-sIntXvd=PJw{`W__-NE4FnZUx7DO2L} zCr_Rn-v(__AFu!ueTdrBrM~fSz<>dK8H3MYO`0@GwRrL3co@hB?!dr6)rb)z66l4& z2Q0t@Y{Ij=e*OCK^oZdzJi4R|K6n63z@`{rZ*LzDKR7rz0ZqEVMIH37ty{Oo!vRdd z7Q+Yb)~#Es!otFI1TCy3_bzrjOS9bX3h9=JlD|QOO`CD8Zu;v>hWU?XQTtl zPzQC<25kWwumF= z1q{H#I|;CX1GvOAP&<3fMF5twvoq$1grMTD@xI5m2gAuyd;$N51`%^e2)I^?pS58! z_Vn~bUzQ~S-=3^KQZ_zku$0K3wUL4+MTA^^R+d=&=*!!-VHlM#oIZUz!M7lz+0gt0 zF7E5QckyWZ7HEzs!SjIOMw%G>kX3~W6%y!^!B)$WCjj$;EMJ&{PRw^9=p%o$d;a{n zYRs51@pE(xzBc>=2M$c|?2^MzecFQJqLU|2@_eAKIAETa;l`YVaD0#Nag51XIlghl zf#C-Z-~vuOgQ#9bdTu?zTm|NN0YeHu)#v4a`3p_YIn2%Ads6B-!SDkIZ~-T9Qyhcu zL`J(N{9=BT{%80Z9^eFSiazM0EFWo5P>@paTI&O*5QqA{@R7pL=Fo)SR$38gr~nw4 z;{r@w@w0k(&&laq14=#{eFSZ#-j#qa;NJ;j13cUDY-70bzQ#Kh|685PU?H0D)sM^;o;$`Hf`GQn0#3jN4&WjfRfS^!`j7Eu2P(s0{wT$2bZt#BfW967W9tM`<1yU- z!toaBq7B*t24DduT?2Lpib}_$mC;@}9<5%zx@z6Jb$rA%cxK~G)TLNi$X{ZwK{G{u zJid4DUX_D`L%dFLjXVl?DYZ^4F1hvuKLbTCnp28hvSf)05!WQ!5h#;uYsfOfmz(g- zLBzEoVgF39Fi(NW9yf~d^Az9BP*I^VNJ@bEpE<=g>Ztekwj}T*&LoZM1v<{%To*i(Kl|~h@S_-wK|}ze4-H<7y!|Px!pySeuDkMxN+kWe6wI340$L+ z9d%uPj@Q7XC;~^c@XvgrCmLg0%rRA|QYHTV!^RdYMVY_9KR*se8*1+b7>bY@pfce! zrO3ZCF&-1nV}Vx8+f}YyIi3&98zGPJ!RE2l<9+_!3YZ2UO)Ch(Q=KBl5m-my*Ap0B zNZYk*$FGlIti$rL=7jYXl(9Ud>a_@f!r1EwCDpYOpl1bwU4Y_h!t;g3nEc$AP^MV3 zqqUIuZzwVS)RwnVK^@d(d;kXO0w!Ps2gL$&8V^&o{|Bnif9DGCV~k_BZ{H5O{$G)<&=xQNi}4B^zy+MZP1U+lRAkXc z_3bF0r^wF{!p4EYN7|)Jm-zWJ)L{Yh9hmnQ)@9fDzUkGgSAzKg)(&%VfXV721x~U( zVO4OUlg$Rz^CrH(VvZ2&w!&|>MvWS&4jnqgU?xbh23)63odh%p>0#HXgSt`yuz`cs z1#Zv)T0j%E@z&OLsM^&NCr+r!mMt3(2hYEiD_2U+UkK?KHf&gY8%BdT#eE?c@E!p! zHdl}KpanF6HXZ1{C!Ev3y$AaZUBZzgN3_z9c_Li`Z~`~uA2bpD_mt9)IYeCpWT$Cf z0d!zqTvOkX!U5dLNk3@7dkXVqQW5VvCBe}2hlGTv@Gccb_4l^ybZ*46W7_wrC9-HvCQ& zfRz&T125)kVE3vm;2wuS&5dDgVFz`b#5TAw76kiUY=I!aAC+G5%x0(9a*( zzvB7K)`K+Bpbz~R|6@G@HUcadntlcswy@9zp8ZlhD5W2B_`-b<43AR!sa;tbBSiy0 zqYE%J1=w^5$Jc1X#){%LpielaWbmoa`aO> z)yR<}d0ugEVvSI2*CC`0?=9@tU}JOao58oFrXZvrG_m<3sy`PrgAcmSOxO1@E({0= z_-_72j(*^Ut@7y6qxo?g{_7I(Ju+(4DAm9J{wrHuNIztWZ&J_*T0t{4&P=f;fWTgp z=~S3%qaSUPDv0T4bb(fN0PXg;#&egI3)9p{zu+AK+GXk2repA)Q~|h!vSimv=trMh zvu2IfZ(l?5fH5B4Gr~C-Mmtg^^s{!b!3zxy#eHK)QWL-eY~Wz_ehjxb)rWq-z_Y$* z&z{V#GXd_z{(-G1_A!dzCt}+1Ur0akoS))n*x3E~=bw`OO$-C`Wv~m?bzVY_H|$3N zEa4oS7@zPz_LqQG&{%04<=2^4^0+idh-m;*`pMr+OPHKNn+>qk0kDC?95{hnoe!G{(Db{Q zUQPe0F5YcDDJEE_qW`88I}^P7m?MVGo}Fl38vA*K-@>>?p0JN&E(>kd^UN3vbOvl8 zJ@h{hMbJ<~m~V({f{C%mc;Z8HT>y5#%nm|m6D%>$KOV3QL6bf(2zLRB@#`{}!xgT} zu>OTSe7h&rI*UHE3)>J6)kzopL>6p`U~|K0$2Ia0)OC_AXp-)Qmwx@WPA|GH!DD=(1_|=r6 zF6Ji$0kGQZLrZeDAsVYvJkIDA?tc*SDz)Ay^=*moGr$l8z)r9aBsuxhgo|k6zm+NF z=VoC4#`XgX`NlQoDX|VK&OdeP6kjIJXZwK#_ISX7?{a>QP7_VZkxw*WAKoO2?}#Se zUm4cIg?5mPAGNOxR8!r)efvB9)oW0^&56`JF<=5V?GNH%0H+$a-nNkX%7_R^N3lEM z=beU7%J27;veSc&B=)jlev$<_{!s^Y(T434VlqSu9I&GVP6Ra#SlmvhFF#7!5gvQO z`44a-z!p+!ep_na)wdS%`e${J3ioLVWq@no6xd-x4xq_i2`@_O66_Kb;|&lnrwf}9 z;e0WpanPVavg@_5V`Oz%3Y}^SSo;M`R+pu~4H}rADYPd!Y@(#N65izM60B?lb0($y zOBp)ByfyU8=wK=Q6k?8EQ@~n#w{G3OYscEdcN69jH3jHf=nIjx11+Elw5bF3LV)IM za=givQCobY^riR$FfpGDe^r|9N$mHhx~TeHz?|KxRjV}a&1QTctyr-l?~_6kEaU^1 zre_WI7=l&=&`uGH%8I_Ns12U$5j+t3fgPYO&tz6#oJ!dj3VD{g7Td;)Vd6cY>0JX_ zg|>^}1w6^=TUbVQy8s{T5%9hi)5qS)%#VneHt~O~M~Go)`_J~_i(!fXg9f>=26#XK zPeLB$uBo~Y+F;*-m`;qz;6qJGfbE}feNYTj{2%uKd(Z2NN7GnSy>A*|eB^i*mZ2^h z2>Hi-ul7-cBE&6R-zC6Tjko_~uAV5c+mVE&St~ zwrkg}yo~_t1T;nXwWNDBG3+PsZIN2|PZUE68z-0k@m`bCBlIjcj#0=C|2=?byc90v zi9>Sn58UE=m;HzTCOMmLG0k%SVMoZ|N~PkqseymciG5|7Y{tbjYx)mc0V$q^dE&OI zg@4efZ5$`2UHBjKBvNxlLf&yL4ylQM(1)?V(g3>zX3s0;SNvZLJGJqTxxK@O4~xmv z_#fYi+HC2CG7tkwZTy2)%wNgbU@;zG4+h&XA%EJgSzDH-M*hJAd<)6F7cuW8^kuD$ zZ&uFuW@&2WAN0bfqNV^JX^bZ&sTf{r=3g)#6_d^TdQ`$Ut1AYST>NXA`($)UrH14m zwy#3}_)HGT#Xs=jTLnGn9*X{u0j=%zwg`8@yvIC^v2pLlg23 z9>9yBJ$PINo|zoz|5m`joFn`KORZlj;UBQD{{sC0{!sM|&^NySH2GH61XsvE>wn-0 zyb0!2w=(`o7Vs-0`wUmgzb4v}BVUStCI`Hy5Wq9zpU3h`ODy?L<$-~E2CQ~WppXgKj6R@MPk-K7~Z5x#ePnuct;)!O8IB-^jQOA zIFlm9dK_qC^l3{O4f^sA_?VZ2e>H7mQHCoiQrJX+23_U|g)(8ZB!+(m5AW4Qix%m% z*OAeoG{v_Da7v9+7+rEH!^ilici}DM!Eb_a-=!Q3aT$E?;f&6t3`8f7L+IyEOo!Zm z@CF_cz_Wn=E|kUFw_smA&hirODHOwmeF63zO8LovFGZ#Ps6dal0GROWAf|=+0F|=O zV0FO@coO&wfPG8?djP@@`=;%Tj=SU+Mr`}Q_PjIu64(|<`B%XGh%vVz_V@z^U`gHM zz|HI%Koj=ki}%KZ2k;^Y;IRbLy*Q<^1|*w!0|%T_gY!SJ)+abC5c0dpU}C+RomawS zjubWzbl#|N%*~o;O)*YKTPeE<;1aHpt7+l;FK7gjeZ&x^qgY;)mxUtsm-8RzZ{EC-JU;;a0k&&`J=N4KVL+Lb zeH+dqfDa(RMj%`tC{CeEI(a%_pgc#4N7Xcg_Us93B+Wm-@U)Ut1x0tTllOXSw03Vz)T!f$={l2PhcMpdkCCGB{fHk zJmL9})HcQJ+YK!#(p>?H>xd`bunF(QGpVHio7nrQs1zHHo)V zl=1=d-OT?0GSp=?Q<~1C#7}IR5TEcXgLf()aE(0rBRfBzlyoIGY~nQ|@!S>>*U63F zh|eeiqXdi+fS(9AilG#lp9r6M^v4*C5->`@C;_7c^p*gP?W}2RH;qzu?m4cl^#*8c zsFMUp=J5GAh-8hqg9JgHH;6Jd`dZWpiLsKT1W2yVB;&9ILYMfXuH!5T#F(jA0wiMi zIXom5^`%Rf_;nntgWy^m)NN9w-$TVhNahA4OV~;lqPT?Q7{B=(GKRew)(C~?apM|! z0$Vgx#k>#NE};lmKg}FSV$?-4%S3Sm#b+e5_<*%>_z;pi?+9h6gSx^1SQLj-o^d`# zgK|hV<`iKJ97!=gVDAR(ZWmK11loSMcQo;Y@nk)UXDIS}F(~B&_JzRyOUe#PC^z_zfIaBh zvu8ER7yhJB2X%#Q#n-?EoDx2rKpSYZr}#sRSBZ~G6tNE^f!yJz6u!6Q9L?9ahD zp)6>VKdXl}u=xQDvHaP8;06t#MHE0QXs(okkBda1re{0m$mUS`&A3U;Aok6`=BZMp zN*d(?nZXux{rdIa`I^vG{y+!2D!>3NIX!?D&?Mf|qoy4^q?x%rVmm#>p+xfo$bbcA zN6GeHu|6nHVV4M>Yhqb2I7;Nt+5i?{O4&RL@k39r<7IZJti76-q4Zyozq3SjV1J&z?(D0 zRHFx?1vY6FDej}l+sabPfAd_wex3K#B4y9b*!SpvDkPi8 z;MSnHABZT857<8g-?MV^K^gY>!VaJ9F^C7C;R5{^``dNt^J4k4|G3ZK7eSZz3djI$ zpb@lc;|I?{@qQ$=Z1xi-(Tu% zW1(EI7P55d()hh4pi9?)=e;52kG*rk=Y_6x;Qa(1W!6f|BVB7T z!CS^);_L=(>mV4nO_(qt-tL{XRhnWQOQ_GpT*EJUVglyF!IRuL8uUq=Z?R0PfVEU0 zx_L_rpG(mom4|OF@z_xjA%e;`Zro78m%5xDM1Dg< zwTM@1F`<{0KgJr^w}^9q^|{9d?0t9HxpU`4-vhmS_x=uUVlu!Zcm>Z=bBD<-|K-b< zYxI|u7(US!XH`h`X8RU=ili(v;pC~$G%HXQ_8RTzpp&1Zh zYL-8~`7z(FEsAXh4JaP1px~2O8+|Aj_!mh4Gd0T}bZdGp3-dAGrPL2!0wL)62jiDk zty<|sqbA>?KZ5+B3;6%QI!AH^*q&e=OxO?Pu77m-gLlm9Cdab~&&6rerpeB4igocb z$R9l8d)Lt4(BgXvzLd1h+5W8Z2j7^_O)4E=OZB|C!_uo-t<$8%;w6%pYsBEoHKnN`E%_GaU$h!Rf0Dtb4h*xad6AG0Ok{ zeyeb|?IJBidv-}|&_#l?B z*OwE&YQ>5bdX06Ybn&yxA2LyL-WqI3wApw{$yrmLQU1mFb1!5&yr6LN=FN$I<_mRU zl)q8_=w4V`6ZQ*SV-8R%z<)c||HSq6{V!VAlR_DvXUP5!AF5b~mI|qP{uA`Vh6K-T zDL=4E^^n~1$G8c0TkvzM>03Ot%b)d`d-v|~eu$OMdkJ-vobtz*7xu)O$z7MhWnM51f~-Y5rW_=MP{b zfL5GIAe24!yy2Pf;>C+^l@jrbG0et|8^5!g$Cx;=b{A6e2Op3XWCqy@gIcz2C@;aj z4E(2vecqp0eb9~lHP~k(_l!ua{DJSzojd#)+8Ce0z8gLqh!#eQLDJ~xXnv0b>`B27 z=I0U{G|3-201mcCNjQ#G%Xkjqj@JQQm!=rMcNesx|H6a?$|Im$5{`$#TQ!AtVHAyCU z@>7HSF;Doj2Jo)!nJ+9)isujWwU8J)k+i12YuB#v{w1XLKMLh7zD^4HGaT^KFlEY= z@BD10HQCD13m>B3QD2`FNhyD(2dp`+UAs2PY-r`=lT>AxrvgujT~AF8`7=E z;J|?-|DH`MnFB87Z@>e1VSFVfO-}iPPBx!|eTc$2kffBEAz*`6(2TwFiCHrh>ngeB z&+x-1?fCKI6Zi))gq)HB27H)+R&9QC8E;BbP4cI?2%J^O2l$xi+O?}e>?Xyu;hc6Q z>#K~W#~Ko33fZy%nG5D03ef-f2|BFN!f!&OMve5+gWR|bv@~wq zn4jxRs(mhuM_p3zdhp;uo+i+yN!D^aX=(#_4I4J(WeGeisAV004lU*5?9wh26Zq4E z?}SB*7U{fBi)SU)v)~^@&QCVzMP2xJgnze`3cw8-v_0d&3wQ!=+Uhc0U=0bf6Z@Zl zj3H~tob`W}Qht8Q$C)edgfhXncjU;CvUXHmx^zi!<}Ti07(1Y^Gn%AQ@Pqkr>=#b1 z09?SSO_rctJch%$!r)bk7vy1G4YHCrZvZldY-RmbQXTkHtwHsUQ2fkf0(ru&SZKe) z?yqgzwyA{o7i)tQd(4+DTc*->MmY8WqraejQU$;U4&c%xKjec}(5#6T@Cu$C9UbGJ z&sgt*Y{WhWAw$TLc!K{zo&B{^T{DX9sqH;V;{$L92M6~n{B`w--s@- zw-;v=X|qYdSR3;y)Lz&;QP+S4nA*nipiRR$N{}IVdMhLZyh8?n3z>-fAl1J|_1jZ4 zW6v0+DZ$7@?Y${|PN~K~grDwG=LV7zuf=S zG`kR}1bvtO!&U*j9#!*Bm)`>Yhiu^Nuc#(DCN`g7*P*zcaNVJFH$~iE8tq!tddNa` z22hNp7#}d^UbSkK*7auQuNXcvv<1{zvSf)?f5KRg1#Ssj&luvZKjFzDCo3w4FJSP# zo9f@D2qX16a&1z&jA+bFG|r_o!Alml0h1<8(mKwqSFfIG`}XaUb9?xfKpE=Dy<0IZ zgsrE@9s%zg&;;6Yr?i}s5j@bOQY z2Uvi~;2TrjBtWvmS-|cT@00xE1IGB+6N8)|sBTpMc(q85RuuoD znBd(2zvg1!=BT5tYxUzvB4s(E8=x4;7T=li-wp9M1?8#Bilr=-KQ?xfH_mIWPw@oF z`xPRtDdHJ#98V^b`bpOKjxMZ@Kh1Y*GKtrS#wY=!1dI|eO28-qqXdi+NHPhOB*;F1 zPO~E>Tp?U>Tn6J*$u~h5e~l6_O28-qqXdi+FiPNOlK{-`QEJ^H7%SXOqj1&M)aaJ?YhxV*Fkp%99MJgSu4s)7lRGNd1BI*qrov zLsHo?nd&ypeT*ct(?+;O|w+x3!$^g=J_97@7k0gHu#i>qnDoYUhV!UWjDBR+C;}ACJA-a(h9A zdX~Ee48RiG+zWB5X(^Q2<(AgzBRS_Fxlg4ufxRr#1$=HVSg=6Ro(ehL3(K(g0?1l+T~5igQMUI!lUc?0tfd0^pPiY8rcj=F}#~ zv`7!hu>r|6OiI?s!#PS~Kl@3ccQH)h1a3`1O>={^DD%`nGs(3$$#AD8`NBu+z<~p0 z_ic%Frfokd>MQX9iTz2S0kmieY95NG2AQS>8c2>gDb6CfNjfFKnJzPC%#ih2B-T65 z?3^%R0`HeVTqgd1^ypE(u99;;(XT+0rt@ahyvzb`X+Z}mK_khAt+b@5u3&Fk z_3G6Xz2mVr|L)zpJiLAT_GxX)e955=+KT&!+<(vp8bPa6pnd?}JSZmcr;-x#PE9yT z9Nh~F7x)H1J7G|wf7T8#nl^2!s2@n-X7G?wKfrp_PrtTAGLT)P(dQn- zH-M&dP4&?~^o9Eweu|ZTUkIN)fFlmn53oM<)2%HL-&)sb;5SE`A3xze51&%AX3dg4 z(@bCeGri%wG~m$X{3J#jcmOYAe{u{a$>OJ3TOytly+*_2DolqA8KT13fZ9T0_0Qk~ z7jOz`&~^>KSnz}Uv#u?X>{?M@H`p2tZJFROlIO#pEVksFNrxgrNPkpXZS%2XcFpK+qDjBOORRh)HF_4LJQGefFgV* zN(Oz_XyC69bMO+r1toEaGjTq%HoaWBbV=Myr~jY{w1Gx#I9RzZYfFS2GK}}BtwaYY zQJ3y@gRjwGo^AB#(ck%A)=4o`iD*)-UcFkUb)lLyYpQndhWkzZ0{laRR?y7!tS!}H zZ7Gg;m;~9TgidwANz&4~MuYoLsoyy_H#Zf0`|2BT25h@_?R3@!(-qF>5c~R8LIY@4 zYI^|LKt|}VQi1ZZ{*~(1mWU?VH5!bQTDNYkNC!&K1{ccKA!H*eldfJ4b2W_zg3KfVw*-XGe&YpEY#eJt76mI!B(t`j!*yTSC6|S)=*uufH_zvk}79=X(0|=}Gr({s#sIDx$>@ zm33KLlE9Oq`X4-au-5I=m)twr{)HLc}nH<-xTc?7|3=wzj+NBJ664W;8KM91IhCmwipN5o`1f>3G`ag5# zjN)hW`t|FRK(dAfiTOc&-Z|Q+_|fz)$B*3j3};KH)_^&DM@L7!zCE<@BquM4wyFO6 zPmUis{ljMV@ZrM}ET?Q1z7INd=%APG!LPO;CohS%Kdk;CE1Y$nSQ`upndzN{_28jH zhw80+qyCF2mL1m16Jsl;x3VP~%H5lC&oW_|1lR;waySxH{PyREzWS#Qurq*4FU&j{GTB*s2lo80Bf&z?Q2$d;4!Td7nI56X=Cm)1XIIdS4d zZQ?U{Iqcr5R;{Y|y(Oi4Y^g^BsjGwT0aPnYY@nq(xGU$SJ$Wce;k z?023f9*psQ<+4AM%8co}~INH1spesDH!g zTqs9e!{*e`--WQlOA5O(M!WI;H*8S8uf2j{X@Qn_%6hHo*}>U z#Cm7{jrupd{vlh~0_q!*;yaJ&Tbyd6QEu!Z(e|g9{}szn>OZ~<^$qjq&rg!Ez7(C> zXf*0y|L21?*=j16lev@*6O*Tj29_^J3#%hYjrTu2`&~kw~xO^4Rs$$!O=#GrgFJ^P704cdCd2lCK_12 z94)MlAWil6Kcf}r>?!q+rBu!gm(o;D=1OT0*N0!|F=NK4uvbNwAV-Tt`!u6}&<evhQpO`RJ4-Cv&krmHhA7v#0Et!&1b_(IQblP3fP}5C7`ZrcFzf&ps(VF!)MS zIhjl0(UymKX?^`2$e$R3*pOM!>5lS)}rKSk>Klx&_DQs|6cfEm6NfyG70(U zlqDx~Z8%Ym@tvW994!(!461*EpN?!FzH@+}Nd}a*a{ee03g6D*QUq(_-_ZI8Zuni(gik8Ja^=d2_9G0u*RNk! zb?MSY5pMX9kBW*ybAtsX`Ug_A&h+*XO(2R=+zwb$0rsy_az|cL=pSqO_-@jKljXDX zmJIEyCp0uv)wpqEt@z<5NbX!%DOu{0C#QetLMA|mMRlF zvOboRLjRxzxN&|C)3rE-j~*?ukYY*ayf0tAsNe%k?hMMrtT)RMBBy`!dFTZ4kqXeI zTBow-M^M`~R8Mk33ils)*Tohhsq_!ta6TvY{|R;P;^Lw@efqQ%>q(NQ=?vQ8!-ppc zJ^+=|Ka&M?1089yds6GRjnuP%P?V$c4^j*$_3fOL`UidR$Aa-7zN@!x-D*&Oyi)vY z%46riffn>Z_@7Uzpo{)lKae|rRITH3;yyt6i^Q}?MnDv1L^;=Q2$h>^V+U1{lKVyp|lNit*`!>z9guKpCdBrUqU*mEX%0>RHl$*Cda7% zWEOZTLub@~DpN=@lVj9>G7CJFp-W5pcXf45^6%kPrk*4v2lGsjDI3e{lS&YnWaEF( zhdJ8WvuCH+IS>;3rn#)wuV3>r6wi031^qJ`Q|cU;G^cD4!MdFL!ep#VDguwcNqYZ_ zX-e*Mpd|QB6In{meG7D~>2)TeJq2r$L;&**1%(Gs-%6j?z*LHrsvlSfjf5&}(e{WE^y z$Mv6o{*fT@$IJq+;FCv8jYi&%!j!{Ga{bm0N-!K6GRTF7H^UF&nUvo5mIrB0bLWmM3mFo@Ux)%yR={^$Pv`+C{` z=t7saI_!*iqE$$Gn!1J^o<3*0Ym<$x<*@&O4#k0F`knm`)zN7G2ir>6l!ojP?&Qe>oi7%6^d|A%J)<;&XtV!T?dS~W#H zF&berjrQ23C*(8}v!AyN@CLxP0Tek4BfsEwr%b7f-Qs@Tl^|Akj z{t>8u!2W+aMUD3VQ>RYV*)|aNXQ(f>O@I6LEkCziwrp9Q`vL00mhI)smno=WY1E(z zv?=8WYb20`FhEv@kTHV^U8;2|YybbP2YmabwneDTHU>kSVxI-hUXbdCEDz;U_NPKv zY~D-B{yy9rC(cf5JXOIMPw5W zcI;4L%}~gzw(A}}dL-$-FEOpS-+)saUBYrZJ3F2?;#~}m{|}j{Wg{!&h7B9?vX+xE z0qjH3Ap3uX{ebAh*kC5bcaltK$V7dL*i*>Ae<-z}h<*?!)dc<$VDF-2JY2eTY1M=Y z6OzpLJLrU8dEfvpp>E}_!2@{Fv{wZ(P|LysvZiac|56_rLpM6Va-b-_h#t5f}xVi@fI#fukJ?b@}|S@zHa ze9FOZL}CMADD_VVT0yg>pysu@j^N-g5W{Mkm&}3 zah>8Oy6%a5rLaoC7B?V64mI^l7BRrl`Q`3N85G668k{w#9)(fB0Y zHKzMkcA`c~_v$u{e>8dgjQo&(O(}YiP9<$Cg!)(4@j#oOQC2@P&!p3w6#YoY-#HFd z=gmT$A6W)Q-grCrQl#fO6wj+8u1gtZW0ZhV0!9fKC18|*Q36H@7$snofKdWQ2^b|{ zlz>qJMhO@tV3fd*CIR0TP7N(GTEi~gqH&}8e{vk$0-10b%qZzJB&Zk1<(<^He%)4H z%U=2qYS!u0zLUt7ll%@sI3DC5aVHLK1X*x+VJ_4PN3 zFU;Q5$-PCB3={g@DBi}}vUR5I$A7Q!`}!*ns&ARRs@s_=emPuxyPeuJaF@-=s_lLc z_bR-$OxSIeO^=|X_>@(Hyh0(Fu9CC7zuH2nQPSt!y51YNv@hqGDQh!Ia?7k~@@3x{d%BI!- zy^>>vU)=Ubds+T%#qBK^Iyj;~?IUY2bZF%XM+#M{RB4W%-*~qQ({}H!dOj@dT%IF? zx%ba!Wi4Fl*X)C04rYv;(r9?O^5u)<%d&dKipYDuhg~L5o}6Lov39PmR#nF5-Prw6 z-pP~pruVVt#^w0u?EU*)=Pg`#uVQSq4F?Y7J9g~YD!VKjyZ=}I&fp@)uW_f%J)CSZ zU3>R&c#d(az3SLcGh5*nP<{g;|M%Zs=Pz71o5v)~JVRr%qVGSF*OI8GPwTq6F86#e zsFka0fl;GI1@GKhv~Rjv1q(fLvL6yK?%j*_^A;=!S^gn!>kb{J@8}&iJxh*_LpMd_ zALQ^C7wXjLMI5;wacS9dbuFT1?OHQ(d{xQOBTJ~$o!AofGjRoe@n~W*ns&B_U%x)h zzEI@I*IP?jW>~RpTQ;(?q>33sCx!%=7hcXq4&+{PlkSGJ@6@S&+qSuf3>~_w*jLBL z|Ngsb|Nf5udb^FSQhdbov2`YuG!5Osm7CG)%;L(uTm1Rws@nHo70rFYyqu|5oA*P1 zKi-;am2PjLCAmW0eOxu^BAB%ny) zS)r;|ajH_=pEbYzWX2!Ws^#w7xpTWtopM$&S)SEW#rcl;diHEaGjsFWH=bO(a;2-g zdj>jWIB4U>mS5v&mv)8f)u+v$pUb64)|+$viF5PjWP@Tt`$?MQC|{z4`Kej?o7P<3 z{nV_&B}z1W+OAUN$`Rq=KI_+)iU>CGU1YcB^T)Y1=|gLCcR7!aJ>H(|R?*YbvyiQA z$B%>VT)o<+nUmAa0=FJLD%zoA$N95M+uG*MpFjV!6Wx9<{7d$2<4i+qhg>slT!cHo zxjFPWaq{8d%$YN<2nuR6a>A8s*B*ZP7`N)ocBxxtf=M z<;q97<}P}o?y88B4OeY^b1bV}{noALzn*k+TX*xL_k*J<9CoOl@8qofw)19>4qIM( z`xDdtJsfVE|2?znftycq=ghfc$Bvf8$M0T4N#pggqxN~$33V(!_LtCWTuxK>Up%Zs z8*}B;mAq_IV7+5r*XX!gH*Z#`UAydDo85bdzg*Jgf;qP$(-Qj4`TMrv&cD0FyvgpP zx?IufVciGzn@gWL_U28fxxH!j=9Th4d|O9Ve%!|yrz-?TehgjP@8pFeF&TaKgibv7 zi^td%Yu}7_7!qJtsnUaUbaT7h}t25@zmpy=K({jf&rVHtzY&Ooiv% ze$sHY%Or=wk9}8+3Mk*Cckd?)0`iS$y0S%vh@e*HHf_Vq=XjYk8=ik%*pXt{%U{@g zV_%zRlP#$OJbCgY;_ls9n>LksJmcO*!gJ};CHH>)S{9f}Sv&XaIajrkUtiCRXL5&D zy+3Bn>lw}Gcn>cAtHTr1IqpIGuDY)d4sP*rf}KYsSI+f7RIdZ`hQvN-kgvLj{m4$8 z+w#zoG};@9aC+bHs?%d-t{* zdHdbVTO~%<3GP!QN1olYW}5%~d9}OE^f8~`?He2!clTMlHP!>@$+dddt}F8$^PcgH z3NL*ApMTDrztQO5fB*HMe~)8_KJ|{Qp1q&rsQgnM3fFpnd+3%;-S3R_&snt2q`^6T z!mkyqYTIJy{qbY7oSCx3^<~_tlPBvxiOPHOUfy??s}M~!E>){zPBsI9VoI{&Fc#-i^V7AaCB zXw#;h|Jir;D%_*#-mv#pTQ8V*a`y}==G287{rXIap4YbBjWgl8OwIJUNQC*bqaQ;T zdhA%)t5V>zI$d(2ZePz&#WJ@$b$4v_Tz}6jJMd1(2)y*AO9gF?<*m}CPHdvNsNPjCA81qT*e=Nxd7{?50{?dMp$_?Cymf@&1>>0#P*YsMZgmS^?4 z;=X$4&YTAi9$eM6>F80TN7t_CzJF%3W*tv;jC6X~x>42OWlNSEjSI8eTFdSEt}Eun z4)oobEyFJ!k4|SJ&u`Q09MW;L8#UCgNW)qqdyVMZEXY;%1!q^eU2QTlzY&OwYhWT$U*;HzJ9qHkaf}SS?ND! zc2Ze$9tC}z{l6A1Z#SuHTiW&J^(FSyeATjDj(O{srDx%X8)0MDei>Qk>xYM@!@{l| z8hfqi$T~5ld_FJB6Z-2qyRM#|Iroovb+tgrt#1#$8Z+n;n$f+tXzjY?qnf-qw!XxR z;wn?8udO?OE^?>CttYDIT~yge<~g4JK+S>`nrAQQG$wSGNvj(chob-UD>pb`kQLu{ zSDcCY)PK$#uJub~OdHjNg%)L+=Xn3I*TdGUTV8s!BKBEVTeIND>DT0@{7e4UeY01N z-4L<9&xS2qoUE4k^*E#2)k8HQy78z|`z@;YF7}Fux@>bJvY!o?cgW2aa~Juxo$1uv z&%&MS*m(EK;uUjjwO$;xfc`E$Gmj^}N~M)1AL_5Idb3d9k8ih*^Z)yaY1I`bo7U5f z5rqotz3RA`T66C|_NcwyvyR)uH&wXkxHE0m9R28HaWRbB8&<+8WT=by4xbmV$%@~;at9HGpkNp=ym1vB(pj7 zpI$^;U&0-8*u*2ix!KV*aVB{`Tm$^#-GS>%KkoLE9G4a^UAo#N=mS>jrT(_DvE$l;Tf7oD>&#CH>5%+Hq+=e0Wt0pE<1$*!aA7(H}1`s~I=)yUx#V>J@rs(z>;4V`g;uGQrGk z?v^d(=n4GgzgOd~)y}z^23Q#;I~-C)&S-1aqDzXZCYzQ}KU2LveLBO2 z4I4;l6>8P`i-tOX{gwHbiFIwNRqH-{c$@dZJ1g1R&Y%ZX`4f+C?;9F2wb);MO@lUU zIC}c@f>WL&9!%Q&s7n=}&z$$OHzkhqZ^n|g1!H!Y&@1(KJ3CeBp=ZyXtLN;Tb-{uK zo>?PWQWAdY(nRtJv-NmUJG+9a52x%rv$|wxZ5F&cZ1$;#zaRUQGjz;u3%4u33{Ur= z*`swQx>d|q$2$)_P{@EhQ>IMU_YHlrU})*GWlyYcxz5|R;eK+H=H}sH>0B%J_<~q^ zmK{HObVBs~nkNUCo<4i_=>20;{a?gYd;Ob_|E#~q`TtrgL*%?D=UI-cNhEy+aZVka z+qP}n-P5zx`#JL~)U5d|%6i|*m380G$^USz3CXbjYL~_Lm!*qY(c<->*VjVRN4V@A zRwuHdY1GS?!)k?{Ki|y8#%5Z+*Llud+1M5X4$3*TjS8>S_HMYhE0_KAmn!A#-|QKi zy@;1pXivXvCms%d^Zq@(t11l09C>tdCRLr=*3}og;g+Pq&HewlAsy3y@tk$uycH`~UOns( zjc(oh_pe{bGN#8}qW`(~-23BAnsGsw{9i3i7g>NC#O?L(Z?)c?D>&wj-}6^>inbg$ zu-skmxaMW!#yp%^ZO+oA&!2kl*uFg`_Ef=si?`;_X&pMC=#b|H?u=ZXv*-o$-9@it zjyyRtZ-+mMrXM?T@02b3ta9b*I%-shbIazg4CmgwjPp;|prBR7D;)LJn280y*mrbT zv($t<*+f2F7f|)}+dh-cg5OT9)hu0~UL5&d>@c@*ev3jyikNOa^l8I_k%Q7(gf=N} zT7B??N$=`6YHLa!4nyfZyt!xe2)Z=`r<&CNJ=^80SNl5qcvkbFTkXZIJz4!4)o+@) zs)K3ppSQSycMp6F{4}iP8q+&NUCXyTwAG%nFF`vISFSw%xGT3s=wce-)1S#FPBbW6 zaivMS^*y;*uY4t(m)CFH*!SIu=BB}0|NcAsm-|`A%_+4h8?eqY@rqqs+1jVWz7`#x zXR!8pJkFG!3N#qMbjYg@7hNi6#*sr>G%^jQ2VY*h7Een&wST|N|Lly34pi07w4H6_ ztrw>A$NFXQ3~S$tw(>?rN4NP_zdP5jV35s!KC{hMIMQB$Jo)l@4(lAjl^K^O^z`Xz zf6pEs&V5-&@2j)B0ITOAlf54UyYajY@3^u>qnh-XKId&3elWaMBlD0a{k!Gs!&zB` z&d#)O@EVi7X71dfj(h(qVi8)!-ZbXU(VkSg#l+g@l~uWijZ8f(!a46f9=|oT_UY$i z7P)`&x#}0WPNp`T^R6+Uhqrz3U|z!lBkO;@eP=-#8*YYKWFUP^*7*==ijtKp3wN<{ zil9NXwNLM7uU?HPR(uuRm;Gj&ScFy}T=h3^-n`{_y#?1?M>ii`#+@@GtV3SjJA7}^ z@cZY^ox6T`+~IeN!nw>QHeBG%UHx)fSy^@Ro!pVe5-YZE|8sPIYQb6iRLYe*_rp(b zpKm#SWWbg#hi5%_(CuZ#RVMCcHe9irhsM}$>9p@blgzCKKR%nQyPdz2X-tN2u2b6z zd5(vN&nX?(c4oj<^PZ$$8!p$yF?XKiJnWkFEcFq0Zs7B`*Sd`8dDr#Q?c1Ab54WM$ zl3C=EW+Bl-rx#>R_RtW$=j~wuEs3>6;Z>cg#{mkl8z9zA;GKD#WvUF}UR7X)niyzIf$=XKk=lSb?v$L=TSPp?hf9?q4q z_6c$w{jy5ie|y(F{OQWpou`(Vt+1q*?76UOW1K2}9M!_g+NXi3$A%IC-WT6fR{M7C z>>D(g{Og)K;T89tJwiH2``@cH7wA0-}5@_ylJ@U*jdfw@Ofte?Wr1C@ak5F zqlY%Bp6}|{X6{@$6YJ0geFqL4-m}2^DZi?z3T@M59YI;-QM+U&i_ldjw;R(-yU&O_ zPv*5Nv-YhT&h=(by-Ak-tc~O2M~~M0NA#5Ia%j_Ib)|OYUElkzekk~N=KkBaEBJmC zT-^2jzKILJwU4v#v1|>AaE-e_PCjeOqp#Ut%nbHP5My zY2-1(Y{m54u3mLV|6StJpmCo&-syTVBUlZJq_OR(J%`?wefjJ1X7mjcQZFzUNN90n z|EohAYwvsc>|$WkkYj-s-!h%YzRvN|cRe!Z_5*T5`zZM~^kx(*!Z z^lALZ$#?dT=;!RduCKd$c>bzkiAmj2a-l3PxY<&J{<>KOZG2qUq=bQKJEU_c#?#L(k@7!Kd%kj5RF;6}oep?qGtZLGqjnn_SYCJO z*fHwjC1GCbssRGwN>f7;oOT2D^_rW4t-qv zrrx!gFOK~EYm>=Cm(XNFsaGy;rm8$XJ!vAVY!~ym2hO)>M&ixexBIqdI8eO6?1#7R zeck=;mj$gyj@%dBBIBiRGZs0zc{UzV$JQ)#(C#G>uU}U>dcQ)(Oqu4J@7=QH!iaxr z)cF!q@8y~23%-BICT`DvaUVOj0BzBvLCl{8 zViqj0B6qco%3GGV9JBIx{exdWJr6n7XNIruuRC|{EIGSjn>JS8h7f~BxQ9hu=zWUw zI^8&Cbwo*rm2+N4nx`|#S7XTWsB#DC!v)_O%l8g^y6sef%Ac-8PM(~e%6=JdZ$Gk( z!%E9l5kZ#<*I8p5Fq!kX`LtO>N5>YeTL*rrOA}eE_UyU#G^Q5Kq zVD&LKw>g&zq%qd$qam9=eHwMA>wnqV$6eU|pr8zne;vd(|uTX z`bGC`d1}_IImh3B^Ow4dTe-iv6!5hbfhgP3HRIo{=4jjI*6soIs^_!%&mzitV9poU zU3&E@Zf$K{p-Povm2bZ{@oqWdZb%lNKe&Rvjy>svjC>iKEx4-GWXHB!UEjX#V*2_0 zt5a{EUmG?xV%G%!9`u=XGAb(Qd<(mDEdp(w=bJ{R=N#S-CP!%WV#Le&wRztrDezGcZsKuU4!=u-fSnic>;>3xS3T|4=#Y~7k@Fpksp7Syd9pE>u zY`Jo)Hf}sO*KTg}k~SeD9~+~ z9Xe#s|BMDbkp=F246-PCH@BCw&4g-$?$#eVbVrGR^OaVHM>&uCG`GZ_B2I7byc*l~ z&60Cf=thaSdUdV$mLqPKbo9a^fB*TvMUReo{@~4bxyYy>T)7I9dMT-^QhtxB?^$v0?{v2`W zw@g00O*&c4jE;#3E-~5BcK8eX>iHJ5&v0>>?T9S*K3*8HvzRLS&i>dlB?8=M)>Ti9 zh3z_Upwm0ssS8bNZL~e?ZQ`@vWM{p|V!wypa#&40XqnwO*Ir#4Wt(v#{Nlw2XZmgG zclMuuPT+Cn`trAS!9z>@>(}nwi02nd-!qA<%dMMKB*1a9W5ID>wv`CnNYw2e^>)MV zk=C7pcl@@Fs}*EB+dHd|KX<{m&ScM0HX&m^SDjU$_J&9HZ|HtGMxQGU%f_Yib_w3G zJS+F&vVXNw=KRF+m_MHW>F)XTVli*k=X)c1mZN#e>RvI0>U@4tc|crj-6I#Q$E6Q$ zIAZx48=8anu=JVJU|rLdcs7iEv$|m8u=^tpfA(JxYkH{Eb(8Gg zm^+>&ZAQhO$Q^iU%fqm-1#`XNe5-hEjrMNTk*k&2%6h=`dznM0rnk-d+*Q>hS8#Y# z=?`bPcER;JnUt~lRBdbpZfnNjG~3!Pcy2kL$&TFls>t{@d@L5Xp;D&dUosZWH1pdW zbJUqTJEqgjmqqBt3I6tld`_NpJb(WD>C6k$+pg!R*2!;^)!q>yo!xsZG4X02Jd_3v zi&t)UE0Jq_kChQOcJv<8+P%kglVG>0c}y<`g*Vz`Lb@qHetXY8JU$`+gFGLC!h?40 z%0*A!S*L=|arCUY=oHeg+mS4OW_3#0;BBz2`>A|0|LJGiuJrZT2QQoC&N%$S`1H0t zEIzCWr%$`{!&mw(G>cq4!T+#HP{hHz)5aHaaewoNPu|~4pWEqBqA4>WV6Sv%999Pg7JKvNO`-DToky<<*?jb< z!<%>S&U#+#c_d4$`J6H~OZ@%cZhE+_?>4uoYs$tnUg`G-U0I&9o9sByH@)qo{#>0u zY_b#942{!yw{q{%wp^|k`OG~IM?a}ItpxFIQ*=pLS1ao~jVV8~$@MLtM_R5*&yAiF z^+)MRZ6`bCef;N<3oSz)I#0`Hzv|((g_9kLtoqp+dDg1BJ$xF$_xdICA2uZa!b^Pq zbtq!>!m=9|vzIT)V^*uAjr!A_&{xb=vZPH$vx)8l2cCTKVpEh|CK8k7E1w=KU5aL} zJ77TBzWw@T^R3?l;+Pbb?(fNt*-;?}Rq(4v{c)PF{r2$FW`zE@XQB4)JAcL1Aj)%p zd-%@k(FG=1{u+58yky46714upICM(q>##bysPF76s<4A0rr82Kp{aXLqSxxd|0kUxer}|qQ+$Q`F&P2yT diff --git a/direct/src/plugin_standalone/panda3dBase.I b/direct/src/plugin_standalone/panda3dBase.I deleted file mode 100644 index f875229f2d..0000000000 --- a/direct/src/plugin_standalone/panda3dBase.I +++ /dev/null @@ -1,29 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file panda3dBase.I - * @author rdb - * @date 2009-12-07 - */ - -/** - * Returns true if it is time to exit because the last instance has exited, or - * false if we should continue running. - */ -bool Panda3DBase:: -time_to_exit() { - return _instances.empty() && _exit_with_last_instance; -} - -/** - * Returns the P3D_instance associated with this URLGetter. - */ -P3D_instance *Panda3DBase::URLGetter:: -get_instance() { - return _instance; -} diff --git a/direct/src/plugin_standalone/panda3dBase.cxx b/direct/src/plugin_standalone/panda3dBase.cxx deleted file mode 100644 index cfdaeb1350..0000000000 --- a/direct/src/plugin_standalone/panda3dBase.cxx +++ /dev/null @@ -1,766 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file panda3dBase.cxx - * @author rdb - * @date 2009-12-07 - */ - -#include "dtoolbase.h" -#ifdef _WIN32 -#include -#include -#else -#include -#endif -#include "panda3dBase.h" -#include "httpClient.h" -#include "find_root_dir.h" -#include "load_plugin.h" -#include "executionEnvironment.h" -#include "multifile.h" -#include "tinyxml.h" - -// We can include this header file to get the DTOOL_PLATFORM definition, even -// though we don't link with dtool. -#include "dtool_platform.h" -#include "pandaVersion.h" - -#include -#include -#include - -using std::cerr; -using std::string; - -// The amount of time in seconds to wait for new messages. -static const double wait_cycle = 0.2; - -/** - * - */ -Panda3DBase:: -Panda3DBase(bool console_environment) { - _console_environment = console_environment; - - // We can't assign _root_dir immediately, because it requires a low-level - // Mac call that will balk if we're not logged in to the console, which will - // prevent scripts from using "panda3d -P" to find the platform and whatnot. - // Instead, we'll assign it after we've processed the command line. - // _root_dir = find_root_dir(); - - _reporting_download = false; - _enable_security = false; - - _window_type = P3D_WT_toplevel; - - _win_x = -1; - _win_y = -1; - _win_width = 800; - _win_height = 600; - _got_win_size = false; - - _exit_with_last_instance = true; - _host_url = PANDA_PACKAGE_HOST_URL; - // Better to leave _this_platform set to the empty string until the user - // specifies otherwise; this allows the plugin to select a suitable platform - // at runtime. - _this_platform = ""; - _coreapi_platform = DTOOL_PLATFORM; - _verify_contents = P3D_VC_none; - _contents_expiration = 0; - - // Seed the lame random number generator in rand(); we use it to select a - // mirror for downloading. - srand((unsigned int)time(nullptr)); - - _prepend_filename_to_args = true; -} - -/** - * Gets lost in the application main loop, waiting for system events and - * notifications from the open instance(s). - */ -void Panda3DBase:: -run_main_loop() { -#ifdef _WIN32 - if (_window_type == P3D_WT_embedded) { - // Wait for new messages from Windows, and new requests from the plugin. - MSG msg; - int retval; - retval = GetMessage(&msg, nullptr, 0, 0); - while (retval != 0 && !time_to_exit()) { - if (retval == -1) { - cerr << "Error processing message queue.\n"; - return; - } - TranslateMessage(&msg); - DispatchMessage(&msg); - - // Check for new requests from the Panda3D plugin. - P3D_instance *inst = P3D_check_request_ptr(wait_cycle); - while (inst != nullptr) { - P3D_request *request = P3D_instance_get_request_ptr(inst); - if (request != nullptr) { - handle_request(request); - } - inst = P3D_check_request_ptr(wait_cycle); - } - - while (!_url_getters.empty() && - !PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE)) { - // If there are no Windows messages, check the download tasks. - run_getters(); - } - retval = GetMessage(&msg, nullptr, 0, 0); - } - - // WM_QUIT has been received. Terminate all instances, and fall through. - while (!_instances.empty()) { - P3D_instance *inst = *(_instances.begin()); - delete_instance(inst); - } - - } else { - // Not an embedded window, so we don't have our own window to generate - // Windows events. Instead, just wait for requests. - while (!time_to_exit()) { - P3D_instance *inst = P3D_check_request_ptr(wait_cycle); - if (inst != nullptr) { - P3D_request *request = P3D_instance_get_request_ptr(inst); - if (request != nullptr) { - handle_request(request); - } - } - run_getters(); - } - } - -#elif defined(__APPLE__) && !__LP64__ - // OSX really prefers to own the main loop, so we install a timer to call - // out to our instances and getters, rather than polling within the event - // loop as we do in the Windows case, above. - EventLoopRef main_loop = GetMainEventLoop(); - EventLoopTimerUPP timer_upp = NewEventLoopTimerUPP(st_timer_callback); - EventLoopTimerRef timer; - EventTimerInterval interval = wait_cycle * kEventDurationSecond; - InstallEventLoopTimer(main_loop, interval, interval, - timer_upp, this, &timer); - RunApplicationEventLoop(); - RemoveEventLoopTimer(timer); - - // Terminate all instances, and fall through. - while (!_instances.empty()) { - P3D_instance *inst = *(_instances.begin()); - delete_instance(inst); - } - -#else // _WIN32, __APPLE__ - - // Now wait while we process pending requests. - while (!time_to_exit()) { - P3D_instance *inst = P3D_check_request_ptr(wait_cycle); - if (inst != nullptr) { - P3D_request *request = P3D_instance_get_request_ptr(inst); - if (request != nullptr) { - handle_request(request); - } - } - run_getters(); - } - -#endif // _WIN32, __APPLE__ -} - -/** - * Polls all of the active URL requests. - */ -void Panda3DBase:: -run_getters() { - URLGetters::iterator gi; - gi = _url_getters.begin(); - while (gi != _url_getters.end()) { - URLGetter *getter = (*gi); - if (getter->run()) { - // This URLGetter is still working. Leave it. - ++gi; - } else { - // This URLGetter is done. Remove it and delete it. - URLGetters::iterator dgi = gi; - ++gi; - _url_getters.erase(dgi); - delete getter; - } - } -} - -/** - * Handles a single request received via the plugin API from a p3d instance. - */ -void Panda3DBase:: -handle_request(P3D_request *request) { - bool handled = false; - switch (request->_request_type) { - case P3D_RT_stop: - delete_instance(request->_instance); -#ifdef _WIN32 - // Post a silly message to spin the event loop. - PostMessage(nullptr, WM_USER, 0, 0); -#endif - handled = true; - break; - - case P3D_RT_get_url: - { - int unique_id = request->_request._get_url._unique_id; - const string &url = request->_request._get_url._url; - URLGetter *getter = new URLGetter - (request->_instance, unique_id, URLSpec(url), ""); - _url_getters.insert(getter); - handled = true; - } - break; - - case P3D_RT_notify: - { - // cerr << "Notify: " << request->_request._notify._message << "\n"; - if (strcmp(request->_request._notify._message, "ondownloadnext") == 0) { - // Tell the user we're downloading a package. - report_downloading_package(request->_instance); - } else if (strcmp(request->_request._notify._message, "ondownloadcomplete") == 0) { - // Tell the user we're done downloading. - report_download_complete(request->_instance); - } else if (strcmp(request->_request._notify._message, "onfail") == 0) { - // Failure! What else can we do? - cerr << "Failed to execute.\n"; - exit(1); - } - } - break; - - default: - break; - }; - - P3D_request_finish_ptr(request, handled); -} - -#ifdef _WIN32 -LONG WINAPI -window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - switch (msg) { - case WM_DESTROY: - PostQuitMessage(0); - break; - }; - - return DefWindowProc(hwnd, msg, wparam, lparam); -} - -/** - * Creates a toplevel window to contain the embedded instances. Windows - * implementation. - */ -void Panda3DBase:: -make_parent_window() { - WNDCLASS wc; - - HINSTANCE application = GetModuleHandle(nullptr); - ZeroMemory(&wc, sizeof(WNDCLASS)); - wc.lpfnWndProc = (WNDPROC)window_proc; - wc.hInstance = application; - wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); - wc.lpszClassName = "panda3d"; - - if (!RegisterClass(&wc)) { - cerr << "Could not register window class!\n"; - exit(1); - } - - DWORD window_style = - WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | - WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | - WS_SIZEBOX | WS_MAXIMIZEBOX; - - HWND toplevel_window = - CreateWindow("panda3d", "Panda3D", window_style, - CW_USEDEFAULT, CW_USEDEFAULT, _win_width, _win_height, - nullptr, nullptr, application, 0); - if (!toplevel_window) { - cerr << "Could not create toplevel window!\n"; - exit(1); - } - - ShowWindow(toplevel_window, SW_SHOWNORMAL); - - memset(&_parent_window, 0, sizeof(_parent_window)); - _parent_window._window_handle_type = P3D_WHT_win_hwnd; - _parent_window._handle._win_hwnd._hwnd = toplevel_window; -} - -#else - -/** - * Creates a toplevel window to contain the embedded instances. - */ -void Panda3DBase:: -make_parent_window() { - // TODO. - assert(false); -} - -#endif - -/** - * Uses the plugin API to create a new P3D instance to play a particular .p3d - * file. This instance is also started if start_instance is true (which - * requires that the named p3d file exists). - */ -P3D_instance *Panda3DBase:: -create_instance(const string &p3d, bool start_instance, - char **args, int num_args, int p3d_offset) { - // Check to see if the p3d filename we were given is a URL, or a local file. - Filename p3d_filename = Filename::from_os_specific(p3d); - string os_p3d_filename = p3d; - bool is_local = !is_url(p3d); - if (is_local && start_instance) { - if (!p3d_filename.exists()) { - cerr << "No such file: " << p3d_filename << "\n"; - exit(1); - } - - p3d_filename.make_absolute(); - os_p3d_filename = p3d_filename.to_os_specific(); - } - if (is_local) { - read_p3d_info(p3d_filename, p3d_offset); - } - - // Build up the token list. - Tokens tokens = _tokens; - P3D_token token; - - string log_basename; - if (!_log_dirname.empty()) { - // Generate output to a logfile. - log_basename = p3d_filename.get_basename_wo_extension(); - token._keyword = "log_basename"; - token._value = log_basename.c_str(); - tokens.push_back(token); - } else { - // Send output to the console. - token._keyword = "console_output"; - if (_console_environment) { - token._value = "1"; - } else { - token._value = "0"; - } - tokens.push_back(token); - } - - token._keyword = "auto_start"; - token._value = "1"; - tokens.push_back(token); - - P3D_token *tokens_p = nullptr; - size_t num_tokens = tokens.size(); - if (!tokens.empty()) { - tokens_p = &tokens[0]; - } - - // Build up the argument list, beginning with the p3d_filename. - pvector argv; - if (_prepend_filename_to_args) { - argv.push_back(os_p3d_filename.c_str()); - } - for (int i = 0; i < num_args; ++i) { - argv.push_back(args[i]); - } - - P3D_instance *inst = P3D_new_instance_ptr(nullptr, tokens_p, num_tokens, - argv.size(), &argv[0], nullptr); - - if (inst != nullptr) { - if (start_instance) { - // We call start() first, to give the core API a chance to notice the - // "hidden" attrib before we set the window parameters. - P3D_instance_start_ptr(inst, is_local, os_p3d_filename.c_str(), p3d_offset); - } - - P3D_instance_setup_window_ptr - (inst, _window_type, _win_x, _win_y, _win_width, _win_height, &_parent_window); - } - - return inst; -} - -/** - * Deletes the indicated instance and removes it from the internal structures. - */ -void Panda3DBase:: -delete_instance(P3D_instance *inst) { - P3D_instance_finish_ptr(inst); - _instances.erase(inst); - - // Make sure we also terminate any pending URLGetters associated with this - // instance. - URLGetters::iterator gi; - gi = _url_getters.begin(); - while (gi != _url_getters.end()) { - URLGetter *getter = (*gi); - if (getter->get_instance() == inst) { - URLGetters::iterator dgi = gi; - ++gi; - _url_getters.erase(dgi); - delete getter; - } - } -} - -/** - * Opens the p3d file to read the p3d_info.xml file within it, looking for any - * locally-relevant parameters (like width and height). - */ -bool Panda3DBase:: -read_p3d_info(const Filename &p3d_filename, int p3d_offset) { - PT(Multifile) mf = new Multifile; - if (!mf->open_read(p3d_filename, p3d_offset)) { - return false; - } - int si = mf->find_subfile("p3d_info.xml"); - if (si == -1) { - return false; - } - - string p3d_info; - mf->read_subfile(si, p3d_info); - std::istringstream strm(p3d_info); - TiXmlDocument doc; - strm >> doc; - if (strm.fail() && !strm.eof()) { - return false; - } - TiXmlElement *xpackage = doc.FirstChildElement("package"); - if (xpackage == nullptr) { - return false; - } - TiXmlElement *xconfig = xpackage->FirstChildElement("config"); - if (xconfig == nullptr) { - return false; - } - - // Successfully read the p3d_info.xml file. - if (!_got_win_size) { - // If the user didn't override the size on the command line, allow the p3d - // file to request a preferred size. - if (xconfig->Attribute("width", &_win_width)) { - _got_win_size = true; - } - if (xconfig->Attribute("height", &_win_height)) { - _got_win_size = true; - } - } - - return true; -} - -/** - * Parses a web token of the form token=value, and stores it in _tokens. - * Returns true on success, false on failure. - */ -bool Panda3DBase:: -parse_token(const char *arg) { - const char *equals = strchr(arg, '='); - if (equals == nullptr) { - return false; - } - - // By convention, the keyword is always lowercase. - string keyword; - for (const char *p = arg; p < equals; ++p) { - keyword += tolower(*p); - } - - P3D_token token; - token._keyword = strdup(keyword.c_str()); - token._value = strdup(equals + 1); - - _tokens.push_back(token); - - return true; -} - -/** - * Parses a string into an x,y pair of integers. Returns true on success, - * false on failure. - */ -bool Panda3DBase:: -parse_int_pair(const char *arg, int &x, int &y) { - char *endptr; - x = strtol(arg, &endptr, 10); - if (*endptr == ',') { - y = strtol(endptr + 1, &endptr, 10); - if (*endptr == '\0') { - return true; - } - } - - // Some parse error on the string. - return false; -} - -/** - * Returns the value associated with the first appearance of the named token, - * or empty string if the token does not appear. - */ -string Panda3DBase:: -lookup_token(const string &keyword) const { - Tokens::const_iterator ti; - for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) { - if (keyword == (*ti)._keyword) { - return (*ti)._value; - } - } - - return string(); -} - -/** - * Compares the two dotted-integer sequence values numerically. Returns -1 if - * seq_a sorts first, 1 if seq_b sorts first, 0 if they are equivalent. - */ -int Panda3DBase:: -compare_seq(const string &seq_a, const string &seq_b) { - const char *num_a = seq_a.c_str(); - const char *num_b = seq_b.c_str(); - int comp = compare_seq_int(num_a, num_b); - while (comp == 0) { - if (*num_a != '.') { - if (*num_b != '.') { - // Both strings ran out together. - return 0; - } - // a ran out first. - return -1; - } else if (*num_b != '.') { - // b ran out first. - return 1; - } - - // Increment past the dot. - ++num_a; - ++num_b; - comp = compare_seq(num_a, num_b); - } - - return comp; -} - -/** - * Numerically compares the formatted integer value at num_a with num_b. - * Increments both num_a and num_b to the next character following the valid - * integer. - */ -int Panda3DBase:: -compare_seq_int(const char *&num_a, const char *&num_b) { - long int a; - char *next_a; - long int b; - char *next_b; - - a = strtol((char *)num_a, &next_a, 10); - b = strtol((char *)num_b, &next_b, 10); - - num_a = next_a; - num_b = next_b; - - if (a < b) { - return -1; - } else if (b < a) { - return 1; - } else { - return 0; - } -} - -/** - * Returns true if the indicated string appears to be a URL, with a leading - * http:// or file:// or whatever, or false if it must be a local filename - * instead. - */ -bool Panda3DBase:: -is_url(const string ¶m) { - // We define a URL prefix as a sequence of at least two letters, followed by - // a colon, followed by at least one slash. - size_t p = 0; - while (p < param.size() && isalpha(param[p])) { - ++p; - } - if (p < 2) { - // Not enough letters. - return false; - } - if (p >= param.size() || param[p] != ':') { - // No colon. - return false; - } - ++p; - if (p >= param.size() || param[p] != '/') { - // No slash. - return false; - } - - // It matches the rules. - return true; -} - -/** - * Tells the user we have to download a package. - */ -void Panda3DBase:: -report_downloading_package(P3D_instance *instance) { - P3D_object *obj = P3D_instance_get_panda_script_object_ptr(instance); - - P3D_object *display_name = P3D_object_get_property_ptr(obj, "downloadPackageDisplayName"); - if (display_name == nullptr) { - cerr << "Installing package.\n"; - return; - } - - int name_length = P3D_object_get_string_ptr(display_name, nullptr, 0); - char *name = new char[name_length + 1]; - P3D_object_get_string_ptr(display_name, name, name_length + 1); - - cerr << "Installing " << name << "\n"; - - delete[] name; - P3D_object_decref_ptr(display_name); - _reporting_download = true; -} - -/** - * Tells the user we're done downloading packages - */ -void Panda3DBase:: -report_download_complete(P3D_instance *instance) { - if (_reporting_download) { - cerr << "Install complete.\n"; - } -} - -#if defined(__APPLE__) && !__LP64__ -/** - * Installed as a timer on the event loop, so we can process local events, in - * the Apple implementation. - */ -pascal void Panda3DBase:: -st_timer_callback(EventLoopTimerRef timer, void *user_data) { - ((Panda3DBase *)user_data)->timer_callback(timer); -} -#endif // __APPLE__ - -#if defined(__APPLE__) && !__LP64__ -/** - * Installed as a timer on the event loop, so we can process local events, in - * the Apple implementation. - */ -void Panda3DBase:: -timer_callback(EventLoopTimerRef timer) { - // Check for new requests from the Panda3D plugin. - P3D_instance *inst = P3D_check_request_ptr(0.0); - while (inst != nullptr) { - P3D_request *request = P3D_instance_get_request_ptr(inst); - if (request != nullptr) { - handle_request(request); - } - inst = P3D_check_request_ptr(0.0); - } - - // Check the download tasks. - run_getters(); - - // If we're out of instances, exit the application. - if (time_to_exit()) { - QuitApplicationEventLoop(); - } -} -#endif // __APPLE__ - -/** - * - */ -Panda3DBase::URLGetter:: -URLGetter(P3D_instance *instance, int unique_id, - const URLSpec &url, const string &post_data) : - _instance(instance), - _unique_id(unique_id), - _url(url), - _post_data(post_data) -{ - HTTPClient *http = HTTPClient::get_global_ptr(); - - _channel = http->make_channel(false); - // _channel->set_download_throttle(true); - if (_post_data.empty()) { - _channel->begin_get_document(_url); - } else { - _channel->begin_post_form(_url, _post_data); - } - - _channel->download_to_ram(&_rf); - _bytes_sent = 0; -} - -/** - * Polls the URLGetter for new results. Returns true if the URL request is - * still in progress and run() should be called again later, or false if the - * URL request has been completed and run() should not be called again. - */ -bool Panda3DBase::URLGetter:: -run() { - if (_channel->run() || _rf.get_data_size() != 0) { - if (_rf.get_data_size() != 0) { - // Got some new data. - bool download_ok = P3D_instance_feed_url_stream_ptr - (_instance, _unique_id, P3D_RC_in_progress, - _channel->get_status_code(), - _channel->get_file_size(), - (const unsigned char *)_rf.get_data().data(), _rf.get_data_size()); - _bytes_sent += _rf.get_data_size(); - _rf.clear(); - - if (!download_ok) { - // The plugin doesn't care any more. Interrupt the download. - cerr << "Download interrupted: " << _url - << ", after " << _bytes_sent << " of " << _channel->get_file_size() - << " bytes.\n"; - return false; - } - } - - // Still more to come; call this method again later. - return true; - } - - // All done. - P3D_result_code status = P3D_RC_done; - if (!_channel->is_valid()) { - if (_channel->get_status_code() != 0) { - status = P3D_RC_http_error; - } else { - status = P3D_RC_generic_error; - } - cerr << "Error getting URL " << _url << "\n"; - } - - P3D_instance_feed_url_stream_ptr - (_instance, _unique_id, status, - _channel->get_status_code(), - _bytes_sent, nullptr, 0); - return false; -} diff --git a/direct/src/plugin_standalone/panda3dBase.h b/direct/src/plugin_standalone/panda3dBase.h deleted file mode 100644 index 3b41aab07c..0000000000 --- a/direct/src/plugin_standalone/panda3dBase.h +++ /dev/null @@ -1,126 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file panda3dBase.h - * @author rdb - * @date 2009-12-07 - */ - -#ifndef PANDA3DBASE_H -#define PANDA3DBASE_H - -// This program must link with Panda for HTTPClient support. This means it -// probably should be built with LINK_ALL_STATIC defined, so we won't have to -// deal with confusing .dll or .so files that might compete on the disk with -// the dynamically-loaded versions. There's no competition in memory address -// space, though, because p3d_plugin--the only file we dynamically link in-- -// doesn't itself link with Panda. - -#include "pandabase.h" -#include "p3d_plugin.h" -#include "httpChannel.h" -#include "ramfile.h" -#include "fileSpec.h" -#include "pset.h" -#include "vector_string.h" - -/** - * Base for creating a standalone application that invokes the panda3d plugin - * to launch .p3d files. - */ -class Panda3DBase { -public: - Panda3DBase(bool console_environment); - - void run_main_loop(); - -protected: - void run_getters(); - void handle_request(P3D_request *request); - void make_parent_window(); - - P3D_instance * - create_instance(const std::string &p3d, bool start_instance, - char **args, int num_args, int p3d_offset = 0); - void delete_instance(P3D_instance *instance); - - bool read_p3d_info(const Filename &p3d_filename, int p3d_offset = 0); - bool parse_token(const char *arg); - bool parse_int_pair(const char *arg, int &x, int &y); - std::string lookup_token(const std::string &keyword) const; - static int compare_seq(const std::string &seq_a, const std::string &seq_b); - static int compare_seq_int(const char *&num_a, const char *&num_b); - static bool is_url(const std::string ¶m); - - void report_downloading_package(P3D_instance *instance); - void report_download_complete(P3D_instance *instance); - - inline bool time_to_exit(); - -#ifdef __APPLE__ - static pascal void st_timer_callback(EventLoopTimerRef timer, void *user_data); - void timer_callback(EventLoopTimerRef timer); -#endif - -protected: - std::string _host_url; - std::string _root_dir; - std::string _host_dir; - std::string _start_dir; - std::string _log_dirname; - std::string _log_basename; - std::string _this_platform; - std::string _coreapi_platform; - P3D_verify_contents _verify_contents; - time_t _contents_expiration; - - P3D_window_type _window_type; - P3D_window_handle _parent_window; - int _win_x, _win_y; - int _win_width, _win_height; - bool _got_win_size; - bool _exit_with_last_instance; - - bool _reporting_download; - bool _enable_security; - bool _console_environment; - bool _prepend_filename_to_args; - - typedef pset Instances; - Instances _instances; - - typedef pvector Tokens; - Tokens _tokens; - - // This nested class keeps track of active URL requests. - class URLGetter { - public: - URLGetter(P3D_instance *instance, int unique_id, - const URLSpec &url, const std::string &post_data); - - bool run(); - inline P3D_instance *get_instance(); - - private: - P3D_instance *_instance; - int _unique_id; - URLSpec _url; - std::string _post_data; - - PT(HTTPChannel) _channel; - Ramfile _rf; - size_t _bytes_sent; - }; - - typedef pset URLGetters; - URLGetters _url_getters; -}; - -#include "panda3dBase.I" - -#endif diff --git a/direct/src/plugin_standalone/panda3dMac.I b/direct/src/plugin_standalone/panda3dMac.I deleted file mode 100644 index d70e879a92..0000000000 --- a/direct/src/plugin_standalone/panda3dMac.I +++ /dev/null @@ -1,12 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file panda3dMac.I - * @author drose - * @date 2009-10-23 - */ diff --git a/direct/src/plugin_standalone/panda3dMac.cxx b/direct/src/plugin_standalone/panda3dMac.cxx deleted file mode 100644 index 5a87c60d3e..0000000000 --- a/direct/src/plugin_standalone/panda3dMac.cxx +++ /dev/null @@ -1,107 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file panda3dMac.cxx - * @author drose - * @date 2009-10-23 - */ - -#include "panda3dMac.h" -#include "load_plugin.h" - -#include -#include - -// Having a global Panda3DMac object just makes things easier. -static Panda3DMac *this_prog; - -/** - * - */ -Panda3DMac:: -Panda3DMac() : Panda3D(false) { - // Mac applications traditionally keep running even when all windows are - // closed. - _exit_with_last_instance = false; - - // No command-line arguments, so just run. - if (!post_arg_processing()) { - exit(1); - } -} - -/** - * Opens a p3d file received via the "open documents" event as its own - * instance. - */ -void Panda3DMac:: -open_p3d_file(FSRef *ref) { - OSErr err; - - static const size_t buffer_size = 4096; - UInt8 filename[buffer_size]; - err = FSRefMakePath(ref, filename, buffer_size); - if (err) { - std::cerr << "Couldn't get filename\n"; - return; - } - - // Create an instance. - create_instance((char *)filename, true, nullptr, 0); -} - -static pascal OSErr -open_documents_handler(const AppleEvent *theAppleEvent, AppleEvent *reply, - SRefCon handlerRefcon) { - AEDescList docList; - FSRef theFSRef; - long index; - long count = 0; - - // Get the list of file aliases from the event. - OSErr err = AEGetParamDesc(theAppleEvent, - keyDirectObject, typeAEList, &docList); - require_noerr(err, CantGetDocList); - - err = AECountItems(&docList, &count); - require_noerr(err, CantGetCount); - - for (index = 1; index <= count; index++) { - err = AEGetNthPtr(&docList, index, typeFSRef, - nullptr, nullptr, &theFSRef, sizeof(FSRef), nullptr);// 5 - require_noerr(err, CantGetDocDescPtr); - - // Here's the file, do something with it. - this_prog->open_p3d_file(&theFSRef); - } - - // Release list of files - AEDisposeDesc(&docList); - - // Error handlers. - CantGetDocList: - CantGetCount: - CantGetDocDescPtr: - return (err); -} - -int -main(int argc, char *argv[]) { - OSErr err; - AEEventHandlerUPP handler; - - this_prog = new Panda3DMac; - handler = NewAEEventHandlerUPP(open_documents_handler); - err = AEInstallEventHandler - (kCoreEventClass, kAEOpenDocuments, handler, 0, false); - - // The command-line options are weird when we start from the Launcher. Just - // ignore them. - this_prog->run_main_loop(); - return 0; -} diff --git a/direct/src/plugin_standalone/panda3dMac.h b/direct/src/plugin_standalone/panda3dMac.h deleted file mode 100644 index 8d6899dba0..0000000000 --- a/direct/src/plugin_standalone/panda3dMac.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file panda3dMac.h - * @author drose - * @date 2009-10-23 - */ - -#ifndef PANDA3DMAC_H -#define PANDA3DMAC_H - -#include "panda3d.h" - -#include - -/** - * A specialization of Panda3D for running as a Carbon application on OS X. - * Instead of taking input from the command line, this program waits quietly - * for an "open documents" Apple event. - */ -class Panda3DMac : public Panda3D { -public: - Panda3DMac(); - - void open_p3d_file(FSRef *ref); -}; - -#endif diff --git a/direct/src/plugin_standalone/panda3dMain.cxx b/direct/src/plugin_standalone/panda3dMain.cxx deleted file mode 100644 index 51420eb39a..0000000000 --- a/direct/src/plugin_standalone/panda3dMain.cxx +++ /dev/null @@ -1,21 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file panda3dMain.cxx - * @author drose - * @date 2009-10-23 - */ - -#include "panda3d.h" - -// The normal, "console" program. -int -main(int argc, char *argv[]) { - Panda3D program(true); - return program.run_command_line(argc, argv); -} diff --git a/direct/src/plugin_standalone/panda3dWinMain.cxx b/direct/src/plugin_standalone/panda3dWinMain.cxx deleted file mode 100644 index ec7b8e630c..0000000000 --- a/direct/src/plugin_standalone/panda3dWinMain.cxx +++ /dev/null @@ -1,76 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file panda3dWinMain.cxx - * @author drose - * @date 2009-10-23 - */ - -#include "panda3d.h" - -// On Windows, we may need to build panda3dw.exe, a non-console version of -// this program. - -// Returns a newly-allocated string representing the quoted argument beginning -// at p. Advances p to the first character following the close quote. -static char * -parse_quoted_arg(char *&p) { - char quote = *p; - ++p; - std::string result; - - while (*p != '\0' && *p != quote) { - // TODO: handle escape characters? Not sure if we need to. - result += *p; - ++p; - } - if (*p == quote) { - ++p; - } - return strdup(result.c_str()); -} - -// Returns a newly-allocated string representing the unquoted argument -// beginning at p. Advances p to the first whitespace following the argument. -static char * -parse_unquoted_arg(char *&p) { - std::string result; - while (*p != '\0' && !isspace(*p)) { - result += *p; - ++p; - } - return strdup(result.c_str()); -} - -int WINAPI -WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { - char *command_line = GetCommandLine(); - - std::vector argv; - - char *p = command_line; - while (*p != '\0') { - if (*p == '"') { - char *arg = parse_quoted_arg(p); - argv.push_back(arg); - } else { - char *arg = parse_unquoted_arg(p); - argv.push_back(arg); - } - - // Skip whitespace. - while (*p != '\0' && isspace(*p)) { - ++p; - } - } - - assert(!argv.empty()); - - Panda3D program(false); - return program.run_command_line(argv.size(), &argv[0]); -} diff --git a/direct/src/plugin_standalone/panda3d_mac.plist b/direct/src/plugin_standalone/panda3d_mac.plist deleted file mode 100644 index eb122e23d8..0000000000 --- a/direct/src/plugin_standalone/panda3d_mac.plist +++ /dev/null @@ -1,55 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleDisplayName - Panda3D Runtime - CFBundleDocumentTypes - - - CFBundleTypeName - Panda3D applet - CFBundleTypeIconFile - panda3d.icns - CFBundleTypeExtensions - - p3d - - CFBundleTypeMIMETypes - - application/x-panda3d - - CFBundleTypeRole - Viewer - LSTypeIsPackage - - - - CFBundleExecutable - panda3d_mac - CFBundleIconFile - panda3d.icns - CFBundleIdentifier - org.panda3d.runtime.panda3d_mac - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - Panda3D - CFBundlePackageType - APPL - CFBundleShortVersionString - 0.9.3 - CFBundleSignature - ???? - CFBundleVersion - 0.9.3 - LSHasLocalizedDisplayName - - NSAppleScriptEnabled - - NSPrincipalClass - NSApplication - - diff --git a/direct/src/showbase/AppRunnerGlobal.py b/direct/src/showbase/AppRunnerGlobal.py index 2ab5c0ccf9..f5663b5ef5 100644 --- a/direct/src/showbase/AppRunnerGlobal.py +++ b/direct/src/showbase/AppRunnerGlobal.py @@ -6,6 +6,9 @@ This is needed for apps that start themselves by importing DirectStart; it provides a place for these apps to look for the AppRunner at startup. """ +if __debug__: + print('AppRunner has been removed and AppRunnerGlobal has been deprecated') + #: Contains the global AppRunner instance, or None if this application #: was not run from the runtime environment. appRunner = None diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 029f171944..f9506074a9 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -46,7 +46,6 @@ if __debug__: from direct.showbase import GarbageReport from direct.directutil import DeltaProfiler from . import OnScreenDebug -from . import AppRunnerGlobal @atexit.register def exitfunc(): @@ -81,7 +80,7 @@ class ShowBase(DirectObject.DirectObject): ## This contains the global appRunner instance, as imported from ## AppRunnerGlobal. This will be None if we are not running in the ## runtime environment (ie. from a .p3d file). - self.appRunner = AppRunnerGlobal.appRunner + self.appRunner = None self.app_runner = self.appRunner #debug running multiplier diff --git a/dtool/PandaVersion.pp b/dtool/PandaVersion.pp index 6e931a149c..e31c9da99a 100644 --- a/dtool/PandaVersion.pp +++ b/dtool/PandaVersion.pp @@ -21,31 +21,3 @@ // It should be set by whoever provides a particular distribution of // Panda. If you build your own Panda, leave this unchanged. #define PANDA_DISTRIBUTOR homebuilt - -// This string is used to describe the Panda3D "package" associated -// with this current build of Panda. It should increment with major -// and minor version changes, but not sequence (or "bugfix") changes. -// It should be unique for each unique distributor. The default is -// the empty string, which means this build does not precisely match -// any distributable Panda3D packages. If you are making a Panda3D -// build which you will be using to produce a distributable Panda3D -// package, you should set this string appropriately. -#define PANDA_PACKAGE_VERSION - -// We also define a version for the Panda3D plugin/runtime, -// i.e. nppanda3d.dll, p3dactivex.ocx, and panda3d.exe. This is an -// independent version number from PANDA_VERSION or -// PANDA_PACKAGE_VERSION, because it is anticipated that this plugin -// code, once settled, will need to be updated much less frequently -// than Panda itself. -#define P3D_PLUGIN_VERSION 1 0 4 - -// Finally, there's a separate version number for the Core API. At -// first, we didn't believe we needed a Core API version number, but -// in this belief we were naive. This version number is a little less -// strict in its format requirements than P3D_PLUGIN_VERSION, above, -// and it doesn't necessarily consist of a specific number of -// integers, but by convention it will consist of four integers, with -// the first three matching the plugin version, and the fourth integer -// being incremented with each new Core API revision. -#define P3D_COREAPI_VERSION $[P3D_PLUGIN_VERSION] 2 diff --git a/dtool/src/dtoolutil/pandaSystem.cxx b/dtool/src/dtoolutil/pandaSystem.cxx index 3d80d0f6b5..c3a6fda015 100644 --- a/dtool/src/dtoolutil/pandaSystem.cxx +++ b/dtool/src/dtoolutil/pandaSystem.cxx @@ -33,8 +33,8 @@ PandaSystem() : // These are settable via Config.prc, but only in development (!NDEBUG) // mode, and only if they are not already defined. - _package_version_string = PANDA_PACKAGE_VERSION_STR; - _package_host_url = PANDA_PACKAGE_HOST_URL; + _package_version_string = ""; + _package_host_url = ""; #ifdef STDFLOAT_DOUBLE add_system("stdfloat-double"); @@ -94,14 +94,13 @@ get_version_string() { * If this string is empty, then the currently-executing Panda was built * independently, and is not part of a distributable package. * - * This string is set explicitly at compilation time. Normally, it should be - * set to a nonempty string only when building a Panda3D package for - * distribution. + * @deprecated Runtime/plugin environment has been removed, this now always + * returns an empty string. */ string PandaSystem:: get_package_version_string() { #ifdef NDEBUG - return PANDA_PACKAGE_VERSION_STR; + return ""; #else return get_global_ptr()->_package_version_string; #endif @@ -118,11 +117,14 @@ get_package_version_string() { * This string is set explicitly at compilation time. Normally, it should be * set to a nonempty string only when building a Panda3D package for * distribution. + * + * @deprecated Runtime/plugin environment has been removed, this now always + * returns an empty string. */ string PandaSystem:: get_package_host_url() { #ifdef NDEBUG - return PANDA_PACKAGE_HOST_URL; + return ""; #else return get_global_ptr()->_package_host_url; #endif @@ -138,14 +140,13 @@ get_package_host_url() { * provide a particular Core API, which will be the normal case in a * development SDK. However, you should not use this method to determine * whether you are running in a runtime environment or not. + * + * @deprecated Runtime/plugin environment has been removed, this now always + * returns an empty string. */ string PandaSystem:: get_p3d_coreapi_version_string() { -#ifndef P3D_COREAPI_VERSION_STR return ""; -#else - return P3D_COREAPI_VERSION_STR; -#endif } /** @@ -468,7 +469,7 @@ reset_system_names() { */ void PandaSystem:: set_package_version_string(const string &package_version_string) { - _package_version_string = PANDA_PACKAGE_VERSION_STR; + _package_version_string = ""; if (_package_version_string.empty()) { _package_version_string = package_version_string; } @@ -483,7 +484,7 @@ set_package_version_string(const string &package_version_string) { */ void PandaSystem:: set_package_host_url(const string &package_host_url) { - _package_host_url = PANDA_PACKAGE_HOST_URL; + _package_host_url = ""; if (_package_host_url.empty()) { _package_host_url = package_host_url; } diff --git a/makepanda/getversion.py b/makepanda/getversion.py index 09b483eea3..9f30f8b9dd 100755 --- a/makepanda/getversion.py +++ b/makepanda/getversion.py @@ -4,13 +4,10 @@ # and returns it on the command-line. This is useful for the # automated scripts that build the Panda3D releases. -from makepandacore import ParsePandaVersion, ParsePluginVersion, GetMetadataValue +from makepandacore import ParsePandaVersion, GetMetadataValue import sys -if '--runtime' in sys.argv: - version = ParsePluginVersion("dtool/PandaVersion.pp") -else: - version = GetMetadataValue('version') +version = GetMetadataValue('version') version = version.strip() sys.stdout.write(version) diff --git a/makepanda/installpanda.py b/makepanda/installpanda.py index a143f2cf61..83e23bac2c 100644 --- a/makepanda/installpanda.py +++ b/makepanda/installpanda.py @@ -21,18 +21,10 @@ MIME_INFO = ( ("bam.pz", "model/x-compressed-bam", "Compressed Panda3D binary model file", "pview"), ) -MIME_INFO_PLUGIN = ( - ("p3d", "application/x-panda3d", "Panda3D game/applet", "panda3d"), -) - APP_INFO = ( ("pview", "Panda3D Model Viewer", ("egg", "bam", "egg.pz", "bam.pz")), ) -APP_INFO_PLUGIN = ( - ("panda3d", "Panda3D", ("p3d")), -) - def WriteApplicationsFile(fname, appinfo, mimeinfo): fhandle = open(fname, "w") for app, desc, exts in appinfo: @@ -253,38 +245,6 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built", libdir=GetLibDir( if (os.path.isfile(destdir+prefix+"/share/panda3d/direct/leveleditor/copyfiles.pl")): os.remove(destdir+prefix+"/share/panda3d/direct/leveleditor/copyfiles.pl") -def InstallRuntime(destdir="", prefix="/usr", outputdir="built", libdir=GetLibDir()): - if (not prefix.startswith("/")): - prefix = "/" + prefix - libdir = prefix + "/" + libdir - - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/bin") - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/mime-info") - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/mime/packages") - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/application-registry") - oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/applications") - if (os.path.exists(outputdir+"/plugins/nppanda3d.so")): - oscmd("mkdir -m 0755 -p "+destdir+libdir) - oscmd("cp "+outputdir+"/plugins/nppanda3d.so "+destdir+libdir+"/nppanda3d.so") - if sys.platform.startswith("freebsd"): - oscmd("mkdir -m 0755 -p "+destdir+libdir+"/browser_plugins/symlinks/gecko19") - oscmd("mkdir -m 0755 -p "+destdir+libdir+"/libxul/plugins") - oscmd("ln -f -s "+libdir+"/nppanda3d.so "+destdir+libdir+"/browser_plugins/symlinks/gecko19/nppanda3d.so") - oscmd("ln -f -s "+libdir+"/nppanda3d.so "+destdir+libdir+"/libxul/plugins/nppanda3d.so") - else: - oscmd("mkdir -m 0755 -p "+destdir+libdir+"/mozilla/plugins") - oscmd("mkdir -m 0755 -p "+destdir+libdir+"/mozilla-firefox/plugins") - oscmd("mkdir -m 0755 -p "+destdir+libdir+"/xulrunner-addons/plugins") - oscmd("ln -f -s "+libdir+"/nppanda3d.so "+destdir+libdir+"/mozilla/plugins/nppanda3d.so") - oscmd("ln -f -s "+libdir+"/nppanda3d.so "+destdir+libdir+"/mozilla-firefox/plugins/nppanda3d.so") - oscmd("ln -f -s "+libdir+"/nppanda3d.so "+destdir+libdir+"/xulrunner-addons/plugins/nppanda3d.so") - WriteMimeFile(destdir+prefix+"/share/mime-info/panda3d-runtime.mime", MIME_INFO_PLUGIN) - WriteKeysFile(destdir+prefix+"/share/mime-info/panda3d-runtime.keys", MIME_INFO_PLUGIN) - WriteMimeXMLFile(destdir+prefix+"/share/mime/packages/panda3d-runtime.xml", MIME_INFO_PLUGIN) - WriteApplicationsFile(destdir+prefix+"/share/application-registry/panda3d-runtime.applications", APP_INFO_PLUGIN, MIME_INFO_PLUGIN) - oscmd("cp makepanda/panda3d.desktop "+destdir+prefix+"/share/applications/panda3d.desktop") - oscmd("cp "+outputdir+"/bin/panda3d "+destdir+prefix+"/bin/") - if (__name__ == "__main__"): if (sys.platform.startswith("win") or sys.platform == "darwin"): exit("This script is not supported on Windows or Mac OS X at the moment!") @@ -295,7 +255,6 @@ if (__name__ == "__main__"): parser.add_option('', '--outputdir', dest = 'outputdir', help = 'Makepanda\'s output directory (default: built)', default = 'built') parser.add_option('', '--destdir', dest = 'destdir', help = 'Destination directory [default=%s]' % destdir, default = destdir) parser.add_option('', '--prefix', dest = 'prefix', help = 'Prefix [default=/usr/local]', default = '/usr/local') - parser.add_option('', '--runtime', dest = 'runtime', help = 'Specify if runtime build [default=no]', action = 'store_true', default = False) parser.add_option('', '--verbose', dest = 'verbose', help = 'Print commands that are executed [default=no]', action = 'store_true', default = False) (options, args) = parser.parse_args() @@ -312,13 +271,9 @@ if (__name__ == "__main__"): if options.verbose: SetVerbose(True) - if (options.runtime): - print("Installing Panda3D Runtime into " + destdir + options.prefix) - InstallRuntime(destdir = destdir, prefix = options.prefix, outputdir = options.outputdir) - else: - print("Installing Panda3D SDK into " + destdir + options.prefix) - InstallPanda(destdir=destdir, - prefix=options.prefix, - outputdir=options.outputdir, - python_versions=ReadPythonVersionInfoFile()) + print("Installing Panda3D SDK into " + destdir + options.prefix) + InstallPanda(destdir=destdir, + prefix=options.prefix, + outputdir=options.outputdir, + python_versions=ReadPythonVersionInfoFile()) print("Installation finished!") diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py index b23260ab5a..560d1a2c55 100755 --- a/makepanda/makepackage.py +++ b/makepanda/makepackage.py @@ -32,23 +32,6 @@ Description: Panda3D free 3D engine SDK """ -RUNTIME_INSTALLER_DEB_FILE = """ -Package: panda3d-runtime -Version: VERSION -Section: web -Priority: optional -Architecture: ARCH -Essential: no -Depends: DEPENDS -Provides: panda3d-runtime -Maintainer: rdb -Installed-Size: INSTSIZE -Description: Runtime binary and browser plugin for the Panda3D Game Engine - This package contains the runtime distribution and browser plugin of the Panda3D engine. It allows you view webpages that contain Panda3D content and to run games created with Panda3D that are packaged as .p3d file. - -""" - - # We're not putting "python" in the "Requires" field, # since the rpm-based distros don't have a common # naming for the Python package. @@ -64,7 +47,7 @@ BuildRoot: PANDASOURCE/targetroot Panda3D is a game engine which includes graphics, audio, I/O, collision detection, and other abilities relevant to the creation of 3D games. Panda3D is open source and free software under the revised BSD license, and can be used for both free and commercial game development at no financial cost. Panda3D's intended game-development language is Python. The engine itself is written in C++, and utilizes an automatic wrapper-generator to expose the complete functionality of the engine in a Python interface. -This package contains the SDK for development with Panda3D, install panda3d-runtime for the runtime files. +This package contains the SDK for development with Panda3D. %post /sbin/ldconfig %postun @@ -86,30 +69,6 @@ INSTALLER_SPEC_FILE_PVIEW = \ /usr/share/application-registry/panda3d.applications """ -RUNTIME_INSTALLER_SPEC_FILE = """ -Summary: Runtime binary and browser plugin for the Panda3D Game Engine -Name: panda3d-runtime -Version: VERSION -Release: RPMRELEASE -License: BSD License -Group: Productivity/Graphics/Other -BuildRoot: PANDASOURCE/targetroot -%description -This package contains the runtime distribution and browser plugin of the Panda3D engine. It allows you view webpages that contain Panda3D content and to run games created with Panda3D that are packaged as .p3d file. -%files -%defattr(-,root,root) -/usr/bin/panda3d -/usr/%_lib/nppanda3d.so -/usr/%_lib/mozilla/plugins/nppanda3d.so -/usr/%_lib/mozilla-firefox/plugins/nppanda3d.so -/usr/%_lib/xulrunner-addons/plugins/nppanda3d.so -/usr/share/mime-info/panda3d-runtime.mime -/usr/share/mime-info/panda3d-runtime.keys -/usr/share/mime/packages/panda3d-runtime.xml -/usr/share/application-registry/panda3d-runtime.applications -/usr/share/applications/*.desktop -""" - # plist file for Mac OSX Info_plist = """ @@ -134,16 +93,7 @@ INSTALLER_PKG_DESCR_FILE = """ Panda3D is a game engine which includes graphics, audio, I/O, collision detection, and other abilities relevant to the creation of 3D games. Panda3D is open source and free software under the revised BSD license, and can be used for both free and commercial game development at no financial cost. Panda3D's intended game-development language is Python. The engine itself is written in C++, and utilizes an automatic wrapper-generator to expose the complete functionality of the engine in a Python interface. -This package contains the SDK for development with Panda3D, install panda3d-runtime for the runtime files. - -WWW: https://www.panda3d.org/ -""" - -# FreeBSD pkg-descr -RUNTIME_INSTALLER_PKG_DESCR_FILE = """ -Runtime binary and browser plugin for the Panda3D Game Engine - -This package contains the runtime distribution and browser plugin of the Panda3D engine. It allows you view webpages that contain Panda3D content and to run games created with Panda3D that are packaged as .p3d file. +This package contains the SDK for development with Panda3D. WWW: https://www.panda3d.org/ """ @@ -163,7 +113,7 @@ deps: {DEPENDS} """ -def MakeInstallerNSIS(version, file, title, installdir, runtime=False, compressor="lzma", **kwargs): +def MakeInstallerNSIS(version, file, title, installdir, compressor="lzma", **kwargs): outputdir = GetOutputDir() if os.path.isfile(file): @@ -176,23 +126,6 @@ def MakeInstallerNSIS(version, file, title, installdir, runtime=False, compresso else: regview = '32' - if runtime: - # Invoke the make_installer script. - AddToPathEnv("PATH", outputdir + "\\bin") - AddToPathEnv("PATH", outputdir + "\\plugins") - - cmd = sys.executable + " -B -u " + os.path.join("direct", "src", "plugin_installer", "make_installer.py") - cmd += " --version %s --regview %s" % (version, regview) - - if GetTargetArch() == 'x64': - cmd += " --install \"$PROGRAMFILES64\\Panda3D\" " - else: - cmd += " --install \"$PROGRAMFILES32\\Panda3D\" " - - oscmd(cmd) - shutil.move(os.path.join("direct", "src", "plugin_installer", "p3d-setup.exe"), file) - return - print("Building "+title+" installer at %s" % (file)) if compressor != "lzma": print("Note: you are using zlib, which is faster, but lzma gives better compression.") @@ -260,7 +193,7 @@ def MakeDebugSymbolArchive(zipname, dirname): zip.close() -def MakeInstallerLinux(version, debversion=None, rpmrelease=1, runtime=False, +def MakeInstallerLinux(version, debversion=None, rpmrelease=1, python_versions=[], **kwargs): outputdir = GetOutputDir() @@ -269,19 +202,18 @@ def MakeInstallerLinux(version, debversion=None, rpmrelease=1, runtime=False, python3_ver = None install_python_versions = [] - if not runtime: - # What's the system version of Python 3? - oscmd('python3 -V > "%s/tmp/python3_version.txt"' % (outputdir)) - sys_python3_ver = '.'.join(ReadFile(outputdir + "/tmp/python3_version.txt").strip().split(' ')[1].split('.')[:2]) + # What's the system version of Python 3? + oscmd('python3 -V > "%s/tmp/python3_version.txt"' % (outputdir)) + sys_python3_ver = '.'.join(ReadFile(outputdir + "/tmp/python3_version.txt").strip().split(' ')[1].split('.')[:2]) - # Check that we built with support for these. - for version_info in python_versions: - if version_info["version"] == "2.7": - python2_ver = "2.7" - install_python_versions.append(version_info) - elif version_info["version"] == sys_python3_ver: - python3_ver = sys_python3_ver - install_python_versions.append(version_info) + # Check that we built with support for these. + for version_info in python_versions: + if version_info["version"] == "2.7": + python2_ver = "2.7" + install_python_versions.append(version_info) + elif version_info["version"] == sys_python3_ver: + python3_ver = sys_python3_ver + install_python_versions.append(version_info) major_version = '.'.join(version.split('.')[:2]) if not debversion: @@ -304,43 +236,31 @@ def MakeInstallerLinux(version, debversion=None, rpmrelease=1, runtime=False, if dpkg_present: # Invoke installpanda.py to install it into a temporary dir lib_dir = GetDebLibDir() - if runtime: - InstallRuntime(destdir="targetroot", prefix="/usr", - outputdir=outputdir, libdir=lib_dir) - else: - InstallPanda(destdir="targetroot", prefix="/usr", - outputdir=outputdir, libdir=lib_dir, - python_versions=install_python_versions) - oscmd("chmod -R 755 targetroot/usr/share/panda3d") - oscmd("mkdir -m 0755 -p targetroot/usr/share/man/man1") - oscmd("install -m 0644 doc/man/*.1 targetroot/usr/share/man/man1/") + InstallPanda(destdir="targetroot", prefix="/usr", + outputdir=outputdir, libdir=lib_dir, + python_versions=install_python_versions) + oscmd("chmod -R 755 targetroot/usr/share/panda3d") + oscmd("mkdir -m 0755 -p targetroot/usr/share/man/man1") + oscmd("install -m 0644 doc/man/*.1 targetroot/usr/share/man/man1/") oscmd("dpkg --print-architecture > "+outputdir+"/tmp/architecture.txt") pkg_arch = ReadFile(outputdir+"/tmp/architecture.txt").strip() - if runtime: - txt = RUNTIME_INSTALLER_DEB_FILE[1:] - else: - txt = INSTALLER_DEB_FILE[1:] + txt = INSTALLER_DEB_FILE[1:] txt = txt.replace("VERSION", debversion).replace("ARCH", pkg_arch).replace("MAJOR", major_version) txt = txt.replace("INSTSIZE", str(GetDirectorySize("targetroot") // 1024)) oscmd("mkdir -m 0755 -p targetroot/DEBIAN") oscmd("cd targetroot && (find usr -type f -exec md5sum {} ;) > DEBIAN/md5sums") - if not runtime: - oscmd("cd targetroot && (find etc -type f -exec md5sum {} ;) >> DEBIAN/md5sums") - WriteFile("targetroot/DEBIAN/conffiles","/etc/Config.prc\n") + oscmd("cd targetroot && (find etc -type f -exec md5sum {} ;) >> DEBIAN/md5sums") + WriteFile("targetroot/DEBIAN/conffiles","/etc/Config.prc\n") WriteFile("targetroot/DEBIAN/postinst","#!/bin/sh\necho running ldconfig\nldconfig\n") oscmd("cp targetroot/DEBIAN/postinst targetroot/DEBIAN/postrm") # Determine the package name and the locations that # dpkg-shlibdeps should look in for executables. pkg_version = debversion - if runtime: - pkg_name = "panda3d-runtime" - lib_pattern = "debian/%s/usr/%s/*.so" % (pkg_name, lib_dir) - else: - pkg_name = "panda3d" + major_version - lib_pattern = "debian/%s/usr/%s/panda3d/*.so*" % (pkg_name, lib_dir) + pkg_name = "panda3d" + major_version + lib_pattern = "debian/%s/usr/%s/panda3d/*.so*" % (pkg_name, lib_dir) bin_pattern = "debian/%s/usr/bin/*" % (pkg_name) # dpkg-shlibdeps looks in the debian/{pkg_name}/DEBIAN/shlibs directory @@ -353,45 +273,38 @@ def MakeInstallerLinux(version, debversion=None, rpmrelease=1, runtime=False, if GetVerbose(): dpkg_shlibdeps += " -v" - if runtime: - # The runtime doesn't export any useful symbols, so just query the dependencies. - oscmd("cd targetroot && %(dpkg_shlibdeps)s -x%(pkg_name)s %(lib_pattern)s %(bin_pattern)s*" % locals()) - depends = ReadFile("targetroot/debian/substvars").replace("shlibs:Depends=", "").strip() - recommends = "" - provides = "panda3d-runtime" - else: - pkg_name = "panda3d" + major_version - pkg_dir = "debian/panda3d" + major_version + pkg_name = "panda3d" + major_version + pkg_dir = "debian/panda3d" + major_version - # Generate a symbols file so that other packages can know which symbols we export. - oscmd("cd targetroot && dpkg-gensymbols -q -ODEBIAN/symbols -v%(pkg_version)s -p%(pkg_name)s -e%(lib_pattern)s" % locals()) + # Generate a symbols file so that other packages can know which symbols we export. + oscmd("cd targetroot && dpkg-gensymbols -q -ODEBIAN/symbols -v%(pkg_version)s -p%(pkg_name)s -e%(lib_pattern)s" % locals()) - # Library dependencies are required, binary dependencies are recommended. - # We explicitly exclude libphysx-extras since we don't want to depend on PhysX. - oscmd("cd targetroot && LD_LIBRARY_PATH=usr/%(lib_dir)s/panda3d %(dpkg_shlibdeps)s -Tdebian/substvars_dep --ignore-missing-info -x%(pkg_name)s -xlibphysx-extras %(lib_pattern)s" % locals()) - oscmd("cd targetroot && LD_LIBRARY_PATH=usr/%(lib_dir)s/panda3d %(dpkg_shlibdeps)s -Tdebian/substvars_rec --ignore-missing-info -x%(pkg_name)s %(bin_pattern)s" % locals()) + # Library dependencies are required, binary dependencies are recommended. + # We explicitly exclude libphysx-extras since we don't want to depend on PhysX. + oscmd("cd targetroot && LD_LIBRARY_PATH=usr/%(lib_dir)s/panda3d %(dpkg_shlibdeps)s -Tdebian/substvars_dep --ignore-missing-info -x%(pkg_name)s -xlibphysx-extras %(lib_pattern)s" % locals()) + oscmd("cd targetroot && LD_LIBRARY_PATH=usr/%(lib_dir)s/panda3d %(dpkg_shlibdeps)s -Tdebian/substvars_rec --ignore-missing-info -x%(pkg_name)s %(bin_pattern)s" % locals()) - # Parse the substvars files generated by dpkg-shlibdeps. - depends = ReadFile("targetroot/debian/substvars_dep").replace("shlibs:Depends=", "").strip() - recommends = ReadFile("targetroot/debian/substvars_rec").replace("shlibs:Depends=", "").strip() - provides = "panda3d" + # Parse the substvars files generated by dpkg-shlibdeps. + depends = ReadFile("targetroot/debian/substvars_dep").replace("shlibs:Depends=", "").strip() + recommends = ReadFile("targetroot/debian/substvars_rec").replace("shlibs:Depends=", "").strip() + provides = "panda3d" - if python2_ver or python3_ver: - recommends += ", python-pmw" + if python2_ver or python3_ver: + recommends += ", python-pmw" - if python2_ver: - depends += ", python%s" % (python2_ver) - recommends += ", python-wxversion" - recommends += ", python-tk (>= %s)" % (python2_ver) - provides += ", python2-panda3d" + if python2_ver: + depends += ", python%s" % (python2_ver) + recommends += ", python-wxversion" + recommends += ", python-tk (>= %s)" % (python2_ver) + provides += ", python2-panda3d" - if python3_ver: - depends += ", python%s" % (python3_ver) - recommends += ", python3-tk (>= %s)" % (python3_ver) - provides += ", python3-panda3d" + if python3_ver: + depends += ", python%s" % (python3_ver) + recommends += ", python3-tk (>= %s)" % (python3_ver) + provides += ", python3-panda3d" - if not PkgSkip("NVIDIACG"): - depends += ", nvidia-cg-toolkit" + if not PkgSkip("NVIDIACG"): + depends += ", nvidia-cg-toolkit" # Write back the dependencies, and delete the dummy set-up. txt = txt.replace("DEPENDS", depends.strip(', ')) @@ -403,46 +316,39 @@ def MakeInstallerLinux(version, debversion=None, rpmrelease=1, runtime=False, # Package it all up into a .deb file. oscmd("chmod -R 755 targetroot/DEBIAN") oscmd("chmod 644 targetroot/DEBIAN/control targetroot/DEBIAN/md5sums") - if not runtime: - oscmd("chmod 644 targetroot/DEBIAN/conffiles targetroot/DEBIAN/symbols") + oscmd("chmod 644 targetroot/DEBIAN/conffiles targetroot/DEBIAN/symbols") oscmd("fakeroot dpkg-deb -b targetroot %s_%s_%s.deb" % (pkg_name, pkg_version, pkg_arch)) elif rpmbuild_present: # Invoke installpanda.py to install it into a temporary dir - if runtime: - InstallRuntime(destdir="targetroot", prefix="/usr", outputdir=outputdir, libdir=GetRPMLibDir()) - else: - InstallPanda(destdir="targetroot", prefix="/usr", - outputdir=outputdir, libdir=GetRPMLibDir(), - python_versions=install_python_versions) - oscmd("chmod -R 755 targetroot/usr/share/panda3d") + InstallPanda(destdir="targetroot", prefix="/usr", + outputdir=outputdir, libdir=GetRPMLibDir(), + python_versions=install_python_versions) + oscmd("chmod -R 755 targetroot/usr/share/panda3d") oscmd("rpm -E '%_target_cpu' > "+outputdir+"/tmp/architecture.txt") arch = ReadFile(outputdir+"/tmp/architecture.txt").strip() pandasource = os.path.abspath(os.getcwd()) - if runtime: - txt = RUNTIME_INSTALLER_SPEC_FILE[1:] - else: - txt = INSTALLER_SPEC_FILE[1:] + txt = INSTALLER_SPEC_FILE[1:] - # Add the MIME associations if we have pview - if not PkgSkip("PVIEW"): - txt += INSTALLER_SPEC_FILE_PVIEW + # Add the MIME associations if we have pview + if not PkgSkip("PVIEW"): + txt += INSTALLER_SPEC_FILE_PVIEW - # Add the platform-specific Python directories. - dirs = set() - for version_info in install_python_versions: - dirs.add(version_info["platlib"]) - dirs.add(version_info["purelib"]) + # Add the platform-specific Python directories. + dirs = set() + for version_info in install_python_versions: + dirs.add(version_info["platlib"]) + dirs.add(version_info["purelib"]) - for dir in dirs: - txt += dir + "\n" + for dir in dirs: + txt += dir + "\n" - # Add the binaries in /usr/bin explicitly to the spec file - for base in os.listdir(outputdir + "/bin"): - if not base.startswith("deploy-stub"): - txt += "/usr/bin/%s\n" % (base) + # Add the binaries in /usr/bin explicitly to the spec file + for base in os.listdir(outputdir + "/bin"): + if not base.startswith("deploy-stub"): + txt += "/usr/bin/%s\n" % (base) # Write out the spec file. txt = txt.replace("VERSION", version) @@ -451,30 +357,16 @@ def MakeInstallerLinux(version, debversion=None, rpmrelease=1, runtime=False, WriteFile("panda3d.spec", txt) oscmd("fakeroot rpmbuild --define '_rpmdir "+pandasource+"' --buildroot '"+os.path.abspath("targetroot")+"' -bb panda3d.spec") - if runtime: - oscmd("mv "+arch+"/panda3d-runtime-"+version+"-"+rpmrelease+"."+arch+".rpm .") - else: - oscmd("mv "+arch+"/panda3d-"+version+"-"+rpmrelease+"."+arch+".rpm .") + oscmd("mv "+arch+"/panda3d-"+version+"-"+rpmrelease+"."+arch+".rpm .") oscmd("rm -rf "+arch, True) else: exit("To build an installer, either rpmbuild or dpkg-deb must be present on your system!") -def MakeInstallerOSX(version, runtime=False, python_versions=[], **kwargs): +def MakeInstallerOSX(version, python_versions=[], **kwargs): outputdir = GetOutputDir() - if runtime: - # Invoke the make_installer script. - AddToPathEnv("DYLD_LIBRARY_PATH", outputdir + "/plugins") - cmdstr = sys.executable + " " - if sys.version_info >= (2, 6): - cmdstr += "-B " - - cmdstr += "direct/src/plugin_installer/make_installer.py --version %s" % version - oscmd(cmdstr) - return - dmg_name = "Panda3D-" + version if len(python_versions) == 1 and not python_versions[0]["version"].startswith("2."): dmg_name += "-py" + python_versions[0]["version"] @@ -746,17 +638,14 @@ def MakeInstallerOSX(version, runtime=False, python_versions=[], **kwargs): oscmd('rm -f Panda3D-rw.dmg') -def MakeInstallerFreeBSD(version, runtime=False, python_versions=[], **kwargs): +def MakeInstallerFreeBSD(version, python_versions=[], **kwargs): outputdir = GetOutputDir() oscmd("rm -rf targetroot +DESC pkg-plist +MANIFEST") oscmd("mkdir targetroot") # Invoke installpanda.py to install it into a temporary dir - if runtime: - InstallRuntime(destdir="targetroot", prefix="/usr/local", outputdir=outputdir) - else: - InstallPanda(destdir="targetroot", prefix="/usr/local", outputdir=outputdir, python_versions=python_versions) + InstallPanda(destdir="targetroot", prefix="/usr/local", outputdir=outputdir, python_versions=python_versions) if not os.path.exists("/usr/sbin/pkg"): exit("Cannot create an installer without pkg") @@ -766,15 +655,14 @@ def MakeInstallerFreeBSD(version, runtime=False, python_versions=[], **kwargs): for f in files: plist_txt += os.path.join(root, f)[21:] + "\n" - if not runtime: - plist_txt += "@postexec /sbin/ldconfig -m /usr/local/lib/panda3d\n" - plist_txt += "@postunexec /sbin/ldconfig -R\n" + plist_txt += "@postexec /sbin/ldconfig -m /usr/local/lib/panda3d\n" + plist_txt += "@postunexec /sbin/ldconfig -R\n" - for remdir in ("lib/panda3d", "share/panda3d", "include/panda3d"): - for root, dirs, files in os.walk("targetroot/usr/local/" + remdir, False): - for d in dirs: - plist_txt += "@dir %s\n" % os.path.join(root, d)[21:] - plist_txt += "@dir %s\n" % remdir + for remdir in ("lib/panda3d", "share/panda3d", "include/panda3d"): + for root, dirs, files in os.walk("targetroot/usr/local/" + remdir, False): + for d in dirs: + plist_txt += "@dir %s\n" % os.path.join(root, d)[21:] + plist_txt += "@dir %s\n" % remdir oscmd("echo \"`pkg config abi | tr '[:upper:]' '[:lower:]' | cut -d: -f1,2`:*\" > " + outputdir + "/tmp/architecture.txt") pkg_arch = ReadFile(outputdir+"/tmp/architecture.txt").strip() @@ -795,15 +683,15 @@ def MakeInstallerFreeBSD(version, runtime=False, python_versions=[], **kwargs): if python_pkg: dependencies += python_pkg - manifest_txt = INSTALLER_PKG_MANIFEST_FILE[1:].replace("NAME", 'panda3d' if not runtime else 'panda3d-runtime') + manifest_txt = INSTALLER_PKG_MANIFEST_FILE[1:].replace("NAME", 'panda3d') manifest_txt = manifest_txt.replace("VERSION", version) manifest_txt = manifest_txt.replace("ARCH", pkg_arch) - manifest_txt = manifest_txt.replace("ORIGIN", 'devel/panda3d' if not runtime else 'graphics/panda3d-runtime') + manifest_txt = manifest_txt.replace("ORIGIN", 'devel/panda3d') manifest_txt = manifest_txt.replace("DEPENDS", dependencies) manifest_txt = manifest_txt.replace("INSTSIZE", str(GetDirectorySize("targetroot") // 1024 // 1024)) WriteFile("pkg-plist", plist_txt) - WriteFile("+DESC", INSTALLER_PKG_DESCR_FILE[1:] if not runtime else RUNTIME_INSTALLER_PKG_DESCR_FILE[1:]) + WriteFile("+DESC", INSTALLER_PKG_DESCR_FILE[1:]) WriteFile("+MANIFEST", manifest_txt) oscmd("pkg create -p pkg-plist -r %s -m . -o . %s" % (os.path.abspath("targetroot"), "--verbose" if GetVerbose() else "--quiet")) @@ -1002,17 +890,12 @@ def MakeInstaller(version, **kwargs): fn = "Panda3D-" dir = "Panda3D-" + version - runtime = kwargs.get('runtime', False) - if runtime: - fn += "Runtime-" - title = "Panda3D " + version - else: - title = "Panda3D SDK " + version + title = "Panda3D SDK " + version fn += version python_versions = kwargs.get('python_versions', []) - if not runtime and len(python_versions) == 1 and python_versions[0]["version"] != "2.7": + if len(python_versions) == 1 and python_versions[0]["version"] != "2.7": fn += '-py' + python_versions[0]["version"] if GetOptimize() <= 2: @@ -1022,8 +905,7 @@ def MakeInstaller(version, **kwargs): dir += '-x64' MakeInstallerNSIS(version, fn + '.exe', title, 'C:\\' + dir, **kwargs) - if not runtime: - MakeDebugSymbolArchive(fn + '-pdb.zip', dir) + MakeDebugSymbolArchive(fn + '-pdb.zip', dir) elif target == 'linux': MakeInstallerLinux(version, **kwargs) elif target == 'darwin': @@ -1045,7 +927,6 @@ if __name__ == "__main__": parser.add_option('', '--rpmrelease', dest='rpmrelease', help='Release number for .rpm file', default='1') parser.add_option('', '--outputdir', dest='outputdir', help='Makepanda\'s output directory (default: built)', default='built') parser.add_option('', '--verbose', dest='verbose', help='Enable verbose output', action='store_true', default=False) - parser.add_option('', '--runtime', dest='runtime', help='Runtime instead of SDK', action='store_true', default=False) parser.add_option('', '--lzma', dest='compressor', help='Use LZMA compression', action='store_const', const='lzma', default='zlib') (options, args) = parser.parse_args() @@ -1079,5 +960,4 @@ if __name__ == "__main__": compressor=options.compressor, debversion=options.debversion, rpmrelease=options.rpmrelease, - runtime=options.runtime, python_versions=ReadPythonVersionInfoFile()) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index c1f1056a1b..2dc92ac7c0 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -49,21 +49,14 @@ THREADCOUNT=0 CFLAGS="" CXXFLAGS="" LDFLAGS="" -RTDIST=0 -RTDIST_VERSION=None -RUNTIME=0 DISTRIBUTOR="" VERSION=None DEBVERSION=None WHLVERSION=None RPMRELEASE="1" GIT_COMMIT=None -P3DSUFFIX=None MAJOR_VERSION=None -COREAPI_VERSION=None -PLUGIN_VERSION=None OSXTARGET=None -HOST_URL=None global STRDXSDKVERSION, BOOUSEINTELCOMPILER STRDXSDKVERSION = 'default' WINDOWS_SDK = None @@ -129,7 +122,6 @@ def usage(problem): print("") print(" --help (print the help message you're reading now)") print(" --verbose (print out more information)") - print(" --runtime (build a runtime build instead of an SDK build)") print(" --tests (run the test suite)") print(" --installer (build an installer)") print(" --wheel (build a pip-installable .whl)") @@ -138,7 +130,6 @@ def usage(problem): print(" --lzma (use lzma compression when building Windows installer)") print(" --distributor X (short string identifying the distributor of the build)") print(" --outputdir X (use the specified directory instead of 'built')") - print(" --host URL (set the host url (runtime build only))") print(" --threads N (use the multithreaded build system. see manual)") print(" --osxtarget N (the OS X version number to build for (OS X only))") print(" --override \"O=V\" (override dtool_config/prc option value)") @@ -167,9 +158,9 @@ def usage(problem): os._exit(1) def parseopts(args): - global INSTALLER,WHEEL,RUNTESTS,RTDIST,RUNTIME,GENMAN,DISTRIBUTOR,VERSION - global COMPRESSOR,THREADCOUNT,OSXTARGET,HOST_URL - global DEBVERSION,WHLVERSION,RPMRELEASE,GIT_COMMIT,P3DSUFFIX,RTDIST_VERSION + global INSTALLER,WHEEL,RUNTESTS,GENMAN,DISTRIBUTOR,VERSION + global COMPRESSOR,THREADCOUNT,OSXTARGET + global DEBVERSION,WHLVERSION,RPMRELEASE,GIT_COMMIT global STRDXSDKVERSION, WINDOWS_SDK, MSVC_VERSION, BOOUSEINTELCOMPILER global COPY_PYTHON @@ -181,10 +172,10 @@ def parseopts(args): # All recognized options. longopts = [ - "help","distributor=","verbose","runtime","osxtarget=","tests", + "help","distributor=","verbose","osxtarget=","tests", "optimize=","everything","nothing","installer","wheel","rtdist","nocolor", "version=","lzma","no-python","threads=","outputdir=","override=", - "static","host=","debversion=","rpmrelease=","p3dsuffix=","rtdist-version=", + "static","debversion=","rpmrelease=","p3dsuffix=","rtdist-version=", "directx-sdk=", "windows-sdk=", "msvc-version=", "clean", "use-icl", "target=", "arch=", "git-commit=", "no-copy-python", ] + removedopts @@ -210,8 +201,6 @@ def parseopts(args): elif (option=="--wheel"): WHEEL=1 elif (option=="--verbose"): SetVerbose(True) elif (option=="--distributor"): DISTRIBUTOR=value - elif (option=="--rtdist"): RTDIST=1 - elif (option=="--runtime"): RUNTIME=1 elif (option=="--genman"): GENMAN=1 elif (option=="--everything"): PkgEnableAll() elif (option=="--nothing"): PkgDisableAll() @@ -230,12 +219,9 @@ def parseopts(args): elif (option=="--lzma"): COMPRESSOR="lzma" elif (option=="--override"): AddOverride(value.strip()) elif (option=="--static"): SetLinkAllStatic(True) - elif (option=="--host"): HOST_URL=value elif (option=="--debversion"): DEBVERSION=value elif (option=="--rpmrelease"): RPMRELEASE=value elif (option=="--git-commit"): GIT_COMMIT=value - elif (option=="--p3dsuffix"): P3DSUFFIX=value - elif (option=="--rtdist-version"): RTDIST_VERSION=value # Backward compatibility, OPENGL was renamed to GL elif (option=="--use-opengl"): PkgEnable("GL") elif (option=="--no-opengl"): PkgDisable("GL") @@ -276,15 +262,9 @@ def parseopts(args): usage(sys.exc_info()[1]) if not anything: - if RUNTIME: - PkgEnableAll() - else: - usage("You should specify a list of packages to use or --everything to enable all packages.") + usage("You should specify a list of packages to use or --everything to enable all packages.") - if (RTDIST and RUNTIME): - usage("Options --runtime and --rtdist cannot be specified at the same time!") - if (optimize=="" and (RTDIST or RUNTIME)): optimize = "4" - elif (optimize==""): optimize = "3" + if (optimize==""): optimize = "3" if OSXTARGET: try: @@ -370,31 +350,20 @@ if GetHost() == "darwin" and OSXTARGET is not None: ## ######################################################################## -PLUGIN_VERSION = ParsePluginVersion("dtool/PandaVersion.pp") -COREAPI_VERSION = PLUGIN_VERSION + "." + ParseCoreapiVersion("dtool/PandaVersion.pp") - if VERSION is None: - if RUNTIME: - VERSION = PLUGIN_VERSION - else: - # Take the value from the setup.cfg file. - VERSION = GetMetadataValue('version') + # Take the value from the setup.cfg file. + VERSION = GetMetadataValue('version') if WHLVERSION is None: WHLVERSION = VERSION print("Version: %s" % VERSION) -if RUNTIME or RTDIST: - print("Core API Version: %s" % COREAPI_VERSION) if DEBVERSION is None: DEBVERSION = VERSION MAJOR_VERSION = '.'.join(VERSION.split('.')[:2]) -if P3DSUFFIX is None: - P3DSUFFIX = MAJOR_VERSION - # Now determine the distutils-style platform tag for the target system. target = GetTarget() if target == 'windows': @@ -443,25 +412,8 @@ print("Platform: %s" % PLATFORM) outputdir_suffix = "" -if (RUNTIME or RTDIST): - # Compiling Maya/Max is pointless in rtdist build - for ver in MAYAVERSIONS + MAXVERSIONS: - PkgDisable(ver) - - if (DISTRIBUTOR.strip() == ""): - exit("You must provide a valid distributor name when making a runtime or rtdist build!") - - outputdir_suffix += "_" + DISTRIBUTOR.strip() - if (RUNTIME): - outputdir_suffix += "_rt" - if DISTRIBUTOR == "": DISTRIBUTOR = "makepanda" -elif not RTDIST_VERSION: - RTDIST_VERSION = DISTRIBUTOR.strip() + "_" + MAJOR_VERSION - -if not RTDIST_VERSION: - RTDIST_VERSION = "dev" if not IsCustomOutputDir(): if GetTarget() == "windows" and GetTargetArch() == 'x64': @@ -469,40 +421,12 @@ if not IsCustomOutputDir(): SetOutputDir("built" + outputdir_suffix) -if (RUNTIME): - for pkg in PkgListGet(): - if pkg in ["GTK2", "MFC"]: - # Optional package(s) for runtime. - pass - elif pkg in ["OPENSSL", "ZLIB"]: - # Required packages for runtime. - if (PkgSkip(pkg)==1): - exit("Runtime must be compiled with OpenSSL and ZLib support!") - else: - # Unused packages for runtime. - PkgDisable(pkg) - -if (INSTALLER and RTDIST): - exit("Cannot build an installer for the rtdist build!") - -if (WHEEL and RUNTIME): - exit("Cannot build a wheel for the runtime build!") - -if (WHEEL and RTDIST): - exit("Cannot build a wheel for the rtdist build!") - -if (INSTALLER) and (PkgSkip("PYTHON")) and (not RUNTIME) and GetTarget() == 'windows': +if (INSTALLER) and (PkgSkip("PYTHON")) and GetTarget() == 'windows': exit("Cannot build installer on Windows without python") if WHEEL and PkgSkip("PYTHON"): exit("Cannot build wheel without Python") -if (RTDIST) and (PkgSkip("WX") and PkgSkip("FLTK")): - exit("Cannot build rtdist without wx or fltk") - -if (RUNTIME): - SetLinkAllStatic(True) - if not os.path.isdir("contrib"): PkgDisable("CONTRIB") @@ -526,7 +450,7 @@ SdkLocateDirectX(STRDXSDKVERSION) SdkLocateMaya() SdkLocateMax() SdkLocateMacOSX(OSXTARGET) -SdkLocatePython(RTDIST) +SdkLocatePython(False) SdkLocateWindows(WINDOWS_SDK) SdkLocatePhysX() SdkLocateSpeedTree() @@ -538,22 +462,6 @@ SdkAutoDisableMax() SdkAutoDisablePhysX() SdkAutoDisableSpeedTree() -if RTDIST and DISTRIBUTOR == "cmu": - # Some validation checks for the CMU builds. - if (RTDIST_VERSION == "cmu_1.7" and SDK["PYTHONVERSION"] != "python2.6"): - exit("The CMU 1.7 runtime distribution must be built against Python 2.6!") - elif (RTDIST_VERSION == "cmu_1.8" and SDK["PYTHONVERSION"] != "python2.7"): - exit("The CMU 1.8 runtime distribution must be built against Python 2.7!") - elif (RTDIST_VERSION == "cmu_1.9" and SDK["PYTHONVERSION"] != "python2.7"): - exit("The CMU 1.9 runtime distribution must be built against Python 2.7!") - -if RTDIST and not HOST_URL: - exit("You must specify a host URL when building the rtdist!") - -if RUNTIME and not HOST_URL: - # Set this to a nice default. - HOST_URL = "https://runtime.panda3d.org/" - if not PkgSkip("PYTHON") and SDK["PYTHONVERSION"] == "python2.7": warn_prefix = "%sWARNING:%s " % (GetColor("red"), GetColor()) print("=========================================================================") @@ -763,17 +671,6 @@ if (COMPILER == "MSVC"): LibName("FMODEX", GetThirdpartyDir() + "fmodex/lib/fmodex64_vc.lib") else: LibName("FMODEX", GetThirdpartyDir() + "fmodex/lib/fmodex_vc.lib") - if (PkgSkip("FLTK")==0 and RTDIST): - LibName("FLTK", GetThirdpartyDir() + "fltk/lib/fltk.lib") - if not PkgSkip("FLTK"): - # If we have fltk, we don't need wx - PkgDisable("WX") - if (PkgSkip("WX")==0 and RTDIST): - LibName("WX", GetThirdpartyDir() + "wx/lib/wxbase28u.lib") - LibName("WX", GetThirdpartyDir() + "wx/lib/wxmsw28u_core.lib") - DefSymbol("WX", "__WXMSW__", "") - DefSymbol("WX", "_UNICODE", "") - DefSymbol("WX", "UNICODE", "") if (PkgSkip("VORBIS")==0): for lib in ('ogg', 'vorbis', 'vorbisfile'): path = GetThirdpartyDir() + "vorbis/lib/lib{0}_static.lib".format(lib) @@ -849,9 +746,6 @@ if (COMPILER == "MSVC"): if (COMPILER=="GCC"): if GetTarget() != "darwin": PkgDisable("COCOA") - elif RUNTIME: - # We don't support Cocoa in the runtime yet. - PkgDisable("COCOA") #if (PkgSkip("PYTHON")==0): # IncDirectory("PYTHON", SDK["PYTHON"]) @@ -877,92 +771,86 @@ if (COMPILER=="GCC"): assimp_libs = ("libassimp", "libassimpd") # Name pkg-config libs, include(dir)s - if (not RUNTIME): - SmartPkgEnable("EIGEN", "eigen3", (), ("Eigen/Dense",), target_pkg = 'ALWAYS') - SmartPkgEnable("ARTOOLKIT", "", ("AR"), "AR/ar.h") - SmartPkgEnable("FCOLLADA", "", ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada/FCollada.h")) - SmartPkgEnable("ASSIMP", "assimp", ChooseLib(assimp_libs, "ASSIMP"), "assimp/Importer.hpp") - SmartPkgEnable("FFMPEG", ffmpeg_libs, ffmpeg_libs, ("libavformat/avformat.h", "libavcodec/avcodec.h", "libavutil/avutil.h")) - SmartPkgEnable("SWSCALE", "libswscale", "libswscale", ("libswscale/swscale.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg") - SmartPkgEnable("SWRESAMPLE","libswresample", "libswresample", ("libswresample/swresample.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg") - SmartPkgEnable("FFTW", "", ("fftw3"), ("fftw.h")) - SmartPkgEnable("FMODEX", "", ("fmodex"), ("fmodex", "fmodex/fmod.h")) - SmartPkgEnable("FREETYPE", "freetype2", ("freetype"), ("freetype2", "freetype2/freetype/freetype.h")) - SmartPkgEnable("HARFBUZZ", "harfbuzz", ("harfbuzz"), ("harfbuzz", "harfbuzz/hb-ft.h")) - SmartPkgEnable("GL", "gl", ("GL"), ("GL/gl.h"), framework = "OpenGL") - SmartPkgEnable("GLES", "glesv1_cm", ("GLESv1_CM"), ("GLES/gl.h"), framework = "OpenGLES") - SmartPkgEnable("GLES2", "glesv2", ("GLESv2"), ("GLES2/gl2.h")) #framework = "OpenGLES"? - SmartPkgEnable("EGL", "egl", ("EGL"), ("EGL/egl.h")) - SmartPkgEnable("NVIDIACG", "", ("Cg"), "Cg/cg.h", framework = "Cg") - SmartPkgEnable("ODE", "", ("ode"), "ode/ode.h", tool = "ode-config") - SmartPkgEnable("OPENAL", "openal", ("openal"), "AL/al.h", framework = "OpenAL") - SmartPkgEnable("SQUISH", "", ("squish"), "squish.h") - SmartPkgEnable("TIFF", "libtiff-4", ("tiff"), "tiff.h") - SmartPkgEnable("OPENEXR", "OpenEXR", ("IlmImf", "Imath", "Half", "Iex", "IexMath", "IlmThread"), ("OpenEXR", "OpenEXR/ImfOutputFile.h")) - SmartPkgEnable("VRPN", "", ("vrpn", "quat"), ("vrpn", "quat.h", "vrpn/vrpn_Types.h")) - SmartPkgEnable("BULLET", "bullet", ("BulletSoftBody", "BulletDynamics", "BulletCollision", "LinearMath"), ("bullet", "bullet/btBulletDynamicsCommon.h")) - SmartPkgEnable("VORBIS", "vorbisfile",("vorbisfile", "vorbis", "ogg"), ("ogg/ogg.h", "vorbis/vorbisfile.h")) - SmartPkgEnable("OPUS", "opusfile", ("opusfile", "opus", "ogg"), ("ogg/ogg.h", "opus/opusfile.h", "opus")) - SmartPkgEnable("JPEG", "", ("jpeg"), "jpeglib.h") - SmartPkgEnable("PNG", "libpng", ("png"), "png.h", tool = "libpng-config") + SmartPkgEnable("EIGEN", "eigen3", (), ("Eigen/Dense",), target_pkg = 'ALWAYS') + SmartPkgEnable("ARTOOLKIT", "", ("AR"), "AR/ar.h") + SmartPkgEnable("FCOLLADA", "", ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada/FCollada.h")) + SmartPkgEnable("ASSIMP", "assimp", ChooseLib(assimp_libs, "ASSIMP"), "assimp/Importer.hpp") + SmartPkgEnable("FFMPEG", ffmpeg_libs, ffmpeg_libs, ("libavformat/avformat.h", "libavcodec/avcodec.h", "libavutil/avutil.h")) + SmartPkgEnable("SWSCALE", "libswscale", "libswscale", ("libswscale/swscale.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg") + SmartPkgEnable("SWRESAMPLE","libswresample", "libswresample", ("libswresample/swresample.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg") + SmartPkgEnable("FFTW", "", ("fftw3"), ("fftw.h")) + SmartPkgEnable("FMODEX", "", ("fmodex"), ("fmodex", "fmodex/fmod.h")) + SmartPkgEnable("FREETYPE", "freetype2", ("freetype"), ("freetype2", "freetype2/freetype/freetype.h")) + SmartPkgEnable("HARFBUZZ", "harfbuzz", ("harfbuzz"), ("harfbuzz", "harfbuzz/hb-ft.h")) + SmartPkgEnable("GL", "gl", ("GL"), ("GL/gl.h"), framework = "OpenGL") + SmartPkgEnable("GLES", "glesv1_cm", ("GLESv1_CM"), ("GLES/gl.h"), framework = "OpenGLES") + SmartPkgEnable("GLES2", "glesv2", ("GLESv2"), ("GLES2/gl2.h")) #framework = "OpenGLES"? + SmartPkgEnable("EGL", "egl", ("EGL"), ("EGL/egl.h")) + SmartPkgEnable("NVIDIACG", "", ("Cg"), "Cg/cg.h", framework = "Cg") + SmartPkgEnable("ODE", "", ("ode"), "ode/ode.h", tool = "ode-config") + SmartPkgEnable("OPENAL", "openal", ("openal"), "AL/al.h", framework = "OpenAL") + SmartPkgEnable("SQUISH", "", ("squish"), "squish.h") + SmartPkgEnable("TIFF", "libtiff-4", ("tiff"), "tiff.h") + SmartPkgEnable("OPENEXR", "OpenEXR", ("IlmImf", "Imath", "Half", "Iex", "IexMath", "IlmThread"), ("OpenEXR", "OpenEXR/ImfOutputFile.h")) + SmartPkgEnable("VRPN", "", ("vrpn", "quat"), ("vrpn", "quat.h", "vrpn/vrpn_Types.h")) + SmartPkgEnable("BULLET", "bullet", ("BulletSoftBody", "BulletDynamics", "BulletCollision", "LinearMath"), ("bullet", "bullet/btBulletDynamicsCommon.h")) + SmartPkgEnable("VORBIS", "vorbisfile",("vorbisfile", "vorbis", "ogg"), ("ogg/ogg.h", "vorbis/vorbisfile.h")) + SmartPkgEnable("OPUS", "opusfile", ("opusfile", "opus", "ogg"), ("ogg/ogg.h", "opus/opusfile.h", "opus")) + SmartPkgEnable("JPEG", "", ("jpeg"), "jpeglib.h") + SmartPkgEnable("PNG", "libpng", ("png"), "png.h", tool = "libpng-config") - if not PkgSkip("FFMPEG"): - if GetTarget() == "darwin": - LibName("FFMPEG", "-framework VideoDecodeAcceleration") - elif os.path.isfile(GetThirdpartyDir() + "ffmpeg/lib/libavcodec.a"): - # Needed when linking ffmpeg statically on Linux. - LibName("FFMPEG", "-Wl,-Bsymbolic") + if not PkgSkip("FFMPEG"): + if GetTarget() == "darwin": + LibName("FFMPEG", "-framework VideoDecodeAcceleration") + elif os.path.isfile(GetThirdpartyDir() + "ffmpeg/lib/libavcodec.a"): + # Needed when linking ffmpeg statically on Linux. + LibName("FFMPEG", "-Wl,-Bsymbolic") - if PkgSkip("FFMPEG") or GetTarget() == "darwin": - cv_lib = ChooseLib(("opencv_core", "cv"), "OPENCV") - if cv_lib == "opencv_core": - OPENCV_VER_23 = True - SmartPkgEnable("OPENCV", "opencv", ("opencv_core", "opencv_highgui"), ("opencv2/core/core.hpp")) - else: - SmartPkgEnable("OPENCV", "opencv", ("cv", "highgui", "cvaux", "ml", "cxcore"), - ("opencv", "opencv/cv.h", "opencv/cxcore.h", "opencv/highgui.h")) + if PkgSkip("FFMPEG") or GetTarget() == "darwin": + cv_lib = ChooseLib(("opencv_core", "cv"), "OPENCV") + if cv_lib == "opencv_core": + OPENCV_VER_23 = True + SmartPkgEnable("OPENCV", "opencv", ("opencv_core", "opencv_highgui"), ("opencv2/core/core.hpp")) else: - PkgDisable("OPENCV") + SmartPkgEnable("OPENCV", "opencv", ("cv", "highgui", "cvaux", "ml", "cxcore"), + ("opencv", "opencv/cv.h", "opencv/cxcore.h", "opencv/highgui.h")) + else: + PkgDisable("OPENCV") - if GetTarget() == "darwin" and not PkgSkip("OPENAL"): - LibName("OPENAL", "-framework AudioToolbox") - LibName("OPENAL", "-framework CoreAudio") + if GetTarget() == "darwin" and not PkgSkip("OPENAL"): + LibName("OPENAL", "-framework AudioToolbox") + LibName("OPENAL", "-framework CoreAudio") - if not PkgSkip("ASSIMP") and \ - os.path.isfile(GetThirdpartyDir() + "assimp/lib/libassimp.a"): - # Also pick up IrrXML, which is needed when linking statically. - irrxml = GetThirdpartyDir() + "assimp/lib/libIrrXML.a" - if os.path.isfile(irrxml): - LibName("ASSIMP", irrxml) + if not PkgSkip("ASSIMP") and \ + os.path.isfile(GetThirdpartyDir() + "assimp/lib/libassimp.a"): + # Also pick up IrrXML, which is needed when linking statically. + irrxml = GetThirdpartyDir() + "assimp/lib/libIrrXML.a" + if os.path.isfile(irrxml): + LibName("ASSIMP", irrxml) - rocket_libs = ("RocketCore", "RocketControls") - if (GetOptimize() <= 3): - rocket_libs += ("RocketDebugger",) - rocket_libs += ("boost_python",) - SmartPkgEnable("ROCKET", "", rocket_libs, "Rocket/Core.h") + rocket_libs = ("RocketCore", "RocketControls") + if (GetOptimize() <= 3): + rocket_libs += ("RocketDebugger",) + rocket_libs += ("boost_python",) + SmartPkgEnable("ROCKET", "", rocket_libs, "Rocket/Core.h") - if not PkgSkip("PYTHON"): - python_lib = SDK["PYTHONVERSION"] - SmartPkgEnable("PYTHON", "", python_lib, (SDK["PYTHONVERSION"], SDK["PYTHONVERSION"] + "/Python.h")) + if not PkgSkip("PYTHON"): + python_lib = SDK["PYTHONVERSION"] + SmartPkgEnable("PYTHON", "", python_lib, (SDK["PYTHONVERSION"], SDK["PYTHONVERSION"] + "/Python.h")) - if GetTarget() == "linux": - LibName("PYTHON", "-lutil") - LibName("PYTHON", "-lrt") + if GetTarget() == "linux": + LibName("PYTHON", "-lutil") + LibName("PYTHON", "-lrt") SmartPkgEnable("OPENSSL", "openssl", ("ssl", "crypto"), ("openssl/ssl.h", "openssl/crypto.h")) SmartPkgEnable("ZLIB", "zlib", ("z"), "zlib.h") SmartPkgEnable("GTK2", "gtk+-2.0") - if (RTDIST): - SmartPkgEnable("WX", tool = "wx-config") - SmartPkgEnable("FLTK", "", ("fltk"), ("FL/Fl.H"), tool = "fltk-config") - if GetTarget() != 'darwin': # CgGL is covered by the Cg framework, and we don't need X11 components on OSX - if not PkgSkip("NVIDIACG") and not RUNTIME: + if not PkgSkip("NVIDIACG"): SmartPkgEnable("CGGL", "", ("CgGL"), "Cg/cgGL.h", thirdparty_dir = "nvidiacg") - if not RUNTIME: - SmartPkgEnable("X11", "x11", "X11", ("X11", "X11/Xlib.h", "X11/XKBlib.h")) + SmartPkgEnable("X11", "x11", "X11", ("X11", "X11/Xlib.h", "X11/XKBlib.h")) if GetHost() != "darwin": # Workaround for an issue where pkg-config does not include this path @@ -980,15 +868,6 @@ if (COMPILER=="GCC"): elif not PkgSkip("X11"): LibDirectory("ALWAYS", "/usr/X11R6/lib") - if RUNTIME: - # For the runtime, these packages are required - for pkg in ["OPENSSL", "ZLIB"]: - skips = [] - if (pkg in PkgListGet() and PkgSkip(pkg)==1): - skips.append(pkg) - if skips: - exit("Runtime must be compiled with OpenSSL and ZLib support (missing %s)" % (', '.join(skips))) - for pkg in MAYAVERSIONS: if (PkgSkip(pkg)==0 and (pkg in SDK)): if (GetHost() == "darwin"): @@ -1118,13 +997,6 @@ def printStatus(header,warnings): else: tkeep = tkeep + x + " " - if RTDIST: - print("Makepanda: Runtime distribution build") - elif RUNTIME: - print("Makepanda: Runtime build") - else: - print("Makepanda: Regular build") - print("Makepanda: Compiler: %s" % (COMPILER)) print("Makepanda: Optimize: %d" % (GetOptimize())) print("Makepanda: Keep Pkg: %s" % (tkeep)) @@ -1135,7 +1007,7 @@ def printStatus(header,warnings): else: print("Makepanda: Don't generate API reference manual") - if GetHost() == "windows" and not RTDIST: + if GetHost() == "windows": if INSTALLER: print("Makepanda: Build installer, using %s" % (COMPRESSOR)) else: @@ -1895,7 +1767,7 @@ def CompileLink(dll, obj, opts): cmd += " " + LDFLAGS # Don't link libraries with Python, except on Android. - if "PYTHON" in opts and GetOrigExt(dll) != ".exe" and not RTDIST and GetTarget() != 'android': + if "PYTHON" in opts and GetOrigExt(dll) != ".exe" and GetTarget() != 'android': opts = opts[:] opts.remove("PYTHON") @@ -2088,67 +1960,6 @@ def FreezePy(target, inputs, opts): if (not os.path.exists(target)): exit("FREEZER_ERROR") -########################################################################################## -# -# Package -# -########################################################################################## - -def Package(target, inputs, opts): - assert len(inputs) == 1 - # Invoke the ppackage script. - command = BracketNameWithQuotes(SDK["PYTHONEXEC"]) + " " - if GetOptimizeOption(opts) >= 4: - command += "-OO " - - if sys.version_info >= (2, 6): - command += "-B " - - command += "direct/src/p3d/ppackage.py" - - if not RTDIST: - # Don't compile Python sources, because we might not running in the same - # Python version as the selected host. - command += " -N" - - if GetTarget() == "darwin": - if SDK.get("MACOSX"): - command += " -R \"%s\"" % SDK["MACOSX"] - - arch = GetTargetArch() - if arch == "x86_64": - arch = "amd64" - command += " -P osx_%s" % arch - - command += " -i \"" + GetOutputDir() + "/stage\"" - if (P3DSUFFIX): - command += ' -a "' + P3DSUFFIX + '"' - - command += " " + inputs[0] - - if GetOrigExt(target) == '.p3d': - # Build a specific .p3d file. - basename = os.path.basename(os.path.splitext(target)[0]) - command += " " + basename - oscmd(command) - - if GetTarget() == 'windows': - # Make an .exe that calls this .p3d. - objfile = FindLocation('p3dWrapper_' + basename + '.obj', []) - CompileCxx(objfile, 'direct/src/p3d/p3dWrapper.c', []) - - exefile = FindLocation(basename + '.exe', []) - CompileLink(exefile, [objfile], ['ADVAPI']) - - # Move it to the bin directory. - os.rename(GetOutputDir() + '/stage/' + basename + P3DSUFFIX + '.p3d', target) - - if sys.platform != 'win32': - oscmd('chmod +x ' + BracketNameWithQuotes(target)) - else: - # This is presumably a package or set of packages. - oscmd(command) - ########################################################################################## # # CompileBundle @@ -2247,12 +2058,6 @@ def CompileAnything(target, inputs, opts, progress = None): elif (infile.endswith(".idl")): ProgressOutput(progress, "Compiling MIDL file", infile) return CompileMIDL(target, infile, opts) - elif (infile.endswith(".pdef")): - if origsuffix == '.p3d': - ProgressOutput(progress, "Building package", target) - else: - ProgressOutput(progress, "Building package from pdef file", infile) - return Package(target, inputs, opts) elif origsuffix in SUFFIX_LIB: ProgressOutput(progress, "Linking static library", target) return CompileLib(target, inputs, opts) @@ -2263,7 +2068,7 @@ def CompileAnything(target, inputs, opts, progress = None): ProgressOutput(progress, "Linking dynamic library", target) # Add version number to the dynamic library, on unix - if origsuffix == ".dll" and "MODULE" not in opts and not RTDIST: + if origsuffix == ".dll" and "MODULE" not in opts: tplatform = GetTarget() if tplatform == "darwin": # On Mac, libraries are named like libpanda.1.2.dylib @@ -2448,7 +2253,6 @@ DTOOL_CONFIG=[ ("PRC_SAVE_DESCRIPTIONS", '1', '1'), # ("_SECURE_SCL", '0', 'UNDEF'), # ("_SECURE_SCL_THROWS", '0', 'UNDEF'), - ("HAVE_P3D_PLUGIN", 'UNDEF', 'UNDEF'), ] PRC_PARAMETERS=[ @@ -2471,7 +2275,6 @@ def WriteConfigSettings(): dtool_config={} prc_parameters={} speedtree_parameters={} - plugin_config={} if (GetTarget() == 'windows'): for key,win,unix in DTOOL_CONFIG: @@ -2577,28 +2380,6 @@ def WriteConfigSettings(): ## if GetTarget() == 'windows' and GetTargetArch() == 'x64': ## dtool_config["SIMPLE_THREADS"] = 'UNDEF' - if (RTDIST or RUNTIME): - prc_parameters["DEFAULT_PRC_DIR"] = '""' - if HOST_URL: - plugin_config["PANDA_PACKAGE_HOST_URL"] = HOST_URL - #plugin_config["P3D_PLUGIN_LOG_DIRECTORY"] = "" - plugin_config["P3D_PLUGIN_LOG_BASENAME1"] = "" - plugin_config["P3D_PLUGIN_LOG_BASENAME2"] = "" - plugin_config["P3D_PLUGIN_LOG_BASENAME3"] = "" - plugin_config["P3D_PLUGIN_P3D_PLUGIN"] = "" - plugin_config["P3D_PLUGIN_P3DPYTHON"] = "" - plugin_config["P3D_COREAPI_VERSION_STR"] = COREAPI_VERSION - plugin_config["P3D_PLUGIN_VERSION_STR"] = PLUGIN_VERSION - if PkgSkip("GTK2") == 0: - plugin_config["HAVE_GTK"] = '1' - - if (RUNTIME): - dtool_config["HAVE_P3D_PLUGIN"] = '1' - - # Whether it's present on the system doesn't matter here, - # as the runtime itself doesn't include or link with X11. - if (RUNTIME and GetTarget() == 'linux'): - dtool_config["HAVE_X11"] = '1' if ("GENERIC_DXERR_LIBRARY" in SDK): dtool_config["USE_GENERIC_DXERR_LIBRARY"] = "1" @@ -2630,14 +2411,6 @@ def WriteConfigSettings(): else: conf = conf + "#define " + key + " " + val + "\n" ConditionalWriteFile(GetOutputDir() + '/include/dtool_config.h', conf) - if (RTDIST or RUNTIME): - conf = "/* p3d_plugin_config.h. Generated automatically by makepanda.py */\n" - for key in sorted(plugin_config.keys()): - val = plugin_config[key] - if (val == 'UNDEF'): conf = conf + "#undef " + key + "\n" - else: conf = conf + "#define " + key + " \"" + val.replace("\\", "\\\\") + "\"\n" - ConditionalWriteFile(GetOutputDir() + '/include/p3d_plugin_config.h', conf) - if (PkgSkip("SPEEDTREE")==0): conf = "/* speedtree_parameters.h. Generated automatically by makepanda.py */\n" for key in sorted(speedtree_parameters.keys()): @@ -2681,24 +2454,6 @@ PANDAVERSION_H=""" #define PANDA_VERSION_STR "$VERSION" #define PANDA_ABI_VERSION_STR "$VERSION1.$VERSION2" #define PANDA_DISTRIBUTOR "$DISTRIBUTOR" -#define PANDA_PACKAGE_VERSION_STR "$RTDIST_VERSION" -#define PANDA_PACKAGE_HOST_URL "$HOST_URL" -""" - -PANDAVERSION_H_RUNTIME=""" -#define PANDA_MAJOR_VERSION 0 -#define PANDA_MINOR_VERSION 0 -#define PANDA_SEQUENCE_VERSION 0 -#define PANDA_VERSION_STR "0.0.0" -#define PANDA_ABI_VERSION_STR "0.0" -#define P3D_PLUGIN_MAJOR_VERSION $VERSION1 -#define P3D_PLUGIN_MINOR_VERSION $VERSION2 -#define P3D_PLUGIN_SEQUENCE_VERSION $VERSION3 -#define P3D_PLUGIN_VERSION_STR "$VERSION1.$VERSION2.$VERSION3" -#define P3D_COREAPI_VERSION_STR "$COREAPI_VERSION" -#define PANDA_DISTRIBUTOR "$DISTRIBUTOR" -#define PANDA_PACKAGE_VERSION_STR "" -#define PANDA_PACKAGE_HOST_URL "$HOST_URL" """ CHECKPANDAVERSION_CXX=""" @@ -2721,65 +2476,6 @@ template class CheckPandaVersion; # endif """ -P3DACTIVEX_RC="""#include "resource.h" -#define APSTUDIO_READONLY_SYMBOLS -#include "afxres.h" -#undef APSTUDIO_READONLY_SYMBOLS -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif -#ifdef APSTUDIO_INVOKED -1 TEXTINCLUDE -BEGIN - "resource.h\\0" -END -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\\r\\n" - "\\0" -END -3 TEXTINCLUDE -BEGIN - "1 TYPELIB ""P3DActiveX.tlb""\\r\\n" - "\\0" -END -#endif -%s -IDB_P3DACTIVEX BITMAP "P3DActiveXCtrl.bmp" -IDD_PROPPAGE_P3DACTIVEX DIALOG 0, 0, 250, 62 -STYLE DS_SETFONT | WS_CHILD -FONT 8, "MS Sans Serif" -BEGIN - LTEXT "TODO: Place controls to manipulate properties of P3DActiveX Control on this dialog.", - IDC_STATIC,7,25,229,16 -END -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_PROPPAGE_P3DACTIVEX, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 243 - TOPMARGIN, 7 - BOTTOMMARGIN, 55 - END -END -#endif -STRINGTABLE -BEGIN - IDS_P3DACTIVEX "P3DActiveX Control" - IDS_P3DACTIVEX_PPG "P3DActiveX Property Page" -END -STRINGTABLE -BEGIN - IDS_P3DACTIVEX_PPG_CAPTION "General" -END -#endif -#ifndef APSTUDIO_INVOKED -1 TYPELIB "P3DActiveX.tlb" -#endif""" def CreatePandaVersionFiles(): version1=int(VERSION.split(".")[0]) @@ -2790,19 +2486,13 @@ def CreatePandaVersionFiles(): # Subtract 1 if we are not an official version. nversion -= 1 - if (RUNTIME): - pandaversion_h = PANDAVERSION_H_RUNTIME - else: - pandaversion_h = PANDAVERSION_H + pandaversion_h = PANDAVERSION_H pandaversion_h = pandaversion_h.replace("$VERSION1",str(version1)) pandaversion_h = pandaversion_h.replace("$VERSION2",str(version2)) pandaversion_h = pandaversion_h.replace("$VERSION3",str(version3)) pandaversion_h = pandaversion_h.replace("$VERSION",VERSION) pandaversion_h = pandaversion_h.replace("$NVERSION",str(nversion)) pandaversion_h = pandaversion_h.replace("$DISTRIBUTOR",DISTRIBUTOR) - pandaversion_h = pandaversion_h.replace("$RTDIST_VERSION",RTDIST_VERSION) - pandaversion_h = pandaversion_h.replace("$COREAPI_VERSION",COREAPI_VERSION) - pandaversion_h = pandaversion_h.replace("$HOST_URL",(HOST_URL or "")) if (DISTRIBUTOR == "cmu"): pandaversion_h += "\n#define PANDA_OFFICIAL_VERSION\n" else: @@ -2811,36 +2501,21 @@ def CreatePandaVersionFiles(): if GIT_COMMIT: pandaversion_h += "\n#define PANDA_GIT_COMMIT_STR \"%s\"\n" % (GIT_COMMIT) - if not RUNTIME: - checkpandaversion_cxx = CHECKPANDAVERSION_CXX.replace("$VERSION1",str(version1)) - checkpandaversion_cxx = checkpandaversion_cxx.replace("$VERSION2",str(version2)) - checkpandaversion_cxx = checkpandaversion_cxx.replace("$VERSION3",str(version3)) - checkpandaversion_cxx = checkpandaversion_cxx.replace("$NVERSION",str(nversion)) + checkpandaversion_cxx = CHECKPANDAVERSION_CXX.replace("$VERSION1",str(version1)) + checkpandaversion_cxx = checkpandaversion_cxx.replace("$VERSION2",str(version2)) + checkpandaversion_cxx = checkpandaversion_cxx.replace("$VERSION3",str(version3)) + checkpandaversion_cxx = checkpandaversion_cxx.replace("$NVERSION",str(nversion)) - checkpandaversion_h = CHECKPANDAVERSION_H.replace("$VERSION1",str(version1)) - checkpandaversion_h = checkpandaversion_h.replace("$VERSION2",str(version2)) - checkpandaversion_h = checkpandaversion_h.replace("$VERSION3",str(version3)) - checkpandaversion_h = checkpandaversion_h.replace("$NVERSION",str(nversion)) + checkpandaversion_h = CHECKPANDAVERSION_H.replace("$VERSION1",str(version1)) + checkpandaversion_h = checkpandaversion_h.replace("$VERSION2",str(version2)) + checkpandaversion_h = checkpandaversion_h.replace("$VERSION3",str(version3)) + checkpandaversion_h = checkpandaversion_h.replace("$NVERSION",str(nversion)) ConditionalWriteFile(GetOutputDir()+'/include/pandaVersion.h', pandaversion_h) - if RUNTIME: - ConditionalWriteFile(GetOutputDir()+'/include/checkPandaVersion.cxx', '') - ConditionalWriteFile(GetOutputDir()+'/include/checkPandaVersion.h', '') - else: - ConditionalWriteFile(GetOutputDir()+'/include/checkPandaVersion.cxx', checkpandaversion_cxx) - ConditionalWriteFile(GetOutputDir()+'/include/checkPandaVersion.h', checkpandaversion_h) + ConditionalWriteFile(GetOutputDir()+'/include/checkPandaVersion.cxx', checkpandaversion_cxx) + ConditionalWriteFile(GetOutputDir()+'/include/checkPandaVersion.h', checkpandaversion_h) ConditionalWriteFile(GetOutputDir()+"/tmp/null.cxx","") - if RUNTIME: - p3dactivex_rc = {"name" : "Panda3D Game Engine Plug-in", - "version" : VERSION, - "description" : "Runs 3-D games and interactive applets", - "filename" : "p3dactivex.ocx", - "mimetype" : "application/x-panda3d", - "extension" : "p3d", - "filedesc" : "Panda3D applet"} - ConditionalWriteFile(GetOutputDir()+"/include/P3DActiveX.rc", P3DACTIVEX_RC % GenerateResourceFile(**p3dactivex_rc)) - CreatePandaVersionFiles() ########################################################################################## @@ -3145,7 +2820,7 @@ if tp_dir is not None: if os.path.isdir(os.path.join(tp_dir, "extras", "bin")): CopyAllFiles(GetOutputDir() + "/bin/", tp_dir + "extras/bin/") - if not PkgSkip("PYTHON") and not RTDIST: + if not PkgSkip("PYTHON"): # We need to copy the Python DLL to the bin directory for now. pydll = "/" + SDK["PYTHONVERSION"].replace(".", "") if GetOptimize() <= 2: @@ -3384,12 +3059,6 @@ if (PkgSkip("DIRECT")==0): CopyAllHeaders('direct/src/showbase') CopyAllHeaders('direct/src/dcparse') -if (RUNTIME or RTDIST): - CopyAllHeaders('direct/src/plugin', skip=["p3d_plugin_config.h"]) -if (RUNTIME): - CopyAllHeaders('direct/src/plugin_npapi') - CopyAllHeaders('direct/src/plugin_standalone') - if (PkgSkip("PANDATOOL")==0): CopyAllHeaders('pandatool/src/pandatoolbase') CopyAllHeaders('pandatool/src/converter') @@ -3524,16 +3193,15 @@ TargetAdd('libp3dtool.dll', opts=['ADVAPI','WINSHELL','WINKERNEL']) # DIRECTORY: dtool/src/cppparser/ # -if (not RUNTIME): - OPTS=['DIR:dtool/src/cppparser', 'BISONPREFIX_cppyy'] - CreateFile(GetOutputDir()+"/include/cppBison.h") - TargetAdd('p3cppParser_cppBison.obj', opts=OPTS, input='cppBison.yxx') - TargetAdd('cppBison.h', input='p3cppParser_cppBison.obj', opts=['DEPENDENCYONLY']) - TargetAdd('p3cppParser_composite1.obj', opts=OPTS, input='p3cppParser_composite1.cxx') - TargetAdd('p3cppParser_composite2.obj', opts=OPTS, input='p3cppParser_composite2.cxx') - TargetAdd('libp3cppParser.ilb', input='p3cppParser_composite1.obj') - TargetAdd('libp3cppParser.ilb', input='p3cppParser_composite2.obj') - TargetAdd('libp3cppParser.ilb', input='p3cppParser_cppBison.obj') +OPTS=['DIR:dtool/src/cppparser', 'BISONPREFIX_cppyy'] +CreateFile(GetOutputDir()+"/include/cppBison.h") +TargetAdd('p3cppParser_cppBison.obj', opts=OPTS, input='cppBison.yxx') +TargetAdd('cppBison.h', input='p3cppParser_cppBison.obj', opts=['DEPENDENCYONLY']) +TargetAdd('p3cppParser_composite1.obj', opts=OPTS, input='p3cppParser_composite1.cxx') +TargetAdd('p3cppParser_composite2.obj', opts=OPTS, input='p3cppParser_composite2.cxx') +TargetAdd('libp3cppParser.ilb', input='p3cppParser_composite1.obj') +TargetAdd('libp3cppParser.ilb', input='p3cppParser_composite2.obj') +TargetAdd('libp3cppParser.ilb', input='p3cppParser_cppBison.obj') # # DIRECTORY: dtool/src/prc/ @@ -3580,45 +3248,43 @@ PyTargetAdd('interrogatedb.pyd', input='libp3interrogatedb.dll') # DIRECTORY: dtool/src/interrogate/ # -if (not RUNTIME): - OPTS=['DIR:dtool/src/interrogate', 'DIR:dtool/src/cppparser', 'DIR:dtool/src/interrogatedb'] - TargetAdd('interrogate_composite1.obj', opts=OPTS, input='interrogate_composite1.cxx') - TargetAdd('interrogate_composite2.obj', opts=OPTS, input='interrogate_composite2.cxx') - TargetAdd('interrogate.exe', input='interrogate_composite1.obj') - TargetAdd('interrogate.exe', input='interrogate_composite2.obj') - TargetAdd('interrogate.exe', input='libp3cppParser.ilb') - TargetAdd('interrogate.exe', input=COMMON_DTOOL_LIBS) - TargetAdd('interrogate.exe', input='libp3interrogatedb.dll') - TargetAdd('interrogate.exe', opts=['ADVAPI', 'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER']) +OPTS=['DIR:dtool/src/interrogate', 'DIR:dtool/src/cppparser', 'DIR:dtool/src/interrogatedb'] +TargetAdd('interrogate_composite1.obj', opts=OPTS, input='interrogate_composite1.cxx') +TargetAdd('interrogate_composite2.obj', opts=OPTS, input='interrogate_composite2.cxx') +TargetAdd('interrogate.exe', input='interrogate_composite1.obj') +TargetAdd('interrogate.exe', input='interrogate_composite2.obj') +TargetAdd('interrogate.exe', input='libp3cppParser.ilb') +TargetAdd('interrogate.exe', input=COMMON_DTOOL_LIBS) +TargetAdd('interrogate.exe', input='libp3interrogatedb.dll') +TargetAdd('interrogate.exe', opts=['ADVAPI', 'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER']) - preamble = WriteEmbeddedStringFile('interrogate_preamble_python_native', inputs=[ - 'dtool/src/interrogatedb/py_panda.cxx', - 'dtool/src/interrogatedb/py_compat.cxx', - 'dtool/src/interrogatedb/py_wrappers.cxx', - 'dtool/src/interrogatedb/dtool_super_base.cxx', - ]) - TargetAdd('interrogate_module_preamble_python_native.obj', opts=OPTS, input=preamble) - TargetAdd('interrogate_module_interrogate_module.obj', opts=OPTS, input='interrogate_module.cxx') - TargetAdd('interrogate_module.exe', input='interrogate_module_interrogate_module.obj') - TargetAdd('interrogate_module.exe', input='interrogate_module_preamble_python_native.obj') - TargetAdd('interrogate_module.exe', input='libp3cppParser.ilb') - TargetAdd('interrogate_module.exe', input=COMMON_DTOOL_LIBS) - TargetAdd('interrogate_module.exe', input='libp3interrogatedb.dll') - TargetAdd('interrogate_module.exe', opts=['ADVAPI', 'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER']) +preamble = WriteEmbeddedStringFile('interrogate_preamble_python_native', inputs=[ +'dtool/src/interrogatedb/py_panda.cxx', +'dtool/src/interrogatedb/py_compat.cxx', +'dtool/src/interrogatedb/py_wrappers.cxx', +'dtool/src/interrogatedb/dtool_super_base.cxx', +]) +TargetAdd('interrogate_module_preamble_python_native.obj', opts=OPTS, input=preamble) +TargetAdd('interrogate_module_interrogate_module.obj', opts=OPTS, input='interrogate_module.cxx') +TargetAdd('interrogate_module.exe', input='interrogate_module_interrogate_module.obj') +TargetAdd('interrogate_module.exe', input='interrogate_module_preamble_python_native.obj') +TargetAdd('interrogate_module.exe', input='libp3cppParser.ilb') +TargetAdd('interrogate_module.exe', input=COMMON_DTOOL_LIBS) +TargetAdd('interrogate_module.exe', input='libp3interrogatedb.dll') +TargetAdd('interrogate_module.exe', opts=['ADVAPI', 'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER']) - if (not RTDIST): - TargetAdd('parse_file_parse_file.obj', opts=OPTS, input='parse_file.cxx') - TargetAdd('parse_file.exe', input='parse_file_parse_file.obj') - TargetAdd('parse_file.exe', input='libp3cppParser.ilb') - TargetAdd('parse_file.exe', input=COMMON_DTOOL_LIBS) - TargetAdd('parse_file.exe', input='libp3interrogatedb.dll') - TargetAdd('parse_file.exe', opts=['ADVAPI', 'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER']) +TargetAdd('parse_file_parse_file.obj', opts=OPTS, input='parse_file.cxx') +TargetAdd('parse_file.exe', input='parse_file_parse_file.obj') +TargetAdd('parse_file.exe', input='libp3cppParser.ilb') +TargetAdd('parse_file.exe', input=COMMON_DTOOL_LIBS) +TargetAdd('parse_file.exe', input='libp3interrogatedb.dll') +TargetAdd('parse_file.exe', opts=['ADVAPI', 'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER']) # # DIRECTORY: dtool/src/prckeys/ # -if (PkgSkip("OPENSSL")==0 and not RUNTIME and not RTDIST): +if (PkgSkip("OPENSSL")==0): OPTS=['DIR:dtool/src/prckeys', 'OPENSSL'] TargetAdd('make-prc-key_makePrcKey.obj', opts=OPTS, input='makePrcKey.cxx') TargetAdd('make-prc-key.exe', input='make-prc-key_makePrcKey.obj') @@ -3629,13 +3295,12 @@ if (PkgSkip("OPENSSL")==0 and not RUNTIME and not RTDIST): # DIRECTORY: dtool/src/test_interrogate/ # -if (not RTDIST and not RUNTIME): - OPTS=['DIR:dtool/src/test_interrogate'] - TargetAdd('test_interrogate_test_interrogate.obj', opts=OPTS, input='test_interrogate.cxx') - TargetAdd('test_interrogate.exe', input='test_interrogate_test_interrogate.obj') - TargetAdd('test_interrogate.exe', input='libp3interrogatedb.dll') - TargetAdd('test_interrogate.exe', input=COMMON_DTOOL_LIBS) - TargetAdd('test_interrogate.exe', opts=['ADVAPI', 'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER']) +OPTS=['DIR:dtool/src/test_interrogate'] +TargetAdd('test_interrogate_test_interrogate.obj', opts=OPTS, input='test_interrogate.cxx') +TargetAdd('test_interrogate.exe', input='test_interrogate_test_interrogate.obj') +TargetAdd('test_interrogate.exe', input='libp3interrogatedb.dll') +TargetAdd('test_interrogate.exe', input=COMMON_DTOOL_LIBS) +TargetAdd('test_interrogate.exe', opts=['ADVAPI', 'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER']) # # DIRECTORY: dtool/src/dtoolbase/ @@ -3742,320 +3407,295 @@ TargetAdd('libpandaexpress.dll', opts=['ADVAPI', 'WINSOCK2', 'OPENSSL', 'ZLIB', # DIRECTORY: panda/src/pipeline/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/pipeline', 'BUILDING:PANDA'] - TargetAdd('p3pipeline_composite1.obj', opts=OPTS, input='p3pipeline_composite1.cxx') - TargetAdd('p3pipeline_composite2.obj', opts=OPTS, input='p3pipeline_composite2.cxx') - TargetAdd('p3pipeline_contextSwitch.obj', opts=OPTS, input='contextSwitch.c') +OPTS=['DIR:panda/src/pipeline', 'BUILDING:PANDA'] +TargetAdd('p3pipeline_composite1.obj', opts=OPTS, input='p3pipeline_composite1.cxx') +TargetAdd('p3pipeline_composite2.obj', opts=OPTS, input='p3pipeline_composite2.cxx') +TargetAdd('p3pipeline_contextSwitch.obj', opts=OPTS, input='contextSwitch.c') - OPTS=['DIR:panda/src/pipeline'] - IGATEFILES=GetDirectoryContents('panda/src/pipeline', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3pipeline.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3pipeline.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pipeline', 'SRCDIR:panda/src/pipeline']) - PyTargetAdd('p3pipeline_pythonThread.obj', opts=OPTS, input='pythonThread.cxx') +OPTS=['DIR:panda/src/pipeline'] +IGATEFILES=GetDirectoryContents('panda/src/pipeline', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3pipeline.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3pipeline.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pipeline', 'SRCDIR:panda/src/pipeline']) +PyTargetAdd('p3pipeline_pythonThread.obj', opts=OPTS, input='pythonThread.cxx') # # DIRECTORY: panda/src/linmath/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/linmath', 'BUILDING:PANDA'] - TargetAdd('p3linmath_composite1.obj', opts=OPTS, input='p3linmath_composite1.cxx') - TargetAdd('p3linmath_composite2.obj', opts=OPTS, input='p3linmath_composite2.cxx') +OPTS=['DIR:panda/src/linmath', 'BUILDING:PANDA'] +TargetAdd('p3linmath_composite1.obj', opts=OPTS, input='p3linmath_composite1.cxx') +TargetAdd('p3linmath_composite2.obj', opts=OPTS, input='p3linmath_composite2.cxx') - OPTS=['DIR:panda/src/linmath'] - IGATEFILES=GetDirectoryContents('panda/src/linmath', ["*.h", "*_composite*.cxx"]) - for ifile in IGATEFILES[:]: - if "_src." in ifile: - IGATEFILES.remove(ifile) - IGATEFILES.remove('cast_to_double.h') - IGATEFILES.remove('lmat_ops.h') - IGATEFILES.remove('cast_to_float.h') - TargetAdd('libp3linmath.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3linmath.in', opts=['IMOD:panda3d.core', 'ILIB:libp3linmath', 'SRCDIR:panda/src/linmath']) +OPTS=['DIR:panda/src/linmath'] +IGATEFILES=GetDirectoryContents('panda/src/linmath', ["*.h", "*_composite*.cxx"]) +for ifile in IGATEFILES[:]: + if "_src." in ifile: + IGATEFILES.remove(ifile) +IGATEFILES.remove('cast_to_double.h') +IGATEFILES.remove('lmat_ops.h') +IGATEFILES.remove('cast_to_float.h') +TargetAdd('libp3linmath.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3linmath.in', opts=['IMOD:panda3d.core', 'ILIB:libp3linmath', 'SRCDIR:panda/src/linmath']) # # DIRECTORY: panda/src/putil/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/putil', 'BUILDING:PANDA', 'ZLIB'] - TargetAdd('p3putil_composite1.obj', opts=OPTS, input='p3putil_composite1.cxx') - TargetAdd('p3putil_composite2.obj', opts=OPTS, input='p3putil_composite2.cxx') +OPTS=['DIR:panda/src/putil', 'BUILDING:PANDA', 'ZLIB'] +TargetAdd('p3putil_composite1.obj', opts=OPTS, input='p3putil_composite1.cxx') +TargetAdd('p3putil_composite2.obj', opts=OPTS, input='p3putil_composite2.cxx') - OPTS=['DIR:panda/src/putil', 'ZLIB'] - IGATEFILES=GetDirectoryContents('panda/src/putil', ["*.h", "*_composite*.cxx"]) - IGATEFILES.remove("test_bam.h") - IGATEFILES.remove("config_util.h") - TargetAdd('libp3putil.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3putil.in', opts=['IMOD:panda3d.core', 'ILIB:libp3putil', 'SRCDIR:panda/src/putil']) - PyTargetAdd('p3putil_ext_composite.obj', opts=OPTS, input='p3putil_ext_composite.cxx') +OPTS=['DIR:panda/src/putil', 'ZLIB'] +IGATEFILES=GetDirectoryContents('panda/src/putil', ["*.h", "*_composite*.cxx"]) +IGATEFILES.remove("test_bam.h") +IGATEFILES.remove("config_util.h") +TargetAdd('libp3putil.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3putil.in', opts=['IMOD:panda3d.core', 'ILIB:libp3putil', 'SRCDIR:panda/src/putil']) +PyTargetAdd('p3putil_ext_composite.obj', opts=OPTS, input='p3putil_ext_composite.cxx') # # DIRECTORY: panda/src/audio/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/audio', 'BUILDING:PANDA'] - TargetAdd('p3audio_composite1.obj', opts=OPTS, input='p3audio_composite1.cxx') +OPTS=['DIR:panda/src/audio', 'BUILDING:PANDA'] +TargetAdd('p3audio_composite1.obj', opts=OPTS, input='p3audio_composite1.cxx') - OPTS=['DIR:panda/src/audio'] - IGATEFILES=["audio.h"] - TargetAdd('libp3audio.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3audio.in', opts=['IMOD:panda3d.core', 'ILIB:libp3audio', 'SRCDIR:panda/src/audio']) +OPTS=['DIR:panda/src/audio'] +IGATEFILES=["audio.h"] +TargetAdd('libp3audio.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3audio.in', opts=['IMOD:panda3d.core', 'ILIB:libp3audio', 'SRCDIR:panda/src/audio']) # # DIRECTORY: panda/src/event/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/event', 'BUILDING:PANDA'] - TargetAdd('p3event_composite1.obj', opts=OPTS, input='p3event_composite1.cxx') - TargetAdd('p3event_composite2.obj', opts=OPTS, input='p3event_composite2.cxx') +OPTS=['DIR:panda/src/event', 'BUILDING:PANDA'] +TargetAdd('p3event_composite1.obj', opts=OPTS, input='p3event_composite1.cxx') +TargetAdd('p3event_composite2.obj', opts=OPTS, input='p3event_composite2.cxx') - OPTS=['DIR:panda/src/event'] - PyTargetAdd('p3event_asyncFuture_ext.obj', opts=OPTS, input='asyncFuture_ext.cxx') - PyTargetAdd('p3event_pythonTask.obj', opts=OPTS, input='pythonTask.cxx') - IGATEFILES=GetDirectoryContents('panda/src/event', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3event.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3event.in', opts=['IMOD:panda3d.core', 'ILIB:libp3event', 'SRCDIR:panda/src/event']) +OPTS=['DIR:panda/src/event'] +PyTargetAdd('p3event_asyncFuture_ext.obj', opts=OPTS, input='asyncFuture_ext.cxx') +PyTargetAdd('p3event_pythonTask.obj', opts=OPTS, input='pythonTask.cxx') +IGATEFILES=GetDirectoryContents('panda/src/event', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3event.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3event.in', opts=['IMOD:panda3d.core', 'ILIB:libp3event', 'SRCDIR:panda/src/event']) # # DIRECTORY: panda/src/mathutil/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/mathutil', 'BUILDING:PANDA', 'FFTW'] - TargetAdd('p3mathutil_composite1.obj', opts=OPTS, input='p3mathutil_composite1.cxx') - TargetAdd('p3mathutil_composite2.obj', opts=OPTS, input='p3mathutil_composite2.cxx') +OPTS=['DIR:panda/src/mathutil', 'BUILDING:PANDA', 'FFTW'] +TargetAdd('p3mathutil_composite1.obj', opts=OPTS, input='p3mathutil_composite1.cxx') +TargetAdd('p3mathutil_composite2.obj', opts=OPTS, input='p3mathutil_composite2.cxx') - OPTS=['DIR:panda/src/mathutil', 'FFTW'] - IGATEFILES=GetDirectoryContents('panda/src/mathutil', ["*.h", "*_composite*.cxx"]) - for ifile in IGATEFILES[:]: - if "_src." in ifile: - IGATEFILES.remove(ifile) - TargetAdd('libp3mathutil.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3mathutil.in', opts=['IMOD:panda3d.core', 'ILIB:libp3mathutil', 'SRCDIR:panda/src/mathutil']) +OPTS=['DIR:panda/src/mathutil', 'FFTW'] +IGATEFILES=GetDirectoryContents('panda/src/mathutil', ["*.h", "*_composite*.cxx"]) +for ifile in IGATEFILES[:]: + if "_src." in ifile: + IGATEFILES.remove(ifile) +TargetAdd('libp3mathutil.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3mathutil.in', opts=['IMOD:panda3d.core', 'ILIB:libp3mathutil', 'SRCDIR:panda/src/mathutil']) # # DIRECTORY: panda/src/gsgbase/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/gsgbase', 'BUILDING:PANDA'] - TargetAdd('p3gsgbase_composite1.obj', opts=OPTS, input='p3gsgbase_composite1.cxx') +OPTS=['DIR:panda/src/gsgbase', 'BUILDING:PANDA'] +TargetAdd('p3gsgbase_composite1.obj', opts=OPTS, input='p3gsgbase_composite1.cxx') - OPTS=['DIR:panda/src/gsgbase'] - IGATEFILES=GetDirectoryContents('panda/src/gsgbase', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3gsgbase.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3gsgbase.in', opts=['IMOD:panda3d.core', 'ILIB:libp3gsgbase', 'SRCDIR:panda/src/gsgbase']) +OPTS=['DIR:panda/src/gsgbase'] +IGATEFILES=GetDirectoryContents('panda/src/gsgbase', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3gsgbase.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3gsgbase.in', opts=['IMOD:panda3d.core', 'ILIB:libp3gsgbase', 'SRCDIR:panda/src/gsgbase']) # # DIRECTORY: panda/src/pnmimage/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/pnmimage', 'BUILDING:PANDA', 'ZLIB'] - TargetAdd('p3pnmimage_composite1.obj', opts=OPTS, input='p3pnmimage_composite1.cxx') - TargetAdd('p3pnmimage_composite2.obj', opts=OPTS, input='p3pnmimage_composite2.cxx') - TargetAdd('p3pnmimage_convert_srgb_sse2.obj', opts=OPTS+['SSE2'], input='convert_srgb_sse2.cxx') +OPTS=['DIR:panda/src/pnmimage', 'BUILDING:PANDA', 'ZLIB'] +TargetAdd('p3pnmimage_composite1.obj', opts=OPTS, input='p3pnmimage_composite1.cxx') +TargetAdd('p3pnmimage_composite2.obj', opts=OPTS, input='p3pnmimage_composite2.cxx') +TargetAdd('p3pnmimage_convert_srgb_sse2.obj', opts=OPTS+['SSE2'], input='convert_srgb_sse2.cxx') - OPTS=['DIR:panda/src/pnmimage', 'ZLIB'] - IGATEFILES=GetDirectoryContents('panda/src/pnmimage', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3pnmimage.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3pnmimage.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pnmimage', 'SRCDIR:panda/src/pnmimage']) - PyTargetAdd('p3pnmimage_pfmFile_ext.obj', opts=OPTS, input='pfmFile_ext.cxx') +OPTS=['DIR:panda/src/pnmimage', 'ZLIB'] +IGATEFILES=GetDirectoryContents('panda/src/pnmimage', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3pnmimage.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3pnmimage.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pnmimage', 'SRCDIR:panda/src/pnmimage']) +PyTargetAdd('p3pnmimage_pfmFile_ext.obj', opts=OPTS, input='pfmFile_ext.cxx') # # DIRECTORY: panda/src/nativenet/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/nativenet', 'OPENSSL', 'BUILDING:PANDA'] - TargetAdd('p3nativenet_composite1.obj', opts=OPTS, input='p3nativenet_composite1.cxx') +OPTS=['DIR:panda/src/nativenet', 'OPENSSL', 'BUILDING:PANDA'] +TargetAdd('p3nativenet_composite1.obj', opts=OPTS, input='p3nativenet_composite1.cxx') - OPTS=['DIR:panda/src/nativenet', 'OPENSSL'] - IGATEFILES=GetDirectoryContents('panda/src/nativenet', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3nativenet.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3nativenet.in', opts=['IMOD:panda3d.core', 'ILIB:libp3nativenet', 'SRCDIR:panda/src/nativenet']) +OPTS=['DIR:panda/src/nativenet', 'OPENSSL'] +IGATEFILES=GetDirectoryContents('panda/src/nativenet', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3nativenet.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3nativenet.in', opts=['IMOD:panda3d.core', 'ILIB:libp3nativenet', 'SRCDIR:panda/src/nativenet']) # # DIRECTORY: panda/src/net/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/net', 'BUILDING:PANDA'] - TargetAdd('p3net_composite1.obj', opts=OPTS, input='p3net_composite1.cxx') - TargetAdd('p3net_composite2.obj', opts=OPTS, input='p3net_composite2.cxx') +OPTS=['DIR:panda/src/net', 'BUILDING:PANDA'] +TargetAdd('p3net_composite1.obj', opts=OPTS, input='p3net_composite1.cxx') +TargetAdd('p3net_composite2.obj', opts=OPTS, input='p3net_composite2.cxx') - OPTS=['DIR:panda/src/net'] - IGATEFILES=GetDirectoryContents('panda/src/net', ["*.h", "*_composite*.cxx"]) - IGATEFILES.remove("datagram_ui.h") - TargetAdd('libp3net.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3net.in', opts=['IMOD:panda3d.core', 'ILIB:libp3net', 'SRCDIR:panda/src/net']) +OPTS=['DIR:panda/src/net'] +IGATEFILES=GetDirectoryContents('panda/src/net', ["*.h", "*_composite*.cxx"]) +IGATEFILES.remove("datagram_ui.h") +TargetAdd('libp3net.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3net.in', opts=['IMOD:panda3d.core', 'ILIB:libp3net', 'SRCDIR:panda/src/net']) # # DIRECTORY: panda/src/pstatclient/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/pstatclient', 'BUILDING:PANDA'] - TargetAdd('p3pstatclient_composite1.obj', opts=OPTS, input='p3pstatclient_composite1.cxx') - TargetAdd('p3pstatclient_composite2.obj', opts=OPTS, input='p3pstatclient_composite2.cxx') +OPTS=['DIR:panda/src/pstatclient', 'BUILDING:PANDA'] +TargetAdd('p3pstatclient_composite1.obj', opts=OPTS, input='p3pstatclient_composite1.cxx') +TargetAdd('p3pstatclient_composite2.obj', opts=OPTS, input='p3pstatclient_composite2.cxx') - OPTS=['DIR:panda/src/pstatclient'] - IGATEFILES=GetDirectoryContents('panda/src/pstatclient', ["*.h", "*_composite*.cxx"]) - IGATEFILES.remove("config_pstats.h") - TargetAdd('libp3pstatclient.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3pstatclient.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pstatclient', 'SRCDIR:panda/src/pstatclient']) +OPTS=['DIR:panda/src/pstatclient'] +IGATEFILES=GetDirectoryContents('panda/src/pstatclient', ["*.h", "*_composite*.cxx"]) +IGATEFILES.remove("config_pstats.h") +TargetAdd('libp3pstatclient.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3pstatclient.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pstatclient', 'SRCDIR:panda/src/pstatclient']) # # DIRECTORY: panda/src/gobj/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/gobj', 'BUILDING:PANDA', 'NVIDIACG', 'ZLIB', 'SQUISH'] - TargetAdd('p3gobj_composite1.obj', opts=OPTS, input='p3gobj_composite1.cxx') - TargetAdd('p3gobj_composite2.obj', opts=OPTS+['BIGOBJ'], input='p3gobj_composite2.cxx') +OPTS=['DIR:panda/src/gobj', 'BUILDING:PANDA', 'NVIDIACG', 'ZLIB', 'SQUISH'] +TargetAdd('p3gobj_composite1.obj', opts=OPTS, input='p3gobj_composite1.cxx') +TargetAdd('p3gobj_composite2.obj', opts=OPTS+['BIGOBJ'], input='p3gobj_composite2.cxx') - OPTS=['DIR:panda/src/gobj', 'NVIDIACG', 'ZLIB', 'SQUISH'] - IGATEFILES=GetDirectoryContents('panda/src/gobj', ["*.h", "*_composite*.cxx"]) - if ("cgfx_states.h" in IGATEFILES): IGATEFILES.remove("cgfx_states.h") - TargetAdd('libp3gobj.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3gobj.in', opts=['IMOD:panda3d.core', 'ILIB:libp3gobj', 'SRCDIR:panda/src/gobj']) - PyTargetAdd('p3gobj_ext_composite.obj', opts=OPTS, input='p3gobj_ext_composite.cxx') +OPTS=['DIR:panda/src/gobj', 'NVIDIACG', 'ZLIB', 'SQUISH'] +IGATEFILES=GetDirectoryContents('panda/src/gobj', ["*.h", "*_composite*.cxx"]) +if ("cgfx_states.h" in IGATEFILES): IGATEFILES.remove("cgfx_states.h") +TargetAdd('libp3gobj.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3gobj.in', opts=['IMOD:panda3d.core', 'ILIB:libp3gobj', 'SRCDIR:panda/src/gobj']) +PyTargetAdd('p3gobj_ext_composite.obj', opts=OPTS, input='p3gobj_ext_composite.cxx') # # DIRECTORY: panda/src/pgraphnodes/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/pgraphnodes', 'BUILDING:PANDA'] - TargetAdd('p3pgraphnodes_composite1.obj', opts=OPTS, input='p3pgraphnodes_composite1.cxx') - TargetAdd('p3pgraphnodes_composite2.obj', opts=OPTS, input='p3pgraphnodes_composite2.cxx') +OPTS=['DIR:panda/src/pgraphnodes', 'BUILDING:PANDA'] +TargetAdd('p3pgraphnodes_composite1.obj', opts=OPTS, input='p3pgraphnodes_composite1.cxx') +TargetAdd('p3pgraphnodes_composite2.obj', opts=OPTS, input='p3pgraphnodes_composite2.cxx') - OPTS=['DIR:panda/src/pgraphnodes'] - IGATEFILES=GetDirectoryContents('panda/src/pgraphnodes', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3pgraphnodes.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3pgraphnodes.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pgraphnodes', 'SRCDIR:panda/src/pgraphnodes']) +OPTS=['DIR:panda/src/pgraphnodes'] +IGATEFILES=GetDirectoryContents('panda/src/pgraphnodes', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3pgraphnodes.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3pgraphnodes.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pgraphnodes', 'SRCDIR:panda/src/pgraphnodes']) # # DIRECTORY: panda/src/pgraph/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/pgraph', 'BUILDING:PANDA'] - TargetAdd('p3pgraph_nodePath.obj', opts=OPTS, input='nodePath.cxx') - TargetAdd('p3pgraph_composite1.obj', opts=OPTS, input='p3pgraph_composite1.cxx') - TargetAdd('p3pgraph_composite2.obj', opts=OPTS, input='p3pgraph_composite2.cxx') - TargetAdd('p3pgraph_composite3.obj', opts=OPTS, input='p3pgraph_composite3.cxx') - TargetAdd('p3pgraph_composite4.obj', opts=OPTS, input='p3pgraph_composite4.cxx') +OPTS=['DIR:panda/src/pgraph', 'BUILDING:PANDA'] +TargetAdd('p3pgraph_nodePath.obj', opts=OPTS, input='nodePath.cxx') +TargetAdd('p3pgraph_composite1.obj', opts=OPTS, input='p3pgraph_composite1.cxx') +TargetAdd('p3pgraph_composite2.obj', opts=OPTS, input='p3pgraph_composite2.cxx') +TargetAdd('p3pgraph_composite3.obj', opts=OPTS, input='p3pgraph_composite3.cxx') +TargetAdd('p3pgraph_composite4.obj', opts=OPTS, input='p3pgraph_composite4.cxx') - OPTS=['DIR:panda/src/pgraph'] - IGATEFILES=GetDirectoryContents('panda/src/pgraph', ["*.h", "nodePath.cxx", "*_composite*.cxx"]) - TargetAdd('libp3pgraph.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3pgraph.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pgraph', 'SRCDIR:panda/src/pgraph']) - PyTargetAdd('p3pgraph_ext_composite.obj', opts=OPTS, input='p3pgraph_ext_composite.cxx') +OPTS=['DIR:panda/src/pgraph'] +IGATEFILES=GetDirectoryContents('panda/src/pgraph', ["*.h", "nodePath.cxx", "*_composite*.cxx"]) +TargetAdd('libp3pgraph.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3pgraph.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pgraph', 'SRCDIR:panda/src/pgraph']) +PyTargetAdd('p3pgraph_ext_composite.obj', opts=OPTS, input='p3pgraph_ext_composite.cxx') # # DIRECTORY: panda/src/cull/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/cull', 'BUILDING:PANDA'] - TargetAdd('p3cull_composite1.obj', opts=OPTS, input='p3cull_composite1.cxx') - TargetAdd('p3cull_composite2.obj', opts=OPTS, input='p3cull_composite2.cxx') +OPTS=['DIR:panda/src/cull', 'BUILDING:PANDA'] +TargetAdd('p3cull_composite1.obj', opts=OPTS, input='p3cull_composite1.cxx') +TargetAdd('p3cull_composite2.obj', opts=OPTS, input='p3cull_composite2.cxx') - OPTS=['DIR:panda/src/cull'] - IGATEFILES=GetDirectoryContents('panda/src/cull', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3cull.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3cull.in', opts=['IMOD:panda3d.core', 'ILIB:libp3cull', 'SRCDIR:panda/src/cull']) +OPTS=['DIR:panda/src/cull'] +IGATEFILES=GetDirectoryContents('panda/src/cull', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3cull.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3cull.in', opts=['IMOD:panda3d.core', 'ILIB:libp3cull', 'SRCDIR:panda/src/cull']) # # DIRECTORY: panda/src/dgraph/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/dgraph', 'BUILDING:PANDA'] - TargetAdd('p3dgraph_composite1.obj', opts=OPTS, input='p3dgraph_composite1.cxx') - TargetAdd('p3dgraph_composite2.obj', opts=OPTS, input='p3dgraph_composite2.cxx') +OPTS=['DIR:panda/src/dgraph', 'BUILDING:PANDA'] +TargetAdd('p3dgraph_composite1.obj', opts=OPTS, input='p3dgraph_composite1.cxx') +TargetAdd('p3dgraph_composite2.obj', opts=OPTS, input='p3dgraph_composite2.cxx') - OPTS=['DIR:panda/src/dgraph'] - IGATEFILES=GetDirectoryContents('panda/src/dgraph', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3dgraph.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3dgraph.in', opts=['IMOD:panda3d.core', 'ILIB:libp3dgraph', 'SRCDIR:panda/src/dgraph']) +OPTS=['DIR:panda/src/dgraph'] +IGATEFILES=GetDirectoryContents('panda/src/dgraph', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3dgraph.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3dgraph.in', opts=['IMOD:panda3d.core', 'ILIB:libp3dgraph', 'SRCDIR:panda/src/dgraph']) # # DIRECTORY: panda/src/device/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/device', 'BUILDING:PANDA'] - TargetAdd('p3device_composite1.obj', opts=OPTS, input='p3device_composite1.cxx') - TargetAdd('p3device_composite2.obj', opts=OPTS, input='p3device_composite2.cxx') +OPTS=['DIR:panda/src/device', 'BUILDING:PANDA'] +TargetAdd('p3device_composite1.obj', opts=OPTS, input='p3device_composite1.cxx') +TargetAdd('p3device_composite2.obj', opts=OPTS, input='p3device_composite2.cxx') - OPTS=['DIR:panda/src/device'] - IGATEFILES=GetDirectoryContents('panda/src/device', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3device.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3device.in', opts=['IMOD:panda3d.core', 'ILIB:libp3device', 'SRCDIR:panda/src/device']) +OPTS=['DIR:panda/src/device'] +IGATEFILES=GetDirectoryContents('panda/src/device', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3device.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3device.in', opts=['IMOD:panda3d.core', 'ILIB:libp3device', 'SRCDIR:panda/src/device']) # # DIRECTORY: panda/src/display/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/display', 'BUILDING:PANDA', 'X11'] - TargetAdd('p3display_graphicsStateGuardian.obj', opts=OPTS, input='graphicsStateGuardian.cxx') - TargetAdd('p3display_composite1.obj', opts=OPTS, input='p3display_composite1.cxx') - TargetAdd('p3display_composite2.obj', opts=OPTS, input='p3display_composite2.cxx') +OPTS=['DIR:panda/src/display', 'BUILDING:PANDA', 'X11'] +TargetAdd('p3display_graphicsStateGuardian.obj', opts=OPTS, input='graphicsStateGuardian.cxx') +TargetAdd('p3display_composite1.obj', opts=OPTS, input='p3display_composite1.cxx') +TargetAdd('p3display_composite2.obj', opts=OPTS, input='p3display_composite2.cxx') - OPTS=['DIR:panda/src/display', 'X11'] - IGATEFILES=GetDirectoryContents('panda/src/display', ["*.h", "*_composite*.cxx"]) - IGATEFILES.remove("renderBuffer.h") - TargetAdd('libp3display.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3display.in', opts=['IMOD:panda3d.core', 'ILIB:libp3display', 'SRCDIR:panda/src/display']) - PyTargetAdd('p3display_ext_composite.obj', opts=OPTS, input='p3display_ext_composite.cxx') - - if RTDIST and GetTarget() == 'darwin': - OPTS=['DIR:panda/src/display'] - TargetAdd('subprocessWindowBuffer.obj', opts=OPTS, input='subprocessWindowBuffer.cxx') - TargetAdd('libp3subprocbuffer.ilb', input='subprocessWindowBuffer.obj') +OPTS=['DIR:panda/src/display', 'X11'] +IGATEFILES=GetDirectoryContents('panda/src/display', ["*.h", "*_composite*.cxx"]) +IGATEFILES.remove("renderBuffer.h") +TargetAdd('libp3display.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3display.in', opts=['IMOD:panda3d.core', 'ILIB:libp3display', 'SRCDIR:panda/src/display']) +PyTargetAdd('p3display_ext_composite.obj', opts=OPTS, input='p3display_ext_composite.cxx') # # DIRECTORY: panda/src/chan/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/chan', 'BUILDING:PANDA'] - TargetAdd('p3chan_composite1.obj', opts=OPTS, input='p3chan_composite1.cxx') - TargetAdd('p3chan_composite2.obj', opts=OPTS, input='p3chan_composite2.cxx') +OPTS=['DIR:panda/src/chan', 'BUILDING:PANDA'] +TargetAdd('p3chan_composite1.obj', opts=OPTS, input='p3chan_composite1.cxx') +TargetAdd('p3chan_composite2.obj', opts=OPTS, input='p3chan_composite2.cxx') - OPTS=['DIR:panda/src/chan'] - IGATEFILES=GetDirectoryContents('panda/src/chan', ["*.h", "*_composite*.cxx"]) - IGATEFILES.remove('movingPart.h') - IGATEFILES.remove('animChannelFixed.h') - TargetAdd('libp3chan.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3chan.in', opts=['IMOD:panda3d.core', 'ILIB:libp3chan', 'SRCDIR:panda/src/chan']) +OPTS=['DIR:panda/src/chan'] +IGATEFILES=GetDirectoryContents('panda/src/chan', ["*.h", "*_composite*.cxx"]) +IGATEFILES.remove('movingPart.h') +IGATEFILES.remove('animChannelFixed.h') +TargetAdd('libp3chan.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3chan.in', opts=['IMOD:panda3d.core', 'ILIB:libp3chan', 'SRCDIR:panda/src/chan']) # DIRECTORY: panda/src/char/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/char', 'BUILDING:PANDA'] - TargetAdd('p3char_composite1.obj', opts=OPTS, input='p3char_composite1.cxx') - TargetAdd('p3char_composite2.obj', opts=OPTS, input='p3char_composite2.cxx') +OPTS=['DIR:panda/src/char', 'BUILDING:PANDA'] +TargetAdd('p3char_composite1.obj', opts=OPTS, input='p3char_composite1.cxx') +TargetAdd('p3char_composite2.obj', opts=OPTS, input='p3char_composite2.cxx') - OPTS=['DIR:panda/src/char'] - IGATEFILES=GetDirectoryContents('panda/src/char', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3char.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3char.in', opts=['IMOD:panda3d.core', 'ILIB:libp3char', 'SRCDIR:panda/src/char']) +OPTS=['DIR:panda/src/char'] +IGATEFILES=GetDirectoryContents('panda/src/char', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3char.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3char.in', opts=['IMOD:panda3d.core', 'ILIB:libp3char', 'SRCDIR:panda/src/char']) # # DIRECTORY: panda/src/pnmtext/ # -if (PkgSkip("FREETYPE")==0 and not RUNTIME): +if (PkgSkip("FREETYPE")==0): OPTS=['DIR:panda/src/pnmtext', 'BUILDING:PANDA', 'FREETYPE'] TargetAdd('p3pnmtext_composite1.obj', opts=OPTS, input='p3pnmtext_composite1.cxx') @@ -4068,126 +3708,117 @@ if (PkgSkip("FREETYPE")==0 and not RUNTIME): # DIRECTORY: panda/src/text/ # -if (not RUNTIME): - if not PkgSkip("HARFBUZZ"): - DefSymbol("HARFBUZZ", "HAVE_HARFBUZZ") +if not PkgSkip("HARFBUZZ"): + DefSymbol("HARFBUZZ", "HAVE_HARFBUZZ") - OPTS=['DIR:panda/src/text', 'BUILDING:PANDA', 'ZLIB', 'FREETYPE', 'HARFBUZZ'] - TargetAdd('p3text_composite1.obj', opts=OPTS, input='p3text_composite1.cxx') - TargetAdd('p3text_composite2.obj', opts=OPTS, input='p3text_composite2.cxx') +OPTS=['DIR:panda/src/text', 'BUILDING:PANDA', 'ZLIB', 'FREETYPE', 'HARFBUZZ'] +TargetAdd('p3text_composite1.obj', opts=OPTS, input='p3text_composite1.cxx') +TargetAdd('p3text_composite2.obj', opts=OPTS, input='p3text_composite2.cxx') - OPTS=['DIR:panda/src/text', 'ZLIB', 'FREETYPE'] - IGATEFILES=GetDirectoryContents('panda/src/text', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3text.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3text.in', opts=['IMOD:panda3d.core', 'ILIB:libp3text', 'SRCDIR:panda/src/text']) +OPTS=['DIR:panda/src/text', 'ZLIB', 'FREETYPE'] +IGATEFILES=GetDirectoryContents('panda/src/text', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3text.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3text.in', opts=['IMOD:panda3d.core', 'ILIB:libp3text', 'SRCDIR:panda/src/text']) # # DIRECTORY: panda/src/movies/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/movies', 'BUILDING:PANDA', 'VORBIS', 'OPUS'] - TargetAdd('p3movies_composite1.obj', opts=OPTS, input='p3movies_composite1.cxx') +OPTS=['DIR:panda/src/movies', 'BUILDING:PANDA', 'VORBIS', 'OPUS'] +TargetAdd('p3movies_composite1.obj', opts=OPTS, input='p3movies_composite1.cxx') - OPTS=['DIR:panda/src/movies', 'VORBIS', 'OPUS'] - IGATEFILES=GetDirectoryContents('panda/src/movies', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3movies.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3movies.in', opts=['IMOD:panda3d.core', 'ILIB:libp3movies', 'SRCDIR:panda/src/movies']) +OPTS=['DIR:panda/src/movies', 'VORBIS', 'OPUS'] +IGATEFILES=GetDirectoryContents('panda/src/movies', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3movies.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3movies.in', opts=['IMOD:panda3d.core', 'ILIB:libp3movies', 'SRCDIR:panda/src/movies']) # # DIRECTORY: panda/src/grutil/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/grutil', 'BUILDING:PANDA'] - TargetAdd('p3grutil_multitexReducer.obj', opts=OPTS, input='multitexReducer.cxx') - TargetAdd('p3grutil_composite1.obj', opts=OPTS, input='p3grutil_composite1.cxx') - TargetAdd('p3grutil_composite2.obj', opts=OPTS, input='p3grutil_composite2.cxx') +OPTS=['DIR:panda/src/grutil', 'BUILDING:PANDA'] +TargetAdd('p3grutil_multitexReducer.obj', opts=OPTS, input='multitexReducer.cxx') +TargetAdd('p3grutil_composite1.obj', opts=OPTS, input='p3grutil_composite1.cxx') +TargetAdd('p3grutil_composite2.obj', opts=OPTS, input='p3grutil_composite2.cxx') - OPTS=['DIR:panda/src/grutil'] - IGATEFILES=GetDirectoryContents('panda/src/grutil', ["*.h", "*_composite*.cxx"]) - if 'convexHull.h' in IGATEFILES: IGATEFILES.remove('convexHull.h') - TargetAdd('libp3grutil.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3grutil.in', opts=['IMOD:panda3d.core', 'ILIB:libp3grutil', 'SRCDIR:panda/src/grutil']) +OPTS=['DIR:panda/src/grutil'] +IGATEFILES=GetDirectoryContents('panda/src/grutil', ["*.h", "*_composite*.cxx"]) +if 'convexHull.h' in IGATEFILES: IGATEFILES.remove('convexHull.h') +TargetAdd('libp3grutil.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3grutil.in', opts=['IMOD:panda3d.core', 'ILIB:libp3grutil', 'SRCDIR:panda/src/grutil']) # # DIRECTORY: panda/src/tform/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/tform', 'BUILDING:PANDA'] - TargetAdd('p3tform_composite1.obj', opts=OPTS, input='p3tform_composite1.cxx') - TargetAdd('p3tform_composite2.obj', opts=OPTS, input='p3tform_composite2.cxx') +OPTS=['DIR:panda/src/tform', 'BUILDING:PANDA'] +TargetAdd('p3tform_composite1.obj', opts=OPTS, input='p3tform_composite1.cxx') +TargetAdd('p3tform_composite2.obj', opts=OPTS, input='p3tform_composite2.cxx') - OPTS=['DIR:panda/src/tform'] - IGATEFILES=GetDirectoryContents('panda/src/tform', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3tform.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3tform.in', opts=['IMOD:panda3d.core', 'ILIB:libp3tform', 'SRCDIR:panda/src/tform']) +OPTS=['DIR:panda/src/tform'] +IGATEFILES=GetDirectoryContents('panda/src/tform', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3tform.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3tform.in', opts=['IMOD:panda3d.core', 'ILIB:libp3tform', 'SRCDIR:panda/src/tform']) # # DIRECTORY: panda/src/collide/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/collide', 'BUILDING:PANDA'] - TargetAdd('p3collide_composite1.obj', opts=OPTS, input='p3collide_composite1.cxx') - TargetAdd('p3collide_composite2.obj', opts=OPTS, input='p3collide_composite2.cxx') +OPTS=['DIR:panda/src/collide', 'BUILDING:PANDA'] +TargetAdd('p3collide_composite1.obj', opts=OPTS, input='p3collide_composite1.cxx') +TargetAdd('p3collide_composite2.obj', opts=OPTS, input='p3collide_composite2.cxx') - OPTS=['DIR:panda/src/collide'] - IGATEFILES=GetDirectoryContents('panda/src/collide', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3collide.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3collide.in', opts=['IMOD:panda3d.core', 'ILIB:libp3collide', 'SRCDIR:panda/src/collide']) +OPTS=['DIR:panda/src/collide'] +IGATEFILES=GetDirectoryContents('panda/src/collide', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3collide.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3collide.in', opts=['IMOD:panda3d.core', 'ILIB:libp3collide', 'SRCDIR:panda/src/collide']) # # DIRECTORY: panda/src/parametrics/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/parametrics', 'BUILDING:PANDA'] - TargetAdd('p3parametrics_composite1.obj', opts=OPTS, input='p3parametrics_composite1.cxx') - TargetAdd('p3parametrics_composite2.obj', opts=OPTS, input='p3parametrics_composite2.cxx') +OPTS=['DIR:panda/src/parametrics', 'BUILDING:PANDA'] +TargetAdd('p3parametrics_composite1.obj', opts=OPTS, input='p3parametrics_composite1.cxx') +TargetAdd('p3parametrics_composite2.obj', opts=OPTS, input='p3parametrics_composite2.cxx') - OPTS=['DIR:panda/src/parametrics'] - IGATEFILES=GetDirectoryContents('panda/src/parametrics', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3parametrics.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3parametrics.in', opts=['IMOD:panda3d.core', 'ILIB:libp3parametrics', 'SRCDIR:panda/src/parametrics']) +OPTS=['DIR:panda/src/parametrics'] +IGATEFILES=GetDirectoryContents('panda/src/parametrics', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3parametrics.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3parametrics.in', opts=['IMOD:panda3d.core', 'ILIB:libp3parametrics', 'SRCDIR:panda/src/parametrics']) # # DIRECTORY: panda/src/pgui/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/pgui', 'BUILDING:PANDA'] - TargetAdd('p3pgui_composite1.obj', opts=OPTS, input='p3pgui_composite1.cxx') - TargetAdd('p3pgui_composite2.obj', opts=OPTS, input='p3pgui_composite2.cxx') +OPTS=['DIR:panda/src/pgui', 'BUILDING:PANDA'] +TargetAdd('p3pgui_composite1.obj', opts=OPTS, input='p3pgui_composite1.cxx') +TargetAdd('p3pgui_composite2.obj', opts=OPTS, input='p3pgui_composite2.cxx') - OPTS=['DIR:panda/src/pgui'] - IGATEFILES=GetDirectoryContents('panda/src/pgui', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3pgui.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3pgui.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pgui', 'SRCDIR:panda/src/pgui']) +OPTS=['DIR:panda/src/pgui'] +IGATEFILES=GetDirectoryContents('panda/src/pgui', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3pgui.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3pgui.in', opts=['IMOD:panda3d.core', 'ILIB:libp3pgui', 'SRCDIR:panda/src/pgui']) # # DIRECTORY: panda/src/pnmimagetypes/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/pnmimagetypes', 'DIR:panda/src/pnmimage', 'BUILDING:PANDA', 'PNG', 'ZLIB', 'JPEG', 'TIFF', 'OPENEXR', 'EXCEPTIONS'] - TargetAdd('p3pnmimagetypes_composite1.obj', opts=OPTS, input='p3pnmimagetypes_composite1.cxx') - TargetAdd('p3pnmimagetypes_composite2.obj', opts=OPTS, input='p3pnmimagetypes_composite2.cxx') +OPTS=['DIR:panda/src/pnmimagetypes', 'DIR:panda/src/pnmimage', 'BUILDING:PANDA', 'PNG', 'ZLIB', 'JPEG', 'TIFF', 'OPENEXR', 'EXCEPTIONS'] +TargetAdd('p3pnmimagetypes_composite1.obj', opts=OPTS, input='p3pnmimagetypes_composite1.cxx') +TargetAdd('p3pnmimagetypes_composite2.obj', opts=OPTS, input='p3pnmimagetypes_composite2.cxx') # # DIRECTORY: panda/src/recorder/ # -if (not RUNTIME): - OPTS=['DIR:panda/src/recorder', 'BUILDING:PANDA'] - TargetAdd('p3recorder_composite1.obj', opts=OPTS, input='p3recorder_composite1.cxx') - TargetAdd('p3recorder_composite2.obj', opts=OPTS, input='p3recorder_composite2.cxx') +OPTS=['DIR:panda/src/recorder', 'BUILDING:PANDA'] +TargetAdd('p3recorder_composite1.obj', opts=OPTS, input='p3recorder_composite1.cxx') +TargetAdd('p3recorder_composite2.obj', opts=OPTS, input='p3recorder_composite2.cxx') - OPTS=['DIR:panda/src/recorder'] - IGATEFILES=GetDirectoryContents('panda/src/recorder', ["*.h", "*_composite*.cxx"]) - TargetAdd('libp3recorder.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3recorder.in', opts=['IMOD:panda3d.core', 'ILIB:libp3recorder', 'SRCDIR:panda/src/recorder']) +OPTS=['DIR:panda/src/recorder'] +IGATEFILES=GetDirectoryContents('panda/src/recorder', ["*.h", "*_composite*.cxx"]) +TargetAdd('libp3recorder.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3recorder.in', opts=['IMOD:panda3d.core', 'ILIB:libp3recorder', 'SRCDIR:panda/src/recorder']) # # DIRECTORY: panda/src/dxml/ @@ -4199,207 +3830,205 @@ OPTS=['DIR:panda/src/dxml', 'TINYXML'] TargetAdd('tinyxml_composite1.obj', opts=OPTS, input='tinyxml_composite1.cxx') TargetAdd('libp3tinyxml.ilb', input='tinyxml_composite1.obj') -if (not RUNTIME): - OPTS=['DIR:panda/src/dxml', 'BUILDING:PANDA', 'TINYXML'] - TargetAdd('p3dxml_composite1.obj', opts=OPTS, input='p3dxml_composite1.cxx') +OPTS=['DIR:panda/src/dxml', 'BUILDING:PANDA', 'TINYXML'] +TargetAdd('p3dxml_composite1.obj', opts=OPTS, input='p3dxml_composite1.cxx') - OPTS=['DIR:panda/src/dxml', 'TINYXML'] - IGATEFILES=GetDirectoryContents('panda/src/dxml', ["*.h", "p3dxml_composite1.cxx"]) - TargetAdd('libp3dxml.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3dxml.in', opts=['IMOD:panda3d.core', 'ILIB:libp3dxml', 'SRCDIR:panda/src/dxml']) +OPTS=['DIR:panda/src/dxml', 'TINYXML'] +IGATEFILES=GetDirectoryContents('panda/src/dxml', ["*.h", "p3dxml_composite1.cxx"]) +TargetAdd('libp3dxml.in', opts=OPTS, input=IGATEFILES) +TargetAdd('libp3dxml.in', opts=['IMOD:panda3d.core', 'ILIB:libp3dxml', 'SRCDIR:panda/src/dxml']) # # DIRECTORY: panda/metalibs/panda/ # -if (not RUNTIME): - OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG', 'HARFBUZZ', - 'TIFF', 'OPENEXR', 'ZLIB', 'OPENSSL', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2', - 'SQUISH', 'NVIDIACG', 'VORBIS', 'OPUS', 'WINUSER', 'WINMM', 'WINGDI', 'IPHLPAPI', - 'SETUPAPI', 'IOKIT'] +OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG', 'HARFBUZZ', + 'TIFF', 'OPENEXR', 'ZLIB', 'OPENSSL', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2', + 'SQUISH', 'NVIDIACG', 'VORBIS', 'OPUS', 'WINUSER', 'WINMM', 'WINGDI', 'IPHLPAPI', + 'SETUPAPI', 'IOKIT'] - TargetAdd('panda_panda.obj', opts=OPTS, input='panda.cxx') +TargetAdd('panda_panda.obj', opts=OPTS, input='panda.cxx') - TargetAdd('libpanda.dll', input='panda_panda.obj') - TargetAdd('libpanda.dll', input='p3recorder_composite1.obj') - TargetAdd('libpanda.dll', input='p3recorder_composite2.obj') - TargetAdd('libpanda.dll', input='p3pgraphnodes_composite1.obj') - TargetAdd('libpanda.dll', input='p3pgraphnodes_composite2.obj') - TargetAdd('libpanda.dll', input='p3pgraph_nodePath.obj') - TargetAdd('libpanda.dll', input='p3pgraph_composite1.obj') - TargetAdd('libpanda.dll', input='p3pgraph_composite2.obj') - TargetAdd('libpanda.dll', input='p3pgraph_composite3.obj') - TargetAdd('libpanda.dll', input='p3pgraph_composite4.obj') - TargetAdd('libpanda.dll', input='p3cull_composite1.obj') - TargetAdd('libpanda.dll', input='p3cull_composite2.obj') - TargetAdd('libpanda.dll', input='p3movies_composite1.obj') - TargetAdd('libpanda.dll', input='p3grutil_multitexReducer.obj') - TargetAdd('libpanda.dll', input='p3grutil_composite1.obj') - TargetAdd('libpanda.dll', input='p3grutil_composite2.obj') - TargetAdd('libpanda.dll', input='p3chan_composite1.obj') - TargetAdd('libpanda.dll', input='p3chan_composite2.obj') - TargetAdd('libpanda.dll', input='p3pstatclient_composite1.obj') - TargetAdd('libpanda.dll', input='p3pstatclient_composite2.obj') - TargetAdd('libpanda.dll', input='p3char_composite1.obj') - TargetAdd('libpanda.dll', input='p3char_composite2.obj') - TargetAdd('libpanda.dll', input='p3collide_composite1.obj') - TargetAdd('libpanda.dll', input='p3collide_composite2.obj') - TargetAdd('libpanda.dll', input='p3device_composite1.obj') - TargetAdd('libpanda.dll', input='p3device_composite2.obj') - TargetAdd('libpanda.dll', input='p3dgraph_composite1.obj') - TargetAdd('libpanda.dll', input='p3dgraph_composite2.obj') - TargetAdd('libpanda.dll', input='p3display_graphicsStateGuardian.obj') - TargetAdd('libpanda.dll', input='p3display_composite1.obj') - TargetAdd('libpanda.dll', input='p3display_composite2.obj') - TargetAdd('libpanda.dll', input='p3pipeline_composite1.obj') - TargetAdd('libpanda.dll', input='p3pipeline_composite2.obj') - TargetAdd('libpanda.dll', input='p3pipeline_contextSwitch.obj') - TargetAdd('libpanda.dll', input='p3event_composite1.obj') - TargetAdd('libpanda.dll', input='p3event_composite2.obj') - TargetAdd('libpanda.dll', input='p3gobj_composite1.obj') - TargetAdd('libpanda.dll', input='p3gobj_composite2.obj') - TargetAdd('libpanda.dll', input='p3gsgbase_composite1.obj') - TargetAdd('libpanda.dll', input='p3linmath_composite1.obj') - TargetAdd('libpanda.dll', input='p3linmath_composite2.obj') - TargetAdd('libpanda.dll', input='p3mathutil_composite1.obj') - TargetAdd('libpanda.dll', input='p3mathutil_composite2.obj') - TargetAdd('libpanda.dll', input='p3parametrics_composite1.obj') - TargetAdd('libpanda.dll', input='p3parametrics_composite2.obj') - TargetAdd('libpanda.dll', input='p3pnmimagetypes_composite1.obj') - TargetAdd('libpanda.dll', input='p3pnmimagetypes_composite2.obj') - TargetAdd('libpanda.dll', input='p3pnmimage_composite1.obj') - TargetAdd('libpanda.dll', input='p3pnmimage_composite2.obj') - TargetAdd('libpanda.dll', input='p3pnmimage_convert_srgb_sse2.obj') - TargetAdd('libpanda.dll', input='p3text_composite1.obj') - TargetAdd('libpanda.dll', input='p3text_composite2.obj') - TargetAdd('libpanda.dll', input='p3tform_composite1.obj') - TargetAdd('libpanda.dll', input='p3tform_composite2.obj') - TargetAdd('libpanda.dll', input='p3putil_composite1.obj') - TargetAdd('libpanda.dll', input='p3putil_composite2.obj') - TargetAdd('libpanda.dll', input='p3audio_composite1.obj') - TargetAdd('libpanda.dll', input='p3pgui_composite1.obj') - TargetAdd('libpanda.dll', input='p3pgui_composite2.obj') - TargetAdd('libpanda.dll', input='p3net_composite1.obj') - TargetAdd('libpanda.dll', input='p3net_composite2.obj') - TargetAdd('libpanda.dll', input='p3nativenet_composite1.obj') - TargetAdd('libpanda.dll', input='p3pandabase_pandabase.obj') - TargetAdd('libpanda.dll', input='libpandaexpress.dll') - TargetAdd('libpanda.dll', input='p3dxml_composite1.obj') - TargetAdd('libpanda.dll', input='libp3dtoolconfig.dll') - TargetAdd('libpanda.dll', input='libp3dtool.dll') +TargetAdd('libpanda.dll', input='panda_panda.obj') +TargetAdd('libpanda.dll', input='p3recorder_composite1.obj') +TargetAdd('libpanda.dll', input='p3recorder_composite2.obj') +TargetAdd('libpanda.dll', input='p3pgraphnodes_composite1.obj') +TargetAdd('libpanda.dll', input='p3pgraphnodes_composite2.obj') +TargetAdd('libpanda.dll', input='p3pgraph_nodePath.obj') +TargetAdd('libpanda.dll', input='p3pgraph_composite1.obj') +TargetAdd('libpanda.dll', input='p3pgraph_composite2.obj') +TargetAdd('libpanda.dll', input='p3pgraph_composite3.obj') +TargetAdd('libpanda.dll', input='p3pgraph_composite4.obj') +TargetAdd('libpanda.dll', input='p3cull_composite1.obj') +TargetAdd('libpanda.dll', input='p3cull_composite2.obj') +TargetAdd('libpanda.dll', input='p3movies_composite1.obj') +TargetAdd('libpanda.dll', input='p3grutil_multitexReducer.obj') +TargetAdd('libpanda.dll', input='p3grutil_composite1.obj') +TargetAdd('libpanda.dll', input='p3grutil_composite2.obj') +TargetAdd('libpanda.dll', input='p3chan_composite1.obj') +TargetAdd('libpanda.dll', input='p3chan_composite2.obj') +TargetAdd('libpanda.dll', input='p3pstatclient_composite1.obj') +TargetAdd('libpanda.dll', input='p3pstatclient_composite2.obj') +TargetAdd('libpanda.dll', input='p3char_composite1.obj') +TargetAdd('libpanda.dll', input='p3char_composite2.obj') +TargetAdd('libpanda.dll', input='p3collide_composite1.obj') +TargetAdd('libpanda.dll', input='p3collide_composite2.obj') +TargetAdd('libpanda.dll', input='p3device_composite1.obj') +TargetAdd('libpanda.dll', input='p3device_composite2.obj') +TargetAdd('libpanda.dll', input='p3dgraph_composite1.obj') +TargetAdd('libpanda.dll', input='p3dgraph_composite2.obj') +TargetAdd('libpanda.dll', input='p3display_graphicsStateGuardian.obj') +TargetAdd('libpanda.dll', input='p3display_composite1.obj') +TargetAdd('libpanda.dll', input='p3display_composite2.obj') +TargetAdd('libpanda.dll', input='p3pipeline_composite1.obj') +TargetAdd('libpanda.dll', input='p3pipeline_composite2.obj') +TargetAdd('libpanda.dll', input='p3pipeline_contextSwitch.obj') +TargetAdd('libpanda.dll', input='p3event_composite1.obj') +TargetAdd('libpanda.dll', input='p3event_composite2.obj') +TargetAdd('libpanda.dll', input='p3gobj_composite1.obj') +TargetAdd('libpanda.dll', input='p3gobj_composite2.obj') +TargetAdd('libpanda.dll', input='p3gsgbase_composite1.obj') +TargetAdd('libpanda.dll', input='p3linmath_composite1.obj') +TargetAdd('libpanda.dll', input='p3linmath_composite2.obj') +TargetAdd('libpanda.dll', input='p3mathutil_composite1.obj') +TargetAdd('libpanda.dll', input='p3mathutil_composite2.obj') +TargetAdd('libpanda.dll', input='p3parametrics_composite1.obj') +TargetAdd('libpanda.dll', input='p3parametrics_composite2.obj') +TargetAdd('libpanda.dll', input='p3pnmimagetypes_composite1.obj') +TargetAdd('libpanda.dll', input='p3pnmimagetypes_composite2.obj') +TargetAdd('libpanda.dll', input='p3pnmimage_composite1.obj') +TargetAdd('libpanda.dll', input='p3pnmimage_composite2.obj') +TargetAdd('libpanda.dll', input='p3pnmimage_convert_srgb_sse2.obj') +TargetAdd('libpanda.dll', input='p3text_composite1.obj') +TargetAdd('libpanda.dll', input='p3text_composite2.obj') +TargetAdd('libpanda.dll', input='p3tform_composite1.obj') +TargetAdd('libpanda.dll', input='p3tform_composite2.obj') +TargetAdd('libpanda.dll', input='p3putil_composite1.obj') +TargetAdd('libpanda.dll', input='p3putil_composite2.obj') +TargetAdd('libpanda.dll', input='p3audio_composite1.obj') +TargetAdd('libpanda.dll', input='p3pgui_composite1.obj') +TargetAdd('libpanda.dll', input='p3pgui_composite2.obj') +TargetAdd('libpanda.dll', input='p3net_composite1.obj') +TargetAdd('libpanda.dll', input='p3net_composite2.obj') +TargetAdd('libpanda.dll', input='p3nativenet_composite1.obj') +TargetAdd('libpanda.dll', input='p3pandabase_pandabase.obj') +TargetAdd('libpanda.dll', input='libpandaexpress.dll') +TargetAdd('libpanda.dll', input='p3dxml_composite1.obj') +TargetAdd('libpanda.dll', input='libp3dtoolconfig.dll') +TargetAdd('libpanda.dll', input='libp3dtool.dll') - if PkgSkip("FREETYPE")==0: - TargetAdd('libpanda.dll', input="p3pnmtext_composite1.obj") +if PkgSkip("FREETYPE")==0: + TargetAdd('libpanda.dll', input="p3pnmtext_composite1.obj") - TargetAdd('libpanda.dll', dep='dtool_have_freetype.dat') - TargetAdd('libpanda.dll', opts=OPTS) +TargetAdd('libpanda.dll', dep='dtool_have_freetype.dat') +TargetAdd('libpanda.dll', opts=OPTS) - PyTargetAdd('core_module.obj', input='libp3dtoolbase.in') - PyTargetAdd('core_module.obj', input='libp3dtoolutil.in') - PyTargetAdd('core_module.obj', input='libp3prc.in') +PyTargetAdd('core_module.obj', input='libp3dtoolbase.in') +PyTargetAdd('core_module.obj', input='libp3dtoolutil.in') +PyTargetAdd('core_module.obj', input='libp3prc.in') - PyTargetAdd('core_module.obj', input='libp3downloader.in') - PyTargetAdd('core_module.obj', input='libp3express.in') +PyTargetAdd('core_module.obj', input='libp3downloader.in') +PyTargetAdd('core_module.obj', input='libp3express.in') - PyTargetAdd('core_module.obj', input='libp3recorder.in') - PyTargetAdd('core_module.obj', input='libp3pgraphnodes.in') - PyTargetAdd('core_module.obj', input='libp3pgraph.in') - PyTargetAdd('core_module.obj', input='libp3cull.in') - PyTargetAdd('core_module.obj', input='libp3grutil.in') - PyTargetAdd('core_module.obj', input='libp3chan.in') - PyTargetAdd('core_module.obj', input='libp3pstatclient.in') - PyTargetAdd('core_module.obj', input='libp3char.in') - PyTargetAdd('core_module.obj', input='libp3collide.in') - PyTargetAdd('core_module.obj', input='libp3device.in') - PyTargetAdd('core_module.obj', input='libp3dgraph.in') - PyTargetAdd('core_module.obj', input='libp3display.in') - PyTargetAdd('core_module.obj', input='libp3pipeline.in') - PyTargetAdd('core_module.obj', input='libp3event.in') - PyTargetAdd('core_module.obj', input='libp3gobj.in') - PyTargetAdd('core_module.obj', input='libp3gsgbase.in') - PyTargetAdd('core_module.obj', input='libp3linmath.in') - PyTargetAdd('core_module.obj', input='libp3mathutil.in') - PyTargetAdd('core_module.obj', input='libp3parametrics.in') - PyTargetAdd('core_module.obj', input='libp3pnmimage.in') - PyTargetAdd('core_module.obj', input='libp3text.in') - PyTargetAdd('core_module.obj', input='libp3tform.in') - PyTargetAdd('core_module.obj', input='libp3putil.in') - PyTargetAdd('core_module.obj', input='libp3audio.in') - PyTargetAdd('core_module.obj', input='libp3nativenet.in') - PyTargetAdd('core_module.obj', input='libp3net.in') - PyTargetAdd('core_module.obj', input='libp3pgui.in') - PyTargetAdd('core_module.obj', input='libp3movies.in') - PyTargetAdd('core_module.obj', input='libp3dxml.in') +PyTargetAdd('core_module.obj', input='libp3recorder.in') +PyTargetAdd('core_module.obj', input='libp3pgraphnodes.in') +PyTargetAdd('core_module.obj', input='libp3pgraph.in') +PyTargetAdd('core_module.obj', input='libp3cull.in') +PyTargetAdd('core_module.obj', input='libp3grutil.in') +PyTargetAdd('core_module.obj', input='libp3chan.in') +PyTargetAdd('core_module.obj', input='libp3pstatclient.in') +PyTargetAdd('core_module.obj', input='libp3char.in') +PyTargetAdd('core_module.obj', input='libp3collide.in') +PyTargetAdd('core_module.obj', input='libp3device.in') +PyTargetAdd('core_module.obj', input='libp3dgraph.in') +PyTargetAdd('core_module.obj', input='libp3display.in') +PyTargetAdd('core_module.obj', input='libp3pipeline.in') +PyTargetAdd('core_module.obj', input='libp3event.in') +PyTargetAdd('core_module.obj', input='libp3gobj.in') +PyTargetAdd('core_module.obj', input='libp3gsgbase.in') +PyTargetAdd('core_module.obj', input='libp3linmath.in') +PyTargetAdd('core_module.obj', input='libp3mathutil.in') +PyTargetAdd('core_module.obj', input='libp3parametrics.in') +PyTargetAdd('core_module.obj', input='libp3pnmimage.in') +PyTargetAdd('core_module.obj', input='libp3text.in') +PyTargetAdd('core_module.obj', input='libp3tform.in') +PyTargetAdd('core_module.obj', input='libp3putil.in') +PyTargetAdd('core_module.obj', input='libp3audio.in') +PyTargetAdd('core_module.obj', input='libp3nativenet.in') +PyTargetAdd('core_module.obj', input='libp3net.in') +PyTargetAdd('core_module.obj', input='libp3pgui.in') +PyTargetAdd('core_module.obj', input='libp3movies.in') +PyTargetAdd('core_module.obj', input='libp3dxml.in') - if PkgSkip("FREETYPE")==0: - PyTargetAdd('core_module.obj', input='libp3pnmtext.in') +if PkgSkip("FREETYPE")==0: + PyTargetAdd('core_module.obj', input='libp3pnmtext.in') - PyTargetAdd('core_module.obj', opts=['IMOD:panda3d.core', 'ILIB:core']) +PyTargetAdd('core_module.obj', opts=['IMOD:panda3d.core', 'ILIB:core']) - PyTargetAdd('core.pyd', input='libp3dtoolbase_igate.obj') - PyTargetAdd('core.pyd', input='p3dtoolbase_typeHandle_ext.obj') - PyTargetAdd('core.pyd', input='libp3dtoolutil_igate.obj') - PyTargetAdd('core.pyd', input='p3dtoolutil_ext_composite.obj') - PyTargetAdd('core.pyd', input='libp3prc_igate.obj') - PyTargetAdd('core.pyd', input='p3prc_ext_composite.obj') +PyTargetAdd('core.pyd', input='libp3dtoolbase_igate.obj') +PyTargetAdd('core.pyd', input='p3dtoolbase_typeHandle_ext.obj') +PyTargetAdd('core.pyd', input='libp3dtoolutil_igate.obj') +PyTargetAdd('core.pyd', input='p3dtoolutil_ext_composite.obj') +PyTargetAdd('core.pyd', input='libp3prc_igate.obj') +PyTargetAdd('core.pyd', input='p3prc_ext_composite.obj') - PyTargetAdd('core.pyd', input='libp3downloader_igate.obj') - PyTargetAdd('core.pyd', input='p3express_ext_composite.obj') - PyTargetAdd('core.pyd', input='libp3express_igate.obj') +PyTargetAdd('core.pyd', input='libp3downloader_igate.obj') +PyTargetAdd('core.pyd', input='p3express_ext_composite.obj') +PyTargetAdd('core.pyd', input='libp3express_igate.obj') - PyTargetAdd('core.pyd', input='libp3recorder_igate.obj') - PyTargetAdd('core.pyd', input='libp3pgraphnodes_igate.obj') - PyTargetAdd('core.pyd', input='libp3pgraph_igate.obj') - PyTargetAdd('core.pyd', input='libp3movies_igate.obj') - PyTargetAdd('core.pyd', input='libp3grutil_igate.obj') - PyTargetAdd('core.pyd', input='libp3chan_igate.obj') - PyTargetAdd('core.pyd', input='libp3pstatclient_igate.obj') - PyTargetAdd('core.pyd', input='libp3char_igate.obj') - PyTargetAdd('core.pyd', input='libp3collide_igate.obj') - PyTargetAdd('core.pyd', input='libp3device_igate.obj') - PyTargetAdd('core.pyd', input='libp3dgraph_igate.obj') - PyTargetAdd('core.pyd', input='libp3display_igate.obj') - PyTargetAdd('core.pyd', input='libp3pipeline_igate.obj') - PyTargetAdd('core.pyd', input='libp3event_igate.obj') - PyTargetAdd('core.pyd', input='libp3gobj_igate.obj') - PyTargetAdd('core.pyd', input='libp3gsgbase_igate.obj') - PyTargetAdd('core.pyd', input='libp3linmath_igate.obj') - PyTargetAdd('core.pyd', input='libp3mathutil_igate.obj') - PyTargetAdd('core.pyd', input='libp3parametrics_igate.obj') - PyTargetAdd('core.pyd', input='libp3pnmimage_igate.obj') - PyTargetAdd('core.pyd', input='libp3text_igate.obj') - PyTargetAdd('core.pyd', input='libp3tform_igate.obj') - PyTargetAdd('core.pyd', input='libp3putil_igate.obj') - PyTargetAdd('core.pyd', input='libp3audio_igate.obj') - PyTargetAdd('core.pyd', input='libp3pgui_igate.obj') - PyTargetAdd('core.pyd', input='libp3net_igate.obj') - PyTargetAdd('core.pyd', input='libp3nativenet_igate.obj') - PyTargetAdd('core.pyd', input='libp3dxml_igate.obj') +PyTargetAdd('core.pyd', input='libp3recorder_igate.obj') +PyTargetAdd('core.pyd', input='libp3pgraphnodes_igate.obj') +PyTargetAdd('core.pyd', input='libp3pgraph_igate.obj') +PyTargetAdd('core.pyd', input='libp3movies_igate.obj') +PyTargetAdd('core.pyd', input='libp3grutil_igate.obj') +PyTargetAdd('core.pyd', input='libp3chan_igate.obj') +PyTargetAdd('core.pyd', input='libp3pstatclient_igate.obj') +PyTargetAdd('core.pyd', input='libp3char_igate.obj') +PyTargetAdd('core.pyd', input='libp3collide_igate.obj') +PyTargetAdd('core.pyd', input='libp3device_igate.obj') +PyTargetAdd('core.pyd', input='libp3dgraph_igate.obj') +PyTargetAdd('core.pyd', input='libp3display_igate.obj') +PyTargetAdd('core.pyd', input='libp3pipeline_igate.obj') +PyTargetAdd('core.pyd', input='libp3event_igate.obj') +PyTargetAdd('core.pyd', input='libp3gobj_igate.obj') +PyTargetAdd('core.pyd', input='libp3gsgbase_igate.obj') +PyTargetAdd('core.pyd', input='libp3linmath_igate.obj') +PyTargetAdd('core.pyd', input='libp3mathutil_igate.obj') +PyTargetAdd('core.pyd', input='libp3parametrics_igate.obj') +PyTargetAdd('core.pyd', input='libp3pnmimage_igate.obj') +PyTargetAdd('core.pyd', input='libp3text_igate.obj') +PyTargetAdd('core.pyd', input='libp3tform_igate.obj') +PyTargetAdd('core.pyd', input='libp3putil_igate.obj') +PyTargetAdd('core.pyd', input='libp3audio_igate.obj') +PyTargetAdd('core.pyd', input='libp3pgui_igate.obj') +PyTargetAdd('core.pyd', input='libp3net_igate.obj') +PyTargetAdd('core.pyd', input='libp3nativenet_igate.obj') +PyTargetAdd('core.pyd', input='libp3dxml_igate.obj') - if PkgSkip("FREETYPE")==0: - PyTargetAdd('core.pyd', input="libp3pnmtext_igate.obj") +if PkgSkip("FREETYPE")==0: + PyTargetAdd('core.pyd', input="libp3pnmtext_igate.obj") - PyTargetAdd('core.pyd', input='p3pipeline_pythonThread.obj') - PyTargetAdd('core.pyd', input='p3putil_ext_composite.obj') - PyTargetAdd('core.pyd', input='p3pnmimage_pfmFile_ext.obj') - PyTargetAdd('core.pyd', input='p3event_asyncFuture_ext.obj') - PyTargetAdd('core.pyd', input='p3event_pythonTask.obj') - PyTargetAdd('core.pyd', input='p3gobj_ext_composite.obj') - PyTargetAdd('core.pyd', input='p3pgraph_ext_composite.obj') - PyTargetAdd('core.pyd', input='p3display_ext_composite.obj') +PyTargetAdd('core.pyd', input='p3pipeline_pythonThread.obj') +PyTargetAdd('core.pyd', input='p3putil_ext_composite.obj') +PyTargetAdd('core.pyd', input='p3pnmimage_pfmFile_ext.obj') +PyTargetAdd('core.pyd', input='p3event_asyncFuture_ext.obj') +PyTargetAdd('core.pyd', input='p3event_pythonTask.obj') +PyTargetAdd('core.pyd', input='p3gobj_ext_composite.obj') +PyTargetAdd('core.pyd', input='p3pgraph_ext_composite.obj') +PyTargetAdd('core.pyd', input='p3display_ext_composite.obj') - PyTargetAdd('core.pyd', input='core_module.obj') - if not GetLinkAllStatic() and GetTarget() != 'emscripten': - PyTargetAdd('core.pyd', input='libp3tinyxml.ilb') - PyTargetAdd('core.pyd', input='libp3interrogatedb.dll') - PyTargetAdd('core.pyd', input=COMMON_PANDA_LIBS) - PyTargetAdd('core.pyd', opts=['WINSOCK2']) +PyTargetAdd('core.pyd', input='core_module.obj') +if not GetLinkAllStatic() and GetTarget() != 'emscripten': + PyTargetAdd('core.pyd', input='libp3tinyxml.ilb') +PyTargetAdd('core.pyd', input='libp3interrogatedb.dll') +PyTargetAdd('core.pyd', input=COMMON_PANDA_LIBS) +PyTargetAdd('core.pyd', opts=['WINSOCK2']) # # DIRECTORY: panda/src/vision/ # -if (PkgSkip("VISION") == 0) and (not RUNTIME): +if (PkgSkip("VISION") == 0): # We want to know whether we have ffmpeg so that we can override the .avi association. if not PkgSkip("FFMPEG"): DefSymbol("OPENCV", "HAVE_FFMPEG") @@ -4439,7 +4068,7 @@ if (PkgSkip("VISION") == 0) and (not RUNTIME): # DIRECTORY: panda/src/rocket/ # -if (PkgSkip("ROCKET") == 0) and (not RUNTIME): +if (PkgSkip("ROCKET") == 0): OPTS=['DIR:panda/src/rocket', 'BUILDING:ROCKET', 'ROCKET', 'PYTHON'] TargetAdd('p3rocket_composite1.obj', opts=OPTS, input='p3rocket_composite1.cxx') @@ -4471,7 +4100,7 @@ if (PkgSkip("ROCKET") == 0) and (not RUNTIME): # DIRECTORY: panda/src/p3skel # -if (PkgSkip('SKEL')==0) and (not RUNTIME): +if (PkgSkip('SKEL')==0): OPTS=['DIR:panda/src/skel', 'BUILDING:PANDASKEL', 'ADVAPI'] TargetAdd('p3skel_composite1.obj', opts=OPTS, input='p3skel_composite1.cxx') @@ -4484,7 +4113,7 @@ if (PkgSkip('SKEL')==0) and (not RUNTIME): # DIRECTORY: panda/src/p3skel # -if (PkgSkip('SKEL')==0) and (not RUNTIME): +if (PkgSkip('SKEL')==0): OPTS=['BUILDING:PANDASKEL', 'ADVAPI'] TargetAdd('libpandaskel.dll', input='p3skel_composite1.obj') TargetAdd('libpandaskel.dll', input=COMMON_PANDA_LIBS) @@ -4503,7 +4132,7 @@ if (PkgSkip('SKEL')==0) and (not RUNTIME): # DIRECTORY: panda/src/distort/ # -if (PkgSkip('PANDAFX')==0) and (not RUNTIME): +if (PkgSkip('PANDAFX')==0): OPTS=['DIR:panda/src/distort', 'BUILDING:PANDAFX'] TargetAdd('p3distort_composite1.obj', opts=OPTS, input='p3distort_composite1.cxx') @@ -4516,7 +4145,7 @@ if (PkgSkip('PANDAFX')==0) and (not RUNTIME): # DIRECTORY: panda/metalibs/pandafx/ # -if (PkgSkip('PANDAFX')==0) and (not RUNTIME): +if (PkgSkip('PANDAFX')==0): OPTS=['DIR:panda/metalibs/pandafx', 'DIR:panda/src/distort', 'BUILDING:PANDAFX', 'NVIDIACG'] TargetAdd('pandafx_pandafx.obj', opts=OPTS, input='pandafx.cxx') @@ -4540,7 +4169,7 @@ if (PkgSkip('PANDAFX')==0) and (not RUNTIME): # DIRECTORY: panda/src/vrpn/ # -if (PkgSkip("VRPN")==0 and not RUNTIME): +if (PkgSkip("VRPN")==0): OPTS=['DIR:panda/src/vrpn', 'BUILDING:VRPN', 'VRPN'] TargetAdd('p3vrpn_composite1.obj', opts=OPTS, input='p3vrpn_composite1.cxx') TargetAdd('libp3vrpn.dll', input='p3vrpn_composite1.obj') @@ -4566,7 +4195,7 @@ if (PkgSkip("VRPN")==0 and not RUNTIME): # # DIRECTORY: panda/src/ffmpeg # -if PkgSkip("FFMPEG") == 0 and not RUNTIME: +if PkgSkip("FFMPEG") == 0: if not PkgSkip("SWSCALE"): DefSymbol("FFMPEG", "HAVE_SWSCALE") if not PkgSkip("SWRESAMPLE"): @@ -4584,14 +4213,14 @@ if PkgSkip("FFMPEG") == 0 and not RUNTIME: # DIRECTORY: panda/src/audiotraits/ # -if PkgSkip("FMODEX") == 0 and not RUNTIME: +if PkgSkip("FMODEX") == 0: OPTS=['DIR:panda/src/audiotraits', 'BUILDING:FMOD_AUDIO', 'FMODEX'] TargetAdd('fmod_audio_fmod_audio_composite1.obj', opts=OPTS, input='fmod_audio_composite1.cxx') TargetAdd('libp3fmod_audio.dll', input='fmod_audio_fmod_audio_composite1.obj') TargetAdd('libp3fmod_audio.dll', input=COMMON_PANDA_LIBS) TargetAdd('libp3fmod_audio.dll', opts=['MODULE', 'ADVAPI', 'WINUSER', 'WINMM', 'FMODEX']) -if PkgSkip("OPENAL") == 0 and not RUNTIME: +if PkgSkip("OPENAL") == 0: OPTS=['DIR:panda/src/audiotraits', 'BUILDING:OPENAL_AUDIO', 'OPENAL'] TargetAdd('openal_audio_openal_audio_composite1.obj', opts=OPTS, input='openal_audio_composite1.cxx') TargetAdd('libp3openal_audio.dll', input='openal_audio_openal_audio_composite1.obj') @@ -4602,7 +4231,7 @@ if PkgSkip("OPENAL") == 0 and not RUNTIME: # DIRECTORY: panda/src/downloadertools/ # -if (PkgSkip("OPENSSL")==0 and not RTDIST and not RUNTIME and PkgSkip("DEPLOYTOOLS")==0): +if (PkgSkip("OPENSSL")==0 and PkgSkip("DEPLOYTOOLS")==0): OPTS=['DIR:panda/src/downloadertools', 'OPENSSL', 'ADVAPI', 'WINSOCK2', 'WINSHELL', 'WINGDI', 'WINUSER'] TargetAdd('pdecrypt_pdecrypt.obj', opts=OPTS, input='pdecrypt.cxx') @@ -4619,7 +4248,7 @@ if (PkgSkip("OPENSSL")==0 and not RTDIST and not RUNTIME and PkgSkip("DEPLOYTOOL # DIRECTORY: panda/src/downloadertools/ # -if (PkgSkip("ZLIB")==0 and not RTDIST and not RUNTIME and PkgSkip("DEPLOYTOOLS")==0): +if (PkgSkip("ZLIB")==0 and PkgSkip("DEPLOYTOOLS")==0): OPTS=['DIR:panda/src/downloadertools', 'ZLIB', 'OPENSSL', 'ADVAPI', 'WINSOCK2', 'WINSHELL', 'WINGDI', 'WINUSER'] TargetAdd('multify_multify.obj', opts=OPTS, input='multify.cxx') @@ -4641,7 +4270,7 @@ if (PkgSkip("ZLIB")==0 and not RTDIST and not RUNTIME and PkgSkip("DEPLOYTOOLS") # DIRECTORY: panda/src/windisplay/ # -if (GetTarget() == 'windows' and not RUNTIME): +if (GetTarget() == 'windows'): OPTS=['DIR:panda/src/windisplay', 'BUILDING:PANDAWIN'] TargetAdd('p3windisplay_composite1.obj', opts=OPTS+["BIGOBJ"], input='p3windisplay_composite1.cxx') TargetAdd('p3windisplay_windetectdx9.obj', opts=OPTS + ["DX9"], input='winDetectDx9.cxx') @@ -4654,7 +4283,7 @@ if (GetTarget() == 'windows' and not RUNTIME): # DIRECTORY: panda/metalibs/pandadx9/ # -if GetTarget() == 'windows' and PkgSkip("DX9")==0 and not RUNTIME: +if GetTarget() == 'windows' and PkgSkip("DX9")==0: OPTS=['DIR:panda/src/dxgsg9', 'BUILDING:PANDADX', 'DX9', 'NVIDIACG', 'CGDX9'] TargetAdd('p3dxgsg9_dxGraphicsStateGuardian9.obj', opts=OPTS, input='dxGraphicsStateGuardian9.cxx') TargetAdd('p3dxgsg9_composite1.obj', opts=OPTS, input='p3dxgsg9_composite1.cxx') @@ -4671,7 +4300,7 @@ if GetTarget() == 'windows' and PkgSkip("DX9")==0 and not RUNTIME: # DIRECTORY: panda/src/egg/ # -if not RUNTIME and not PkgSkip("EGG"): +if not PkgSkip("EGG"): OPTS=['DIR:panda/src/egg', 'BUILDING:PANDAEGG', 'ZLIB', 'BISONPREFIX_eggyy', 'FLEXDASHI'] CreateFile(GetOutputDir()+"/include/parser.h") TargetAdd('p3egg_parser.obj', opts=OPTS, input='parser.yxx') @@ -4691,7 +4320,7 @@ if not RUNTIME and not PkgSkip("EGG"): # DIRECTORY: panda/src/egg2pg/ # -if not RUNTIME and not PkgSkip("EGG"): +if not PkgSkip("EGG"): OPTS=['DIR:panda/src/egg2pg', 'BUILDING:PANDAEGG'] TargetAdd('p3egg2pg_composite1.obj', opts=OPTS, input='p3egg2pg_composite1.cxx') TargetAdd('p3egg2pg_composite2.obj', opts=OPTS, input='p3egg2pg_composite2.cxx') @@ -4705,29 +4334,28 @@ if not RUNTIME and not PkgSkip("EGG"): # DIRECTORY: panda/src/framework/ # -if (not RUNTIME): - deps = [] - # Framework wants to link in a renderer when building statically, so tell it what is available. - if GetLinkAllStatic(): - deps = ['dtool_have_gl.dat', 'dtool_have_tinydisplay.dat', 'dtool_have_egg.dat'] - if not PkgSkip("GL"): - DefSymbol("FRAMEWORK", "HAVE_GL") - if not PkgSkip("TINYDISPLAY"): - DefSymbol("FRAMEWORK", "HAVE_TINYDISPLAY") - if not PkgSkip("EGG"): - DefSymbol("FRAMEWORK", "HAVE_EGG") +deps = [] +# Framework wants to link in a renderer when building statically, so tell it what is available. +if GetLinkAllStatic(): + deps = ['dtool_have_gl.dat', 'dtool_have_tinydisplay.dat', 'dtool_have_egg.dat'] + if not PkgSkip("GL"): + DefSymbol("FRAMEWORK", "HAVE_GL") + if not PkgSkip("TINYDISPLAY"): + DefSymbol("FRAMEWORK", "HAVE_TINYDISPLAY") + if not PkgSkip("EGG"): + DefSymbol("FRAMEWORK", "HAVE_EGG") - OPTS=['DIR:panda/src/framework', 'BUILDING:FRAMEWORK', 'FRAMEWORK'] - TargetAdd('p3framework_composite1.obj', opts=OPTS, input='p3framework_composite1.cxx', dep=deps) - TargetAdd('libp3framework.dll', input='p3framework_composite1.obj') - TargetAdd('libp3framework.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libp3framework.dll', opts=['ADVAPI']) +OPTS=['DIR:panda/src/framework', 'BUILDING:FRAMEWORK', 'FRAMEWORK'] +TargetAdd('p3framework_composite1.obj', opts=OPTS, input='p3framework_composite1.cxx', dep=deps) +TargetAdd('libp3framework.dll', input='p3framework_composite1.obj') +TargetAdd('libp3framework.dll', input=COMMON_PANDA_LIBS) +TargetAdd('libp3framework.dll', opts=['ADVAPI']) # # DIRECTORY: panda/src/glgsg/ # -if (not RUNTIME and PkgSkip("GL")==0): +if (PkgSkip("GL")==0): OPTS=['DIR:panda/src/glgsg', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG'] TargetAdd('p3glgsg_config_glgsg.obj', opts=OPTS, input='config_glgsg.cxx') TargetAdd('p3glgsg_glgsg.obj', opts=OPTS, input='glgsg.cxx') @@ -4736,7 +4364,7 @@ if (not RUNTIME and PkgSkip("GL")==0): # DIRECTORY: panda/src/glesgsg/ # -if (not RUNTIME and PkgSkip("GLES")==0): +if (PkgSkip("GLES")==0): OPTS=['DIR:panda/src/glesgsg', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES', 'GLES'] TargetAdd('p3glesgsg_config_glesgsg.obj', opts=OPTS, input='config_glesgsg.cxx') TargetAdd('p3glesgsg_glesgsg.obj', opts=OPTS, input='glesgsg.cxx') @@ -4745,7 +4373,7 @@ if (not RUNTIME and PkgSkip("GLES")==0): # DIRECTORY: panda/src/gles2gsg/ # -if (not RUNTIME and PkgSkip("GLES2")==0): +if (PkgSkip("GLES2")==0): OPTS=['DIR:panda/src/gles2gsg', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES2', 'GLES2'] TargetAdd('p3gles2gsg_config_gles2gsg.obj', opts=OPTS, input='config_gles2gsg.cxx') TargetAdd('p3gles2gsg_gles2gsg.obj', opts=OPTS, input='gles2gsg.cxx') @@ -4754,7 +4382,7 @@ if (not RUNTIME and PkgSkip("GLES2")==0): # DIRECTORY: panda/metalibs/pandaegg/ # -if not RUNTIME and not PkgSkip("EGG"): +if not PkgSkip("EGG"): OPTS=['DIR:panda/metalibs/pandaegg', 'DIR:panda/src/egg', 'BUILDING:PANDAEGG'] TargetAdd('pandaegg_pandaegg.obj', opts=OPTS, input='pandaegg.cxx') @@ -4786,7 +4414,7 @@ if not RUNTIME and not PkgSkip("EGG"): # DIRECTORY: panda/src/x11display/ # -if (GetTarget() not in ['windows', 'darwin'] and PkgSkip("X11")==0 and not RUNTIME): +if (GetTarget() not in ['windows', 'darwin'] and PkgSkip("X11")==0): OPTS=['DIR:panda/src/x11display', 'BUILDING:PANDAX11', 'X11'] TargetAdd('p3x11display_composite1.obj', opts=OPTS, input='p3x11display_composite1.cxx') @@ -4794,7 +4422,7 @@ if (GetTarget() not in ['windows', 'darwin'] and PkgSkip("X11")==0 and not RUNTI # DIRECTORY: panda/src/glxdisplay/ # -if (GetTarget() not in ['windows', 'darwin'] and PkgSkip("GL")==0 and PkgSkip("X11")==0 and not RUNTIME): +if (GetTarget() not in ['windows', 'darwin'] and PkgSkip("GL")==0 and PkgSkip("X11")==0): OPTS=['DIR:panda/src/glxdisplay', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG', 'CGGL'] TargetAdd('p3glxdisplay_composite1.obj', opts=OPTS, input='p3glxdisplay_composite1.cxx') OPTS=['DIR:panda/metalibs/pandagl', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG', 'CGGL'] @@ -4811,7 +4439,7 @@ if (GetTarget() not in ['windows', 'darwin'] and PkgSkip("GL")==0 and PkgSkip("X # DIRECTORY: panda/src/cocoadisplay/ # -if (GetTarget() == 'darwin' and PkgSkip("COCOA")==0 and PkgSkip("GL")==0 and not RUNTIME): +if (GetTarget() == 'darwin' and PkgSkip("COCOA")==0 and PkgSkip("GL")==0): OPTS=['DIR:panda/src/cocoadisplay', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG', 'CGGL'] TargetAdd('p3cocoadisplay_composite1.obj', opts=OPTS, input='p3cocoadisplay_composite1.mm') OPTS=['DIR:panda/metalibs/pandagl', 'BUILDING:PANDAGL', 'GL', 'NVIDIACG', 'CGGL'] @@ -4829,7 +4457,7 @@ if (GetTarget() == 'darwin' and PkgSkip("COCOA")==0 and PkgSkip("GL")==0 and not # DIRECTORY: panda/src/wgldisplay/ # -if (GetTarget() == 'windows' and PkgSkip("GL")==0 and not RUNTIME): +if (GetTarget() == 'windows' and PkgSkip("GL")==0): OPTS=['DIR:panda/src/wgldisplay', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGL', 'NVIDIACG', 'CGGL'] TargetAdd('p3wgldisplay_composite1.obj', opts=OPTS, input='p3wgldisplay_composite1.cxx') OPTS=['DIR:panda/metalibs/pandagl', 'BUILDING:PANDAGL', 'NVIDIACG', 'CGGL'] @@ -4848,7 +4476,7 @@ if (GetTarget() == 'windows' and PkgSkip("GL")==0 and not RUNTIME): # DIRECTORY: panda/src/egldisplay/ # -if (PkgSkip("EGL")==0 and PkgSkip("GLES")==0 and PkgSkip("X11")==0 and not RUNTIME): +if (PkgSkip("EGL")==0 and PkgSkip("GLES")==0 and PkgSkip("X11")==0): DefSymbol('GLES', 'OPENGLES_1', '') OPTS=['DIR:panda/src/egldisplay', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES', 'GLES', 'EGL'] TargetAdd('pandagles_egldisplay_composite1.obj', opts=OPTS, input='p3egldisplay_composite1.cxx') @@ -4866,7 +4494,7 @@ if (PkgSkip("EGL")==0 and PkgSkip("GLES")==0 and PkgSkip("X11")==0 and not RUNTI # DIRECTORY: panda/src/egldisplay/ # -if (PkgSkip("EGL")==0 and PkgSkip("GLES2")==0 and PkgSkip("X11")==0 and not RUNTIME): +if (PkgSkip("EGL")==0 and PkgSkip("GLES2")==0 and PkgSkip("X11")==0): DefSymbol('GLES2', 'OPENGLES_2', '') OPTS=['DIR:panda/src/egldisplay', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES2', 'GLES2', 'EGL'] TargetAdd('pandagles2_egldisplay_composite1.obj', opts=OPTS, input='p3egldisplay_composite1.cxx') @@ -4883,7 +4511,7 @@ if (PkgSkip("EGL")==0 and PkgSkip("GLES2")==0 and PkgSkip("X11")==0 and not RUNT # # DIRECTORY: panda/src/ode/ # -if (PkgSkip("ODE")==0 and not RUNTIME): +if (PkgSkip("ODE")==0): OPTS=['DIR:panda/src/ode', 'BUILDING:PANDAODE', 'ODE'] TargetAdd('p3ode_composite1.obj', opts=OPTS, input='p3ode_composite1.cxx') TargetAdd('p3ode_composite2.obj', opts=OPTS, input='p3ode_composite2.cxx') @@ -4900,7 +4528,7 @@ if (PkgSkip("ODE")==0 and not RUNTIME): # # DIRECTORY: panda/metalibs/pandaode/ # -if (PkgSkip("ODE")==0 and not RUNTIME): +if (PkgSkip("ODE")==0): OPTS=['DIR:panda/metalibs/pandaode', 'BUILDING:PANDAODE', 'ODE'] TargetAdd('pandaode_pandaode.obj', opts=OPTS, input='pandaode.cxx') @@ -4927,7 +4555,7 @@ if (PkgSkip("ODE")==0 and not RUNTIME): # # DIRECTORY: panda/src/bullet/ # -if (PkgSkip("BULLET")==0 and not RUNTIME): +if (PkgSkip("BULLET")==0): OPTS=['DIR:panda/src/bullet', 'BUILDING:PANDABULLET', 'BULLET'] TargetAdd('p3bullet_composite.obj', opts=OPTS, input='p3bullet_composite.cxx') @@ -4939,7 +4567,7 @@ if (PkgSkip("BULLET")==0 and not RUNTIME): # # DIRECTORY: panda/metalibs/pandabullet/ # -if (PkgSkip("BULLET")==0 and not RUNTIME): +if (PkgSkip("BULLET")==0): OPTS=['DIR:panda/metalibs/pandabullet', 'BUILDING:PANDABULLET', 'BULLET'] TargetAdd('pandabullet_pandabullet.obj', opts=OPTS, input='pandabullet.cxx') @@ -5002,7 +4630,7 @@ if (PkgSkip("PHYSX")==0): # DIRECTORY: panda/src/physics/ # -if (PkgSkip("PANDAPHYSICS")==0) and (not RUNTIME): +if (PkgSkip("PANDAPHYSICS")==0): OPTS=['DIR:panda/src/physics', 'BUILDING:PANDAPHYSICS'] TargetAdd('p3physics_composite1.obj', opts=OPTS, input='p3physics_composite1.cxx') TargetAdd('p3physics_composite2.obj', opts=OPTS, input='p3physics_composite2.cxx') @@ -5017,7 +4645,7 @@ if (PkgSkip("PANDAPHYSICS")==0) and (not RUNTIME): # DIRECTORY: panda/src/particlesystem/ # -if (PkgSkip("PANDAPHYSICS")==0) and (PkgSkip("PANDAPARTICLESYSTEM")==0) and (not RUNTIME): +if (PkgSkip("PANDAPHYSICS")==0) and (PkgSkip("PANDAPARTICLESYSTEM")==0): OPTS=['DIR:panda/src/particlesystem', 'BUILDING:PANDAPHYSICS'] TargetAdd('p3particlesystem_composite1.obj', opts=OPTS, input='p3particlesystem_composite1.cxx') TargetAdd('p3particlesystem_composite2.obj', opts=OPTS, input='p3particlesystem_composite2.cxx') @@ -5036,7 +4664,7 @@ if (PkgSkip("PANDAPHYSICS")==0) and (PkgSkip("PANDAPARTICLESYSTEM")==0) and (not # DIRECTORY: panda/metalibs/pandaphysics/ # -if (PkgSkip("PANDAPHYSICS")==0) and (not RUNTIME): +if (PkgSkip("PANDAPHYSICS")==0): OPTS=['DIR:panda/metalibs/pandaphysics', 'BUILDING:PANDAPHYSICS'] TargetAdd('pandaphysics_pandaphysics.obj', opts=OPTS, input='pandaphysics.cxx') @@ -5091,7 +4719,7 @@ if (PkgSkip("SPEEDTREE")==0): # DIRECTORY: panda/src/testbed/ # -if (not RTDIST and not RUNTIME and PkgSkip("PVIEW")==0): +if (PkgSkip("PVIEW")==0): OPTS=['DIR:panda/src/testbed'] TargetAdd('pview_pview.obj', opts=OPTS, input='pview.cxx') TargetAdd('pview.exe', input='pview_pview.obj') @@ -5108,7 +4736,7 @@ if (not RTDIST and not RUNTIME and PkgSkip("PVIEW")==0): # DIRECTORY: panda/src/android/ # -if (not RUNTIME and GetTarget() == 'android'): +if (GetTarget() == 'android'): OPTS=['DIR:panda/src/android'] TargetAdd('org/panda3d/android/NativeIStream.class', opts=OPTS, input='NativeIStream.java') TargetAdd('org/panda3d/android/NativeOStream.class', opts=OPTS, input='NativeOStream.java') @@ -5123,7 +4751,7 @@ if (not RUNTIME and GetTarget() == 'android'): TargetAdd('android_native_app_glue.obj', opts=OPTS + ['NOHIDDEN'], input='android_native_app_glue.c') TargetAdd('android_main.obj', opts=OPTS, input='android_main.cxx') - if (not RTDIST and PkgSkip("PVIEW")==0): + if (PkgSkip("PVIEW")==0): TargetAdd('libpview_pview.obj', opts=OPTS, input='pview.cxx') TargetAdd('libpview.dll', input='android_native_app_glue.obj') TargetAdd('libpview.dll', input='android_main.obj') @@ -5135,7 +4763,7 @@ if (not RUNTIME and GetTarget() == 'android'): TargetAdd('libpview.dll', input=COMMON_PANDA_LIBS) TargetAdd('libpview.dll', opts=['MODULE', 'ANDROID']) - if (not RTDIST and PkgSkip("PYTHON")==0): + if (PkgSkip("PYTHON")==0): OPTS += ['PYTHON'] TargetAdd('ppython_ppython.obj', opts=OPTS, input='python_main.cxx') TargetAdd('libppython.dll', input='android_native_app_glue.obj') @@ -5150,7 +4778,7 @@ if (not RUNTIME and GetTarget() == 'android'): # DIRECTORY: panda/src/androiddisplay/ # -if (GetTarget() == 'android' and PkgSkip("EGL")==0 and PkgSkip("GLES")==0 and not RUNTIME): +if (GetTarget() == 'android' and PkgSkip("EGL")==0 and PkgSkip("GLES")==0): DefSymbol('GLES', 'OPENGLES_1', '') OPTS=['DIR:panda/src/androiddisplay', 'DIR:panda/src/glstuff', 'BUILDING:PANDAGLES', 'GLES', 'EGL'] TargetAdd('pandagles_androiddisplay_composite1.obj', opts=OPTS, input='p3androiddisplay_composite1.cxx') @@ -5168,7 +4796,7 @@ if (GetTarget() == 'android' and PkgSkip("EGL")==0 and PkgSkip("GLES")==0 and no # DIRECTORY: panda/src/tinydisplay/ # -if (not RUNTIME and (GetTarget() in ('windows', 'darwin') or PkgSkip("X11")==0) and PkgSkip("TINYDISPLAY")==0): +if ((GetTarget() in ('windows', 'darwin') or PkgSkip("X11")==0) and PkgSkip("TINYDISPLAY")==0): OPTS=['DIR:panda/src/tinydisplay', 'BUILDING:TINYDISPLAY', 'X11'] TargetAdd('p3tinydisplay_composite1.obj', opts=OPTS, input='p3tinydisplay_composite1.cxx') TargetAdd('p3tinydisplay_composite2.obj', opts=OPTS, input='p3tinydisplay_composite2.cxx') @@ -5344,7 +4972,7 @@ if (PkgSkip("DIRECT")==0): # DIRECTORY: direct/src/dcparse/ # -if (PkgSkip("DIRECT")==0 and not RTDIST and not RUNTIME): +if (PkgSkip("DIRECT")==0): OPTS=['DIR:direct/src/dcparse', 'DIR:direct/src/dcparser', 'WITHINPANDA', 'ADVAPI'] TargetAdd('dcparse_dcparse.obj', opts=OPTS, input='dcparse.cxx') TargetAdd('p3dcparse.exe', input='dcparse_dcparse.obj') @@ -5352,308 +4980,6 @@ if (PkgSkip("DIRECT")==0 and not RTDIST and not RUNTIME): TargetAdd('p3dcparse.exe', input=COMMON_PANDA_LIBS) TargetAdd('p3dcparse.exe', opts=['ADVAPI']) -# -# DIRECTORY: direct/src/plugin/ -# - -if (RTDIST or RUNTIME): - # Explicitly define this as we don't include dtool_config.h here. - if GetTarget() not in ('windows', 'darwin'): - DefSymbol("RUNTIME", "HAVE_X11", "1") - - OPTS=['DIR:direct/src/plugin', 'BUILDING:P3D_PLUGIN', 'RUNTIME', 'OPENSSL'] - TargetAdd('plugin_common.obj', opts=OPTS, input='plugin_common_composite1.cxx') - - OPTS += ['ZLIB', 'MSIMG'] - TargetAdd('plugin_plugin.obj', opts=OPTS, input='p3d_plugin_composite1.cxx') - TargetAdd('plugin_mkdir_complete.obj', opts=OPTS, input='mkdir_complete.cxx') - TargetAdd('plugin_wstring_encode.obj', opts=OPTS, input='wstring_encode.cxx') - TargetAdd('plugin_parse_color.obj', opts=OPTS, input='parse_color.cxx') - TargetAdd('plugin_get_twirl_data.obj', opts=OPTS, input='get_twirl_data.cxx') - TargetAdd('plugin_find_root_dir.obj', opts=OPTS, input='find_root_dir.cxx') - if GetTarget() == 'darwin': - TargetAdd('plugin_find_root_dir_assist.obj', opts=OPTS, input='find_root_dir_assist.mm') - TargetAdd('plugin_binaryXml.obj', opts=OPTS, input='binaryXml.cxx') - TargetAdd('plugin_fileSpec.obj', opts=OPTS, input='fileSpec.cxx') - TargetAdd('plugin_handleStream.obj', opts=OPTS, input='handleStream.cxx') - TargetAdd('plugin_handleStreamBuf.obj', opts=OPTS, input='handleStreamBuf.cxx') - if (RTDIST): - for fname in ("p3d_plugin.dll", "libp3d_plugin_static.ilb"): - TargetAdd(fname, input='plugin_plugin.obj') - TargetAdd(fname, input='plugin_mkdir_complete.obj') - TargetAdd(fname, input='plugin_wstring_encode.obj') - TargetAdd(fname, input='plugin_parse_color.obj') - TargetAdd(fname, input='plugin_find_root_dir.obj') - if GetTarget() == 'darwin': - TargetAdd(fname, input='plugin_find_root_dir_assist.obj') - TargetAdd(fname, input='plugin_fileSpec.obj') - TargetAdd(fname, input='plugin_binaryXml.obj') - TargetAdd(fname, input='plugin_handleStream.obj') - TargetAdd(fname, input='plugin_handleStreamBuf.obj') - TargetAdd(fname, input='libp3tinyxml.ilb') - if GetTarget() == 'darwin': - TargetAdd(fname, input='libp3subprocbuffer.ilb') - TargetAdd(fname, opts=['OPENSSL', 'ZLIB', 'X11', 'ADVAPI', 'WINUSER', 'WINGDI', 'WINSHELL', 'WINCOMCTL', 'WINOLE', 'MSIMG']) - TargetAdd("libp3d_plugin_static.ilb", input='plugin_get_twirl_data.obj') - - if (PkgSkip("PYTHON")==0 and RTDIST): - # Freeze VFSImporter and its dependency modules into p3dpython. - # Mark panda3d.core as a dependency to make sure to build that first. - TargetAdd('p3dpython_frozen.obj', input='VFSImporter.py', opts=['DIR:direct/src/showbase', 'FREEZE_STARTUP']) - TargetAdd('p3dpython_frozen.obj', dep='core.pyd') - - OPTS += ['PYTHON'] - TargetAdd('p3dpython_p3dpython_composite1.obj', opts=OPTS, input='p3dpython_composite1.cxx') - TargetAdd('p3dpython_p3dPythonMain.obj', opts=OPTS, input='p3dPythonMain.cxx') - TargetAdd('p3dpython.exe', input='p3dpython_p3dpython_composite1.obj') - TargetAdd('p3dpython.exe', input='p3dpython_p3dPythonMain.obj') - TargetAdd('p3dpython.exe', input='p3dpython_frozen.obj') - TargetAdd('p3dpython.exe', input=COMMON_PANDA_LIBS) - TargetAdd('p3dpython.exe', input='libp3tinyxml.ilb') - TargetAdd('p3dpython.exe', input='libp3interrogatedb.dll') - TargetAdd('p3dpython.exe', opts=['PYTHON', 'WINUSER']) - - TargetAdd('libp3dpython.dll', input='p3dpython_p3dpython_composite1.obj') - TargetAdd('libp3dpython.dll', input='p3dpython_frozen.obj') - TargetAdd('libp3dpython.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libp3dpython.dll', input='libp3tinyxml.ilb') - TargetAdd('libp3dpython.dll', input='libp3interrogatedb.dll') - TargetAdd('libp3dpython.dll', opts=['PYTHON', 'WINUSER']) - - if GetTarget() == 'windows': - DefSymbol("NON_CONSOLE", "NON_CONSOLE", "") - OPTS.append("NON_CONSOLE") - TargetAdd('p3dpythonw_p3dpython_composite1.obj', opts=OPTS, input='p3dpython_composite1.cxx') - TargetAdd('p3dpythonw_p3dPythonMain.obj', opts=OPTS, input='p3dPythonMain.cxx') - TargetAdd('p3dpythonw.exe', input='p3dpythonw_p3dpython_composite1.obj') - TargetAdd('p3dpythonw.exe', input='p3dpythonw_p3dPythonMain.obj') - TargetAdd('p3dpythonw.exe', input='p3dpython_frozen.obj') - TargetAdd('p3dpythonw.exe', input=COMMON_PANDA_LIBS) - TargetAdd('p3dpythonw.exe', input='libp3tinyxml.ilb') - TargetAdd('p3dpythonw.exe', input='libp3interrogatedb.dll') - TargetAdd('p3dpythonw.exe', opts=['SUBSYSTEM:WINDOWS', 'WINUSER']) - - if (PkgSkip("OPENSSL")==0 and RTDIST and False): - OPTS=['DIR:direct/src/plugin', 'DIR:panda/src/express', 'OPENSSL'] - if GetTarget() == 'darwin': - OPTS += ['OPT:2'] - if (PkgSkip("FLTK")==0): - OPTS.append("FLTK") - TargetAdd('plugin_p3dCert.obj', opts=OPTS, input='p3dCert.cxx') - TargetAdd('plugin_p3dCert_strings.obj', opts=OPTS, input='p3dCert_strings.cxx') - TargetAdd('p3dcert.exe', input='plugin_mkdir_complete.obj') - TargetAdd('p3dcert.exe', input='plugin_wstring_encode.obj') - TargetAdd('p3dcert.exe', input='plugin_p3dCert.obj') - TargetAdd('p3dcert.exe', input='plugin_p3dCert_strings.obj') - OPTS=['SUBSYSTEM:WINDOWS', 'OPENSSL', 'FLTK', 'X11', 'WINCOMCTL', 'WINSOCK', 'WINGDI', 'WINUSER', 'ADVAPI', 'WINOLE', 'WINSHELL', 'SUBSYSTEM:WINDOWS'] - if GetTarget() == 'darwin': - OPTS += ['OPT:2'] - TargetAdd('p3dcert.exe', opts=OPTS) - elif (PkgSkip("WX")==0): - OPTS += ["WX", "RTTI"] - TargetAdd('plugin_p3dCert.obj', opts=OPTS, input='p3dCert_wx.cxx') - TargetAdd('p3dcert.exe', input='plugin_mkdir_complete.obj') - TargetAdd('p3dcert.exe', input='plugin_wstring_encode.obj') - TargetAdd('p3dcert.exe', input='plugin_p3dCert.obj') - OPTS=['SUBSYSTEM:WINDOWS', 'OPENSSL', 'WX', 'CARBON', 'WINOLE', 'WINOLEAUT', 'WINUSER', 'ADVAPI', 'WINSHELL', 'WINCOMCTL', 'WINGDI', 'WINCOMDLG'] - if GetTarget() == "darwin": - OPTS += ['GL', 'OPT:2'] - TargetAdd('p3dcert.exe', opts=OPTS) - -# -# DIRECTORY: direct/src/plugin_npapi/ -# - -if RUNTIME: - OPTS=['DIR:direct/src/plugin_npapi', 'RUNTIME', 'GTK2'] - if GetTarget() == 'windows': - nppanda3d_rc = {"name" : "Panda3D Game Engine Plug-in", - "version" : VERSION, - "description" : "Runs 3-D games and interactive applets", - "filename" : "nppanda3d.dll", - "mimetype" : "application/x-panda3d", - "extension" : "p3d", - "filedesc" : "Panda3D applet"} - TargetAdd('nppanda3d.res', opts=OPTS, winrc=nppanda3d_rc) - elif GetTarget() == 'darwin': - TargetAdd('nppanda3d.rsrc', opts=OPTS, input='nppanda3d.r') - - OPTS += ['GTK2'] - TargetAdd('plugin_npapi_nppanda3d_composite1.obj', opts=OPTS, input='nppanda3d_composite1.cxx') - - TargetAdd('nppanda3d.plugin', input='plugin_common.obj') - TargetAdd('nppanda3d.plugin', input='plugin_parse_color.obj') - TargetAdd('nppanda3d.plugin', input='plugin_get_twirl_data.obj') - TargetAdd('nppanda3d.plugin', input='plugin_wstring_encode.obj') - TargetAdd('nppanda3d.plugin', input='plugin_npapi_nppanda3d_composite1.obj') - if GetTarget() == 'windows': - TargetAdd('nppanda3d.plugin', input='nppanda3d.res') - TargetAdd('nppanda3d.plugin', input='nppanda3d.def', ipath=OPTS) - elif GetTarget() == 'darwin': - TargetAdd('nppanda3d.plugin', input='nppanda3d.rsrc') - TargetAdd('nppanda3d.plugin', input='nppanda3d.plist', ipath=OPTS) - TargetAdd('nppanda3d.plugin', input='plugin_find_root_dir_assist.obj') - TargetAdd('nppanda3d.plugin', input='libp3tinyxml.ilb') - TargetAdd('nppanda3d.plugin', opts=['OPENSSL', 'WINGDI', 'WINUSER', 'WINSHELL', 'WINOLE', 'CARBON']) - -# -# DIRECTORY: direct/src/plugin_activex/ -# - -if (RUNTIME and GetTarget() == 'windows' and PkgSkip("MFC")==0): - OPTS=['DIR:direct/src/plugin_activex', 'RUNTIME', 'ACTIVEX', 'MFC'] - DefSymbol('ACTIVEX', '_USRDLL', '') - DefSymbol('ACTIVEX', '_WINDLL', '') - DefSymbol('ACTIVEX', '_AFXDLL', '') - DefSymbol('ACTIVEX', '_MBCS', '') - TargetAdd('P3DActiveX.tlb', opts=OPTS, input='P3DActiveX.idl') - TargetAdd('P3DActiveX.res', opts=OPTS, input='P3DActiveX.rc') - - TargetAdd('plugin_activex_p3dactivex_composite1.obj', opts=OPTS, input='p3dactivex_composite1.cxx') - - TargetAdd('p3dactivex.ocx', input='plugin_common.obj') - TargetAdd('p3dactivex.ocx', input='plugin_parse_color.obj') - TargetAdd('p3dactivex.ocx', input='plugin_get_twirl_data.obj') - TargetAdd('p3dactivex.ocx', input='plugin_wstring_encode.obj') - TargetAdd('p3dactivex.ocx', input='plugin_activex_p3dactivex_composite1.obj') - TargetAdd('p3dactivex.ocx', input='P3DActiveX.res') - TargetAdd('p3dactivex.ocx', input='P3DActiveX.def', ipath=OPTS) - TargetAdd('p3dactivex.ocx', input='libp3tinyxml.ilb') - TargetAdd('p3dactivex.ocx', opts=['MFC', 'WINSOCK2', 'OPENSSL', 'WINGDI', 'WINUSER']) - -# -# DIRECTORY: direct/src/plugin_standalone/ -# - -if (RUNTIME): - OPTS=['DIR:direct/src/plugin_standalone', 'RUNTIME', 'OPENSSL'] - TargetAdd('plugin_standalone_panda3d.obj', opts=OPTS, input='panda3d.cxx') - TargetAdd('plugin_standalone_panda3dBase.obj', opts=OPTS, input='panda3dBase.cxx') - - if GetTarget() == 'windows': - panda3d_rc = {"name" : "Panda3D Game Engine Plug-in", - "version" : VERSION, - "description" : "Runs 3-D games and interactive applets", - "filename" : "panda3d.exe", - "mimetype" : "application/x-panda3d", - "extension" : "p3d", - "filedesc" : "Panda3D applet", - "icon" : "panda3d.ico"} - TargetAdd('panda3d.res', opts=OPTS, winrc=panda3d_rc) - - TargetAdd('plugin_standalone_panda3dMain.obj', opts=OPTS, input='panda3dMain.cxx') - TargetAdd('panda3d.exe', input='plugin_standalone_panda3d.obj') - TargetAdd('panda3d.exe', input='plugin_standalone_panda3dMain.obj') - TargetAdd('panda3d.exe', input='plugin_standalone_panda3dBase.obj') - TargetAdd('panda3d.exe', input='plugin_common.obj') - TargetAdd('panda3d.exe', input='plugin_wstring_encode.obj') - if GetTarget() == 'darwin': - TargetAdd('panda3d.exe', input='plugin_find_root_dir_assist.obj') - elif GetTarget() == 'windows': - TargetAdd('panda3d.exe', input='panda3d.res') - TargetAdd('panda3d.exe', input='libpandaexpress.dll') - TargetAdd('panda3d.exe', input='libp3dtoolconfig.dll') - TargetAdd('panda3d.exe', input='libp3dtool.dll') - TargetAdd('panda3d.exe', input='libp3tinyxml.ilb') - TargetAdd('panda3d.exe', opts=['NOICON', 'OPENSSL', 'ZLIB', 'WINGDI', 'WINUSER', 'WINSHELL', 'ADVAPI', 'WINSOCK2', 'WINOLE', 'CARBON']) - - if (GetTarget() == 'darwin'): - TargetAdd('plugin_standalone_panda3dMac.obj', opts=OPTS, input='panda3dMac.cxx') - TargetAdd('Panda3D.app', input='plugin_standalone_panda3d.obj') - TargetAdd('Panda3D.app', input='plugin_standalone_panda3dMac.obj') - TargetAdd('Panda3D.app', input='plugin_standalone_panda3dBase.obj') - TargetAdd('Panda3D.app', input='plugin_common.obj') - TargetAdd('Panda3D.app', input='plugin_find_root_dir_assist.obj') - TargetAdd('Panda3D.app', input='libpandaexpress.dll') - TargetAdd('Panda3D.app', input='libp3dtoolconfig.dll') - TargetAdd('Panda3D.app', input='libp3dtool.dll') - TargetAdd('Panda3D.app', input='libp3tinyxml.ilb') - TargetAdd('Panda3D.app', input='panda3d_mac.plist', ipath=OPTS) - TargetAdd('Panda3D.app', input='models/plugin_images/panda3d.icns') - TargetAdd('Panda3D.app', opts=['OPENSSL', 'ZLIB', 'WINGDI', 'WINUSER', 'WINSHELL', 'ADVAPI', 'WINSOCK2', 'WINOLE', 'CARBON']) - elif (GetTarget() == 'windows'): - TargetAdd('plugin_standalone_panda3dWinMain.obj', opts=OPTS, input='panda3dWinMain.cxx') - TargetAdd('panda3dw.exe', input='plugin_standalone_panda3d.obj') - TargetAdd('panda3dw.exe', input='plugin_standalone_panda3dWinMain.obj') - TargetAdd('panda3dw.exe', input='plugin_standalone_panda3dBase.obj') - TargetAdd('panda3dw.exe', input='plugin_wstring_encode.obj') - TargetAdd('panda3dw.exe', input='plugin_common.obj') - TargetAdd('panda3dw.exe', input='libpandaexpress.dll') - TargetAdd('panda3dw.exe', input='libp3dtoolconfig.dll') - TargetAdd('panda3dw.exe', input='libp3dtool.dll') - TargetAdd('panda3dw.exe', input='libp3tinyxml.ilb') - TargetAdd('panda3dw.exe', opts=['SUBSYSTEM:WINDOWS', 'OPENSSL', 'ZLIB', 'WINGDI', 'WINUSER', 'WINSHELL', 'ADVAPI', 'WINSOCK2', 'WINOLE', 'CARBON']) - -if (RTDIST): - OPTS=['BUILDING:P3D_PLUGIN', 'DIR:direct/src/plugin_standalone', 'DIR:direct/src/plugin', 'DIR:dtool/src/dtoolbase', 'DIR:dtool/src/dtoolutil', 'DIR:dtool/src/prc', 'DIR:dtool/src/dconfig', 'DIR:panda/src/express', 'DIR:panda/src/downloader', 'RUNTIME', 'P3DEMBED', 'OPENSSL', 'ZLIB'] - # This is arguably a big fat ugly hack, but doing it otherwise would complicate the build process considerably. - DefSymbol("P3DEMBED", "LINK_ALL_STATIC", "") - TargetAdd('plugin_standalone_panda3dBase.obj', opts=OPTS, input='panda3dBase.cxx') - TargetAdd('plugin_standalone_p3dEmbedMain.obj', opts=OPTS, input='p3dEmbedMain.cxx') - TargetAdd('plugin_standalone_p3dEmbed.obj', opts=OPTS, input='p3dEmbed.cxx') - TargetAdd('plugin_standalone_dtoolbase_composite1.obj', opts=OPTS, input='p3dtoolbase_composite1.cxx') - TargetAdd('plugin_standalone_dtoolbase_composite2.obj', opts=OPTS, input='p3dtoolbase_composite2.cxx') - TargetAdd('plugin_standalone_lookup3.obj', opts=OPTS, input='lookup3.c') - TargetAdd('plugin_standalone_indent.obj', opts=OPTS, input='indent.cxx') - TargetAdd('plugin_standalone_dtoolutil_composite1.obj', opts=OPTS, input='p3dtoolutil_composite1.cxx') - TargetAdd('plugin_standalone_dtoolutil_composite2.obj', opts=OPTS, input='p3dtoolutil_composite2.cxx') - if (GetTarget() == 'darwin'): - TargetAdd('plugin_standalone_dtoolutil_filename_assist.obj', opts=OPTS, input='filename_assist.mm') - TargetAdd('plugin_standalone_prc_composite1.obj', opts=OPTS, input='p3prc_composite1.cxx') - TargetAdd('plugin_standalone_prc_composite2.obj', opts=OPTS, input='p3prc_composite2.cxx') - TargetAdd('plugin_standalone_express_composite1.obj', opts=OPTS, input='p3express_composite1.cxx') - TargetAdd('plugin_standalone_express_composite2.obj', opts=OPTS, input='p3express_composite2.cxx') - TargetAdd('plugin_standalone_downloader_composite1.obj', opts=OPTS, input='p3downloader_composite1.cxx') - TargetAdd('plugin_standalone_downloader_composite2.obj', opts=OPTS, input='p3downloader_composite2.cxx') - TargetAdd('p3dembed.exe', input='plugin_standalone_panda3dBase.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_p3dEmbedMain.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_p3dEmbed.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_dtoolbase_composite1.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_dtoolbase_composite2.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_lookup3.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_indent.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_dtoolutil_composite1.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_dtoolutil_composite2.obj') - if GetTarget() == 'darwin': - TargetAdd('p3dembed.exe', input='plugin_standalone_dtoolutil_filename_assist.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_prc_composite1.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_prc_composite2.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_express_composite1.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_express_composite2.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_downloader_composite1.obj') - TargetAdd('p3dembed.exe', input='plugin_standalone_downloader_composite2.obj') - TargetAdd('p3dembed.exe', input='plugin_common.obj') - if GetTarget() == 'darwin': - TargetAdd('p3dembed.exe', input='plugin_find_root_dir_assist.obj') - TargetAdd('p3dembed.exe', input='libp3subprocbuffer.ilb') - TargetAdd('p3dembed.exe', input='libp3tinyxml.ilb') - TargetAdd('p3dembed.exe', input='libp3d_plugin_static.ilb') - TargetAdd('p3dembed.exe', opts=['NOICON', 'WINGDI', 'WINSOCK2', 'ZLIB', 'WINUSER', 'OPENSSL', 'WINOLE', 'CARBON', 'MSIMG', 'WINCOMCTL', 'ADVAPI', 'WINSHELL', 'X11']) - - if GetTarget() == 'windows': - OPTS.append("P3DEMBEDW") - DefSymbol("P3DEMBEDW", "P3DEMBEDW", "") - TargetAdd('plugin_standalone_p3dEmbedWinMain.obj', opts=OPTS, input='p3dEmbedMain.cxx') - TargetAdd('p3dembedw.exe', input='plugin_standalone_panda3dBase.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_p3dEmbedWinMain.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_p3dEmbed.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_dtoolbase_composite1.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_dtoolbase_composite2.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_lookup3.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_indent.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_dtoolutil_composite1.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_dtoolutil_composite2.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_prc_composite1.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_prc_composite2.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_express_composite1.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_express_composite2.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_downloader_composite1.obj') - TargetAdd('p3dembedw.exe', input='plugin_standalone_downloader_composite2.obj') - TargetAdd('p3dembedw.exe', input='plugin_common.obj') - TargetAdd('p3dembedw.exe', input='libp3tinyxml.ilb') - TargetAdd('p3dembedw.exe', input='libp3d_plugin_static.ilb') - TargetAdd('p3dembedw.exe', opts=['SUBSYSTEM:WINDOWS', 'NOICON', 'WINGDI', 'WINSOCK2', 'ZLIB', 'WINUSER', 'OPENSSL', 'WINOLE', 'MSIMG', 'WINCOMCTL', 'ADVAPI', 'WINSHELL']) - # # DIRECTORY: pandatool/src/pandatoolbase/ # @@ -6467,7 +5793,7 @@ for VER in MAYAVERSIONS: # # DIRECTORY: contrib/src/ai/ # -if (PkgSkip("CONTRIB")==0 and not RUNTIME): +if (PkgSkip("CONTRIB")==0 ): OPTS=['DIR:contrib/src/ai', 'BUILDING:PANDAAI'] TargetAdd('p3ai_composite1.obj', opts=OPTS, input='p3ai_composite1.cxx') TargetAdd('libpandaai.dll', input='p3ai_composite1.obj') @@ -6491,7 +5817,7 @@ if (PkgSkip("CONTRIB")==0 and not RUNTIME): # # DIRECTORY: contrib/src/rplight/ # -if not PkgSkip("CONTRIB") and not PkgSkip("PYTHON") and not RUNTIME: +if not PkgSkip("CONTRIB") and not PkgSkip("PYTHON"): OPTS=['DIR:contrib/src/rplight', 'BUILDING:RPLIGHT'] TargetAdd('p3rplight_composite1.obj', opts=OPTS, input='p3rplight_composite1.cxx') @@ -6543,7 +5869,7 @@ if PkgSkip("PYTHON") == 0: # Generate the models directory and samples directory # -if not PkgSkip("DIRECT") and not RUNTIME and not PkgSkip("EGG"): +if not PkgSkip("DIRECT") and not PkgSkip("EGG"): model_extensions = ["*.egg"] # Check if we have access to an flt2egg utility, either self-compiled or on the system. @@ -6551,27 +5877,27 @@ if not PkgSkip("DIRECT") and not RUNTIME and not PkgSkip("EGG"): model_extensions.append("*.flt") for model in GetDirectoryContents("dmodels/src/misc", model_extensions): - if (PkgSkip("ZLIB")==0 and PkgSkip("DEPLOYTOOLS")==0 and not RTDIST): + if (PkgSkip("ZLIB")==0 and PkgSkip("DEPLOYTOOLS")==0): newname = model[:-4] + ".egg.pz" else: newname = model[:-4] + ".egg" TargetAdd(GetOutputDir()+"/models/misc/"+newname, input="dmodels/src/misc/"+model) for model in GetDirectoryContents("dmodels/src/gui", model_extensions): - if (PkgSkip("ZLIB")==0 and PkgSkip("DEPLOYTOOLS")==0 and not RTDIST): + if (PkgSkip("ZLIB")==0 and PkgSkip("DEPLOYTOOLS")==0): newname = model[:-4] + ".egg.pz" else: newname = model[:-4] + ".egg" TargetAdd(GetOutputDir()+"/models/gui/"+newname, input="dmodels/src/gui/"+model) for model in GetDirectoryContents("models", model_extensions): - if (PkgSkip("ZLIB")==0 and PkgSkip("DEPLOYTOOLS")==0 and not RTDIST): + if (PkgSkip("ZLIB")==0 and PkgSkip("DEPLOYTOOLS")==0): newname = model[:-4] + ".egg.pz" else: newname = model[:-4] + ".egg" TargetAdd(GetOutputDir()+"/models/"+newname, input="models/"+model) -if not PkgSkip("DIRECT") and not RUNTIME: +if not PkgSkip("DIRECT"): CopyAllFiles(GetOutputDir()+"/models/audio/sfx/", "dmodels/src/audio/sfx/", ".wav") CopyAllFiles(GetOutputDir()+"/models/icons/", "dmodels/src/icons/", ".gif") @@ -6585,28 +5911,6 @@ if not PkgSkip("DIRECT") and not RUNTIME: CopyAllFiles(GetOutputDir()+"/models/maps/", "dmodels/src/maps/", ".rgb") CopyAllFiles(GetOutputDir()+"/models/maps/", "dmodels/src/maps/", ".rgba") -# -# Build the rtdist. -# - -if (RTDIST): - OPTS=['DIR:direct/src/p3d'] - TargetAdd('_panda3d', opts=OPTS, input='panda3d.pdef') - TargetAdd('_coreapi', opts=OPTS, input='coreapi.pdef') - TargetAdd('_thirdparty', opts=OPTS, input='thirdparty.pdef') - -# -# If we have a host URL and distributor, we can make .p3d deployment tools. -# - -if not PkgSkip("DIRECT") and not PkgSkip("DEPLOYTOOLS") and not RUNTIME and not RTDIST and HOST_URL and DISTRIBUTOR: - OPTS=['DIR:direct/src/p3d'] - - TargetAdd('packp3d.p3d', opts=OPTS, input='panda3d.pdef') - TargetAdd('pdeploy.p3d', opts=OPTS, input='panda3d.pdef') - TargetAdd('pmerge.p3d', opts=OPTS, input='panda3d.pdef') - TargetAdd('ppackage.p3d', opts=OPTS, input='panda3d.pdef') - TargetAdd('ppatcher.p3d', opts=OPTS, input='panda3d.pdef') ########################################################################################## # @@ -6778,7 +6082,7 @@ if INSTALLER: MakeInstaller(version=VERSION, outputdir=GetOutputDir(), optimize=GetOptimize(), compressor=COMPRESSOR, debversion=DEBVERSION, rpmrelease=RPMRELEASE, - runtime=RUNTIME, python_versions=python_versions) + python_versions=python_versions) if WHEEL: ProgressOutput(100.0, "Building wheel") diff --git a/makepanda/makepanda.vcproj b/makepanda/makepanda.vcproj index c521d6964c..06b9cd8f07 100644 --- a/makepanda/makepanda.vcproj +++ b/makepanda/makepanda.vcproj @@ -5302,27 +5302,6 @@ - - - - - - - - - - - - - - - - - - - - - @@ -5401,133 +5380,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -5538,32 +5390,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -5587,22 +5413,6 @@ - - - - - - - - - - - - - - - - diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 932210f9c7..b9e80ed0f0 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -3221,32 +3221,6 @@ def ParsePandaVersion(fn): except: pass return "0.0.0" -def ParsePluginVersion(fn): - try: - f = open(fn, "r") - pattern = re.compile('^[ \t]*[#][ \t]*define[ \t]+P3D_PLUGIN_VERSION[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)') - for line in f: - match = pattern.match(line,0) - if (match): - f.close() - return match.group(1) + "." + match.group(2) + "." + match.group(3) - f.close() - except: pass - return "0.0.0" - -def ParseCoreapiVersion(fn): - try: - f = open(fn, "r") - pattern = re.compile('^[ \t]*[#][ \t]*define[ \t]+P3D_COREAPI_VERSION.*([0-9]+)[ \t]*$') - for line in f: - match = pattern.match(line,0) - if (match): - f.close() - return match.group(1) - f.close() - except: pass - return "0" - ########################################################################################## # # Utility function to generate a resource file @@ -3429,7 +3403,6 @@ def CalcLocation(fn, ipath): if (fn.endswith(".py")): return CxxFindSource(fn, ipath) if (fn.endswith(".yxx")): return CxxFindSource(fn, ipath) if (fn.endswith(".lxx")): return CxxFindSource(fn, ipath) - if (fn.endswith(".pdef")):return CxxFindSource(fn, ipath) if (fn.endswith(".xml")): return CxxFindSource(fn, ipath) if (fn.endswith(".java")):return CxxFindSource(fn, ipath) if (fn.endswith(".egg")): return OUTPUTDIR+"/models/"+fn diff --git a/panda/src/display/subprocessWindowBuffer.h b/panda/src/display/subprocessWindowBuffer.h index 2cadcee8f5..a6c00db7c3 100644 --- a/panda/src/display/subprocessWindowBuffer.h +++ b/panda/src/display/subprocessWindowBuffer.h @@ -25,8 +25,7 @@ * between processes, as well as appropriate synchronization primitives. * * It's designed to be compiled outside of Panda, so that code that doesn't - * link with Panda (in particular, the Panda3D plugin core API) may still link - * with this and use it. + * link with Panda may still link with this and use it. * * At the moment, and maybe indefinitely, it is only compiled on OSX, and only * when we are building support for the plugin; because it is only needed diff --git a/tests/test_imports.py b/tests/test_imports.py index 1e5778f44b..262685f8b7 100644 --- a/tests/test_imports.py +++ b/tests/test_imports.py @@ -71,6 +71,8 @@ def test_imports_direct(): import direct.directutil.Verify import direct.directutil.WeightedChoice import direct.dist.FreezeTool + import direct.dist.icon + import direct.dist.commands import direct.distributed.AsyncRequest import direct.distributed.CRCache import direct.distributed.CRDataCache @@ -167,21 +169,6 @@ def test_imports_direct(): import direct.interval.SoundInterval import direct.interval.TestInterval import direct.motiontrail.MotionTrail - import direct.p3d.AppRunner - import direct.p3d.DWBPackageInstaller - import direct.p3d.DeploymentTools - import direct.p3d.FileSpec - import direct.p3d.HostInfo - import direct.p3d.InstalledHostData - import direct.p3d.InstalledPackageData - import direct.p3d.JavaScript - import direct.p3d.PackageInfo - import direct.p3d.PackageInstaller - import direct.p3d.PackageMerger - import direct.p3d.Packager - import direct.p3d.PatchMaker - import direct.p3d.ScanDirectoryNode - import direct.p3d.SeqValue import direct.particles.ForceGroup import direct.particles.GlobalForceGroup import direct.particles.ParticleEffect @@ -192,7 +179,6 @@ def test_imports_direct(): import direct.particles.SpriteParticleRendererExt import direct.physics.FallTest import direct.physics.RotationTest - import direct.showbase.AppRunnerGlobal import direct.showbase.Audio3DManager import direct.showbase.BufferViewer import direct.showbase.BulletinBoard