diff --git a/dtool/src/prc/encryptStreamBuf.cxx b/dtool/src/prc/encryptStreamBuf.cxx index fef8746126..683e05a931 100644 --- a/dtool/src/prc/encryptStreamBuf.cxx +++ b/dtool/src/prc/encryptStreamBuf.cxx @@ -23,6 +23,32 @@ #include #include +#if OPENSSL_VERSION_MAJOR >= 3 +#include + +/** + * Tries to load the legacy provider in OpenSSL. Returns true if the provider + * was just loaded, false if it was already loaded or couldn't be loaded. + */ +static bool load_legacy_provider() { + static bool tried = false; + if (!tried) { + tried = true; + if (OSSL_PROVIDER_try_load(nullptr, "legacy", 1) != nullptr) { + if (prc_cat.is_debug()) { + prc_cat.debug() + << "Loaded legacy OpenSSL provider.\n"; + } + return true; + } else { + prc_cat.warning() + << "Failed to load legacy OpenSSL provider.\n"; + } + } + return false; +} +#endif // OPENSSL_VERSION_MAJOR + // The iteration count is scaled by this factor for writing to the stream. static const int iteration_count_factor = 1000; @@ -122,7 +148,31 @@ open_read(std::istream *source, bool owns_source, const std::string &password) { int key_length = sr.get_uint16(); int count = sr.get_uint16(); +#if OPENSSL_VERSION_MAJOR >= 3 + // First, convert the cipher's nid to its full name. + const char *cipher_name = OBJ_nid2ln(nid); + + const EVP_CIPHER *cipher = nullptr; + if (cipher_name != nullptr) { + // Now, fetch the cipher known by this name. + cipher = EVP_CIPHER_fetch(nullptr, cipher_name, nullptr); + + if (cipher == nullptr && EVP_get_cipherbynid(nid) != nullptr) { + if (load_legacy_provider()) { + cipher = EVP_CIPHER_fetch(nullptr, cipher_name, nullptr); + } + + if (cipher == nullptr) { + prc_cat.error() + << "No implementation available for encryption algorithm in stream: " + << cipher_name << "\n"; + return; + } + } + } +#else const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid); +#endif if (cipher == nullptr) { prc_cat.error() @@ -220,8 +270,29 @@ open_write(std::ostream *dest, bool owns_dest, const std::string &password) { _dest = dest; _owns_dest = owns_dest; +#if OPENSSL_VERSION_MAJOR >= 3 + // This checks that there is actually an implementation available. + const EVP_CIPHER *cipher = + EVP_CIPHER_fetch(nullptr, _algorithm.c_str(), nullptr); + + if (cipher == nullptr && + EVP_get_cipherbyname(_algorithm.c_str()) != nullptr) { + // The cipher does exist, though, do we need to load the legacy provider? + if (load_legacy_provider()) { + cipher = EVP_CIPHER_fetch(nullptr, _algorithm.c_str(), nullptr); + } + + if (cipher == nullptr) { + prc_cat.error() + << "No implementation available for encryption algorithm: " + << _algorithm << "\n"; + return; + } + } +#else const EVP_CIPHER *cipher = EVP_get_cipherbyname(_algorithm.c_str()); +#endif if (cipher == nullptr) { prc_cat.error() diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index e9d5a5106c..4256e64876 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -3208,13 +3208,14 @@ get_texture(TextureStage *stage) const { * Recursively searches the scene graph for references to the given texture, * and replaces them with the new texture. * + * As of Panda3D 1.10.13, new_tex may be null to remove the texture. + * * @since 1.10.4 */ void NodePath:: replace_texture(Texture *tex, Texture *new_tex) { nassertv_always(!is_empty()); nassertv(tex != nullptr); - nassertv(new_tex != nullptr); r_replace_texture(node(), tex, new_tex); } @@ -4250,15 +4251,19 @@ get_material() const { * Recursively searches the scene graph for references to the given material, * and replaces them with the new material. * + * As of Panda3D 1.10.13, new_mat may be null to remove the material. + * * @since 1.10.0 */ void NodePath:: replace_material(Material *mat, Material *new_mat) { nassertv_always(!is_empty()); nassertv(mat != nullptr); - nassertv(new_mat != nullptr); - CPT(RenderAttrib) new_attrib = MaterialAttrib::make(new_mat); + CPT(RenderAttrib) new_attrib; + if (new_mat != nullptr) { + new_attrib = MaterialAttrib::make(new_mat); + } r_replace_material(node(), mat, (const MaterialAttrib *)new_attrib.p()); } @@ -6878,7 +6883,11 @@ r_replace_material(PandaNode *node, Material *mat, const MaterialAttrib *ma; if (node_state->get_attrib(ma)) { if (mat == ma->get_material()) { - node->set_state(node_state->set_attrib(new_attrib)); + if (new_attrib != nullptr) { + node->set_state(node_state->set_attrib(new_attrib)); + } else { + node->set_state(node_state->remove_attrib(MaterialAttrib::get_class_slot())); + } } } } @@ -6897,7 +6906,11 @@ r_replace_material(PandaNode *node, Material *mat, if (geom_state->get_attrib(ma)) { if (mat == ma->get_material()) { // Replace it - gnode->set_geom_state(i, geom_state->set_attrib(new_attrib)); + if (new_attrib != nullptr) { + gnode->set_geom_state(i, geom_state->set_attrib(new_attrib)); + } else { + gnode->set_geom_state(i, geom_state->remove_attrib(MaterialAttrib::get_class_slot())); + } } } } diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 66bf5eb9ae..d27a76c7ad 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -619,6 +619,9 @@ PUBLISHED: Texture *get_texture() const; Texture *get_texture(TextureStage *stage) const; void replace_texture(Texture *tex, Texture *new_tex); +#ifdef CPPPARSER // Let interrogate know this also accepts None + void replace_texture(Texture *tex, std::nullptr_t new_tex); +#endif const SamplerState &get_texture_sampler() const; const SamplerState &get_texture_sampler(TextureStage *stage) const; @@ -771,6 +774,9 @@ PUBLISHED: bool has_material() const; PT(Material) get_material() const; void replace_material(Material *mat, Material *new_mat); +#ifdef CPPPARSER // Let interrogate know this also accepts None + void replace_material(Material *mat, std::nullptr_t new_mat); +#endif void set_fog(Fog *fog, int priority = 0); void set_fog_off(int priority = 0); diff --git a/panda/src/pgraph/renderEffects.I b/panda/src/pgraph/renderEffects.I index a0ae6af279..74f161f05c 100644 --- a/panda/src/pgraph/renderEffects.I +++ b/panda/src/pgraph/renderEffects.I @@ -26,7 +26,7 @@ Effect(const RenderEffect *effect) : * file. At this point, the effect pointer is unknown. */ INLINE RenderEffects::Effect:: -Effect() { +Effect() : _type(TypeHandle::none()) { } /** diff --git a/panda/src/pgraph/textureAttrib.cxx b/panda/src/pgraph/textureAttrib.cxx index d08344fc4d..7303ee9245 100644 --- a/panda/src/pgraph/textureAttrib.cxx +++ b/panda/src/pgraph/textureAttrib.cxx @@ -253,12 +253,15 @@ unify_texture_stages(TextureStage *stage) const { * Returns a new TextureAttrib, just like this one, but with all references to * the given texture replaced with the new texture. * + * As of Panda3D 1.10.13, new_tex may be null to remove the texture. + * * @since 1.10.4 */ CPT(RenderAttrib) TextureAttrib:: replace_texture(Texture *tex, Texture *new_tex) const { TextureAttrib *attrib = nullptr; + size_t j = 0; for (size_t i = 0; i < _on_stages.size(); ++i) { const StageNode &sn = _on_stages[i]; if (sn._texture == tex) { @@ -266,8 +269,14 @@ replace_texture(Texture *tex, Texture *new_tex) const { attrib = new TextureAttrib(*this); } - attrib->_on_stages[i]._texture = new_tex; + if (new_tex != nullptr) { + attrib->_on_stages[j]._texture = new_tex; + } else { + attrib->_on_stages.erase(attrib->_on_stages.begin() + j); + continue; + } } + ++j; } if (attrib != nullptr) { diff --git a/panda/src/pgraph/textureAttrib.h b/panda/src/pgraph/textureAttrib.h index 0858cc68a7..ba0eae0d19 100644 --- a/panda/src/pgraph/textureAttrib.h +++ b/panda/src/pgraph/textureAttrib.h @@ -90,6 +90,9 @@ PUBLISHED: CPT(RenderAttrib) remove_off_stage(TextureStage *stage) const; CPT(RenderAttrib) unify_texture_stages(TextureStage *stage) const; CPT(RenderAttrib) replace_texture(Texture *tex, Texture *new_tex) const; +#ifdef CPPPARSER // Let interrogate know this also accepts None + CPT(RenderAttrib) replace_texture(Texture *tex, std::nullptr_t new_tex) const; +#endif public: CPT(TextureAttrib) filter_to_max(int max_texture_stages) const; diff --git a/tests/express/test_encrypt.py b/tests/express/test_encrypt.py index 5624bcae99..bb49d46599 100644 --- a/tests/express/test_encrypt.py +++ b/tests/express/test_encrypt.py @@ -3,12 +3,17 @@ from panda3d import core def test_encrypt_string(): # Test encrypt and then decrypt cycle - enc = core.encrypt_string('abcdefg', '12345') - assert len(enc) > 0 + for algorithm in ('', 'bf-cbc', 'aes-256-cbc'): + enc = core.encrypt_string('abcdefg', '12345', algorithm) + assert len(enc) > 0 - dec = core.decrypt_string(enc, '12345') - assert dec == 'abcdefg' + dec = core.decrypt_string(enc, '12345') + assert dec == 'abcdefg' - # Test pre-encrypted string + # Test pre-encrypted bf-cbc string enc = b'[\x00\x10\x00d\x00\xb5\x7f\xc44Y\xb7\xd9\x15\xe3\xbd\xcf\xb3yK\xfb\xf6' assert 'test' == core.decrypt_string(enc, '98765') + + # Test pre-encrypted aes-256-cbc string + enc = b'\xab\x01 \x00d\x00\xf1WP\xb0\x96h\xf8\xc5\xf4\x8d\x0b>q0\xf15\x185\xf8+\x1b\xe4\xae8\x88\xf2\x91\x15\xb8\x8fh\x88' + assert 'test' == core.decrypt_string(enc, '98765') diff --git a/tests/pgraph/test_nodepath.py b/tests/pgraph/test_nodepath.py index abdcad14e6..9339394724 100644 --- a/tests/pgraph/test_nodepath.py +++ b/tests/pgraph/test_nodepath.py @@ -291,3 +291,24 @@ def test_nodepath_replace_texture(): path1.replace_texture(tex1, tex2) assert not path1.has_texture() assert path2.get_texture() == tex2 + + +def test_nodepath_replace_texture_none(): + from panda3d.core import NodePath, Texture + + tex1 = Texture("tex1") + + path1 = NodePath("node1") + assert path1.get_texture() is None + path1.set_texture(tex1) + assert path1.get_texture() == tex1 + path1.replace_texture(tex1, None) + assert path1.get_texture() is None + + path1 = NodePath("node1") + path2 = path1.attach_new_node("node2") + assert path2.get_texture() is None + path2.set_texture(tex1) + assert path2.get_texture() == tex1 + path1.replace_texture(tex1, None) + assert path2.get_texture() is None