From 3688c5899e0390e6cad35738d5dde440844d8046 Mon Sep 17 00:00:00 2001 From: even1024 Date: Mon, 20 Jun 2022 14:49:53 +0300 Subject: [PATCH] core: base64 support for binary formats, uninitialized data and #764 fix (#766) --- .../integration/ref/formats/smarts.py.out | 2 + api/tests/integration/tests/formats/smarts.py | 35 +++++++++++ api/wasm/indigo-ketcher/CMakeLists.txt | 2 + api/wasm/indigo-ketcher/indigo-ketcher.cpp | 37 ++++++------ api/wasm/indigo-ketcher/test.js | 11 ++++ api/wasm/indigo-ketcher/test64.cdx | 1 + api/wasm/indigo-ketcher/test64.ket | 1 + core/indigo-core/common/base_cpp/scanner.cpp | 24 +++++--- core/indigo-core/common/base_cpp/scanner.h | 11 ++-- core/indigo-core/molecule/metadata_storage.h | 4 +- core/indigo-core/molecule/smiles_saver.h | 2 +- .../molecule/src/base_molecule.cpp | 2 +- .../molecule/src/metadata_storage.cpp | 4 +- .../molecule/src/molecule_auto_loader.cpp | 60 ++++++++++++------- .../indigo-core/molecule/src/smiles_saver.cpp | 12 ++-- core/render2d/src/render_common.cpp | 20 +++++++ core/render2d/src/render_single.cpp | 2 +- utils/indigo-depict/main.c | 26 +++++++- 18 files changed, 192 insertions(+), 64 deletions(-) create mode 100644 api/wasm/indigo-ketcher/test64.cdx create mode 100644 api/wasm/indigo-ketcher/test64.ket diff --git a/api/tests/integration/ref/formats/smarts.py.out b/api/tests/integration/ref/formats/smarts.py.out index 5eba9f3473..605a3dc506 100644 --- a/api/tests/integration/ref/formats/smarts.py.out +++ b/api/tests/integration/ref/formats/smarts.py.out @@ -4,3 +4,5 @@ CC[C+5]CCCCC **** Load and Save as Molecule **** [#6]-[#6]-[#6;+5]-[#6]-[#6]-[#6]-[#6]-[#6] CC[C+5]CCCCC +**** Load and Save as Query with not list **** +[#6]-[#6]-[!#5!#6!#7]-[#6]-[#6]-[#6]-[#6]-[#6]-[#6] diff --git a/api/tests/integration/tests/formats/smarts.py b/api/tests/integration/tests/formats/smarts.py index effd747723..d16c49c348 100644 --- a/api/tests/integration/tests/formats/smarts.py +++ b/api/tests/integration/tests/formats/smarts.py @@ -39,6 +39,37 @@ def testSmarts(m): M END """ +notlist = """ + -INDIGO-06202202172D + + 0 0 0 0 0 0 0 0 0 0 0 V3000 +M V30 BEGIN CTAB +M V30 COUNTS 9 8 0 0 0 +M V30 BEGIN ATOM +M V30 1 C 4.9359 -3.675 0.0 0 +M V30 2 C 5.80192 -3.175 0.0 0 +M V30 3 NOT[B,C,N] 6.66795 -3.675 0.0 0 +M V30 4 C 7.53397 -3.175 0.0 0 +M V30 5 C 8.4 -3.675 0.0 0 +M V30 6 C 9.26603 -3.175 0.0 0 +M V30 7 C 10.1321 -3.675 0.0 0 +M V30 8 C 10.9981 -3.175 0.0 0 +M V30 9 C 11.8641 -3.675 0.0 0 +M V30 END ATOM +M V30 BEGIN BOND +M V30 1 1 1 2 +M V30 2 1 2 3 +M V30 3 1 3 4 +M V30 4 1 4 5 +M V30 5 1 5 6 +M V30 6 1 6 7 +M V30 7 1 7 8 +M V30 8 1 8 9 +M V30 END BOND +M V30 END CTAB +M END +""" + print("**** Load and Save as Query ****") m = indigo.loadQueryMolecule(molstr) testSmarts(m) @@ -46,3 +77,7 @@ def testSmarts(m): print("**** Load and Save as Molecule ****") m = indigo.loadMolecule(molstr) testSmarts(m) + +print("**** Load and Save as Query with not list ****") +m = indigo.loadQueryMolecule(notlist) +print(m.smarts()) diff --git a/api/wasm/indigo-ketcher/CMakeLists.txt b/api/wasm/indigo-ketcher/CMakeLists.txt index afa7ea2433..3c4deaf94d 100644 --- a/api/wasm/indigo-ketcher/CMakeLists.txt +++ b/api/wasm/indigo-ketcher/CMakeLists.txt @@ -34,6 +34,8 @@ add_custom_target(${PROJECT_NAME} add_custom_target(${PROJECT_NAME}-test COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/test.js ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/test64.cdx ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/test64.ket ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/ COMMAND node test WORKING_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} DEPENDS ${PROJECT_NAME} diff --git a/api/wasm/indigo-ketcher/indigo-ketcher.cpp b/api/wasm/indigo-ketcher/indigo-ketcher.cpp index 9b3bf31cc8..4b71c91da7 100644 --- a/api/wasm/indigo-ketcher/indigo-ketcher.cpp +++ b/api/wasm/indigo-ketcher/indigo-ketcher.cpp @@ -238,49 +238,50 @@ namespace indigo IndigoRendererSession& operator=(IndigoRendererSession&&) = delete; }; - IndigoKetcherObject loadMoleculeOrReaction(cstring data) + IndigoKetcherObject loadMoleculeOrReaction(const std::string& data) { print_js("loadMoleculeOrReaction:"); - print_js(data); std::vector exceptionMessages; exceptionMessages.reserve(4); int objectId = -1; - if (std::string(data).find("InChI") == 0) + if (data.find("InChI") == 0) { - objectId = indigoInchiLoadMolecule(data); + objectId = indigoInchiLoadMolecule(data.c_str()); if (objectId >= 0) return IndigoKetcherObject(objectId, IndigoKetcherObject::EKETMolecule); } - objectId = indigoLoadReactionFromString(data); + // Let's try a simple molecule + print_js("try as molecule"); + objectId = indigoLoadMoleculeFromBuffer(data.c_str(), data.size()); if (objectId >= 0) { - print_js("try as reaction"); - return IndigoKetcherObject(objectId, IndigoKetcherObject::EKETReaction); + return IndigoKetcherObject(objectId, IndigoKetcherObject::EKETMolecule); } exceptionMessages.emplace_back(indigoGetLastError()); - // Let's try query reaction - objectId = indigoLoadQueryReactionFromString(data); + + // Let's try reaction + print_js("try as reaction"); + objectId = indigoLoadReactionFromBuffer(data.c_str(), data.size()); if (objectId >= 0) { - print_js("try as query reaction"); - return IndigoKetcherObject(objectId, IndigoKetcherObject::EKETReactionQuery); + return IndigoKetcherObject(objectId, IndigoKetcherObject::EKETReaction); } exceptionMessages.emplace_back(indigoGetLastError()); - // Let's try a simple molecule - objectId = indigoLoadMoleculeFromString(data); + // Let's try query reaction + print_js("try as query reaction"); + objectId = indigoLoadQueryReactionFromBuffer(data.c_str(), data.size()); if (objectId >= 0) { - print_js("try as molecule"); - return IndigoKetcherObject(objectId, IndigoKetcherObject::EKETMolecule); + return IndigoKetcherObject(objectId, IndigoKetcherObject::EKETReactionQuery); } exceptionMessages.emplace_back(indigoGetLastError()); // Let's try query molecule - objectId = indigoLoadQueryMoleculeFromString(data); + print_js("try as query molecule"); + objectId = indigoLoadQueryMoleculeFromBuffer(data.c_str(), data.size()); if (objectId >= 0) { - print_js("try as query molecule"); return IndigoKetcherObject(objectId, IndigoKetcherObject::EKETMoleculeQuery); } exceptionMessages.emplace_back(indigoGetLastError()); @@ -306,7 +307,7 @@ namespace indigo { const IndigoSession session; indigoSetOptions(options); - IndigoKetcherObject iko = loadMoleculeOrReaction(data.c_str()); + IndigoKetcherObject iko = loadMoleculeOrReaction(data); return iko.toString(options, outputFormat.size() ? outputFormat : "ket"); } diff --git a/api/wasm/indigo-ketcher/test.js b/api/wasm/indigo-ketcher/test.js index c1947aa744..23f669f701 100644 --- a/api/wasm/indigo-ketcher/test.js +++ b/api/wasm/indigo-ketcher/test.js @@ -414,6 +414,17 @@ M END assert.equal(inchi_aux, "InChI=1S/C6H6/c1-2-4-6-5-3-1/h1-6H\nAuxInfo=1/0/N:1,2,6,3,5,4/E:(1,2,3,4,5,6)/rA:6CCCCCC/rB:d1;s2;d3;s4;s1d5;/rC:;;;;;;"); options.delete(); }); + + test("convert", "cdx_to_ket", () => { + let options = new indigo.MapStringString(); + var fs = require('fs'); + const cdx_data = fs.readFileSync("test64.cdx"); + const ket = indigo.convert(cdx_data, "ket", options); + const ket_data = indigo.convert(fs.readFileSync("test64.ket"),"ket", options); + assert.equal(ket, ket_data); + options.delete(); + }); + } // Dearomatize diff --git a/api/wasm/indigo-ketcher/test64.cdx b/api/wasm/indigo-ketcher/test64.cdx new file mode 100644 index 0000000000..a3754258b3 --- /dev/null +++ b/api/wasm/indigo-ketcher/test64.cdx @@ -0,0 +1 @@ +base64::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 \ No newline at end of file diff --git a/api/wasm/indigo-ketcher/test64.ket b/api/wasm/indigo-ketcher/test64.ket new file mode 100644 index 0000000000..96aaf1c45b --- /dev/null +++ b/api/wasm/indigo-ketcher/test64.ket @@ -0,0 +1 @@ +{"root":{"nodes":[{"$ref":"mol0"}]},"mol0":{"type":"molecule","atoms":[{"label":"C","location":[8.822282791137696,16.86986541748047,0.0]},{"label":"C","location":[9.738801002502442,16.3406982421875,0.0]},{"label":"C","location":[9.738801002502442,15.28236198425293,0.0]},{"label":"O","location":[7.905764579772949,16.3406982421875,0.0]},{"label":"N","location":[8.822282791137696,14.753194808959961,0.0]},{"label":"C","location":[9.738801002502442,18.457368850708009,0.0],"stereoLabel":"abs"},{"label":"C","location":[10.655319213867188,17.928199768066408,0.0]},{"label":"N","location":[8.822282791137696,17.928199768066408,0.0]},{"label":"O","location":[11.571837425231934,18.457368850708009,0.0]},{"label":"C","location":[7.528291702270508,18.608003616333009,0.0]},{"label":"C","location":[6.493239879608154,18.387868881225587,0.0]},{"label":"C","location":[5.784860610961914,19.174213409423829,0.0]},{"label":"C","location":[6.111886501312256,20.18069076538086,0.0]},{"label":"C","location":[7.855317115783691,19.61448097229004,0.0]},{"label":"C","location":[7.1472907066345219,20.40082359313965,0.0]},{"label":"N","location":[7.676458358764648,21.31734275817871,0.0]},{"label":"C","location":[8.71151065826416,21.09756088256836,0.0]},{"label":"C","location":[8.822282791137696,20.044870376586915,0.0]},{"label":"C","location":[9.738801002502442,19.515703201293947,0.0]},{"label":"C","location":[11.571837425231934,16.3406982421875,0.0],"stereoLabel":"abs"},{"label":"C","location":[11.571837425231934,15.28236198425293,0.0]},{"label":"N","location":[10.655319213867188,16.86986541748047,0.0]},{"label":"O","location":[12.488356590270996,14.753194808959961,0.0]},{"label":"C","location":[14.698864936828614,17.777563095092775,0.0]},{"label":"C","location":[15.733918190002442,17.997695922851564,0.0]},{"label":"C","location":[16.442296981811525,17.211355209350587,0.0]},{"label":"C","location":[16.115272521972658,16.204875946044923,0.0]},{"label":"C","location":[14.371841430664063,16.771085739135743,0.0]},{"label":"C","location":[15.079866409301758,15.984743118286133,0.0]},{"label":"N","location":[14.550699234008789,15.068225860595704,0.0]},{"label":"C","location":[13.515646934509278,15.288005828857422,0.0]},{"label":"C","location":[13.404873847961426,16.3406982421875,0.0]},{"label":"C","location":[12.488356590270996,16.86986541748047,0.0]},{"label":"C","location":[8.822282791137696,13.694859504699707,0.0]},{"label":"N","location":[9.738801002502442,12.107356071472168,0.0]},{"label":"C","location":[9.738801002502442,13.165691375732422,0.0],"stereoLabel":"abs"},{"label":"C","location":[10.655319213867188,13.694859504699707,0.0],"stereoLabel":"abs"},{"label":"C","location":[11.571837425231934,13.165691375732422,0.0]},{"label":"O","location":[10.655319213867188,14.753194808959961,0.0]},{"label":"O","location":[7.905764579772949,13.165691375732422,0.0]},{"label":"C","location":[8.822282791137696,11.5781888961792,0.0]},{"label":"O","location":[8.822282791137696,10.519853591918946,0.0]},{"label":"C","location":[7.905764579772949,12.107356071472168,0.0]},{"label":"C","location":[6.989246368408203,11.5781888961792,0.0]},{"label":"C","location":[6.989246368408203,10.519853591918946,0.0]},{"label":"C","location":[6.072728157043457,9.99068546295166,0.0]},{"label":"C","location":[5.155856609344482,10.519853591918946,0.0]},{"label":"C","location":[5.155856609344482,11.5781888961792,0.0]},{"label":"C","location":[6.072728157043457,12.107356071472168,0.0]}],"bonds":[{"type":1,"atoms":[0,7]},{"type":1,"atoms":[6,21]},{"type":1,"atoms":[20,38]},{"type":1,"atoms":[33,4]},{"type":1,"atoms":[0,1]},{"type":1,"atoms":[1,2]},{"type":2,"atoms":[0,3]},{"type":1,"atoms":[2,4]},{"type":1,"atoms":[13,9]},{"type":2,"atoms":[10,9]},{"type":1,"atoms":[11,10]},{"type":2,"atoms":[12,11]},{"type":1,"atoms":[14,12]},{"type":1,"atoms":[17,13]},{"type":2,"atoms":[14,13]},{"type":1,"atoms":[15,14]},{"type":1,"atoms":[16,15]},{"type":2,"atoms":[17,16]},{"type":1,"atoms":[5,18],"stereo":1},{"type":1,"atoms":[5,6]},{"type":1,"atoms":[5,7]},{"type":2,"atoms":[6,8]},{"type":1,"atoms":[18,17]},{"type":1,"atoms":[27,23]},{"type":2,"atoms":[24,23]},{"type":1,"atoms":[25,24]},{"type":2,"atoms":[26,25]},{"type":1,"atoms":[28,26]},{"type":1,"atoms":[31,27]},{"type":2,"atoms":[28,27]},{"type":1,"atoms":[29,28]},{"type":1,"atoms":[30,29]},{"type":2,"atoms":[31,30]},{"type":1,"atoms":[19,32],"stereo":6},{"type":1,"atoms":[19,20]},{"type":1,"atoms":[19,21]},{"type":2,"atoms":[20,22]},{"type":1,"atoms":[32,31]},{"type":1,"atoms":[35,34],"stereo":1},{"type":1,"atoms":[33,35]},{"type":1,"atoms":[35,36]},{"type":1,"atoms":[36,37],"stereo":1},{"type":1,"atoms":[36,38]},{"type":2,"atoms":[33,39]},{"type":2,"atoms":[40,41]},{"type":1,"atoms":[40,42]},{"type":1,"atoms":[43,44]},{"type":2,"atoms":[44,45]},{"type":1,"atoms":[45,46]},{"type":2,"atoms":[46,47]},{"type":1,"atoms":[47,48]},{"type":2,"atoms":[43,48]},{"type":1,"atoms":[42,43]},{"type":1,"atoms":[34,40]}]}} \ No newline at end of file diff --git a/core/indigo-core/common/base_cpp/scanner.cpp b/core/indigo-core/common/base_cpp/scanner.cpp index 30f0470e11..51be7f5f6a 100644 --- a/core/indigo-core/common/base_cpp/scanner.cpp +++ b/core/indigo-core/common/base_cpp/scanner.cpp @@ -28,6 +28,7 @@ #include "base_cpp/tlscont.h" #include "reusable_obj_array.h" +#include <../cppcodec/cppcodec/base64_default_rfc4648.hpp> #include using namespace indigo; @@ -692,30 +693,39 @@ void BufferScanner::_init(const char* buffer, int size) { if (size < -1 || (size > 0 && buffer == 0)) throw Error("incorrect parameters in BufferScanner constructor"); - - _buffer = buffer; - _size = size; + if (_is_base64) + { + auto decoded = base64::decode(buffer, size); + _base64_buffer.copy((char*)decoded.data(), decoded.size()); + _buffer = _base64_buffer.ptr(); + _size = _base64_buffer.size(); + } + else + { + _buffer = buffer; + _size = size; + } _offset = 0; } -BufferScanner::BufferScanner(const char* buffer, int buffer_size) +BufferScanner::BufferScanner(const char* buffer, int buffer_size, bool is_base64) : _is_base64(is_base64) { _init(buffer, buffer_size); } -BufferScanner::BufferScanner(const byte* buffer, int buffer_size) +BufferScanner::BufferScanner(const byte* buffer, int buffer_size, bool is_base64) : _is_base64(is_base64) { _init((const char*)buffer, buffer_size); } -BufferScanner::BufferScanner(const char* str) +BufferScanner::BufferScanner(const char* str, bool is_base64) : _is_base64(is_base64) { if (str == 0) throw Error("null input"); _init(str, (int)strlen(str)); } -BufferScanner::BufferScanner(const Array& arr) +BufferScanner::BufferScanner(const Array& arr, bool is_base64) : _is_base64(is_base64) { _init(arr.ptr(), arr.size()); } diff --git a/core/indigo-core/common/base_cpp/scanner.h b/core/indigo-core/common/base_cpp/scanner.h index 2f053b2950..71d5c6b5be 100644 --- a/core/indigo-core/common/base_cpp/scanner.h +++ b/core/indigo-core/common/base_cpp/scanner.h @@ -124,10 +124,10 @@ namespace indigo class DLLEXPORT BufferScanner : public Scanner { public: - explicit BufferScanner(const char* buffer, int buffer_size); - explicit BufferScanner(const byte* buffer, int buffer_size); - explicit BufferScanner(const char* str); - explicit BufferScanner(const Array& arr); + explicit BufferScanner(const char* buffer, int buffer_size, bool is_base64 = false); + explicit BufferScanner(const byte* buffer, int buffer_size, bool is_base64 = false); + explicit BufferScanner(const char* str, bool is_base64 = false); + explicit BufferScanner(const Array& arr, bool is_base64 = false); ~BufferScanner() override; bool isEOF() override; @@ -145,7 +145,8 @@ namespace indigo const char* _buffer; int _size; int _offset; - + bool _is_base64; + Array _base64_buffer; void _init(const char* buffer, int length); // no implicit copy diff --git a/core/indigo-core/molecule/metadata_storage.h b/core/indigo-core/molecule/metadata_storage.h index 24a31f2998..a4efef968c 100644 --- a/core/indigo-core/molecule/metadata_storage.h +++ b/core/indigo-core/molecule/metadata_storage.h @@ -60,8 +60,8 @@ namespace indigo return _meta_data; } - int getMetaCount(std::uint32_t meta_type) const; - const MetaObject& getMetaObject(std::uint32_t meta_type, int index) const; + int getMetaCount(uint32_t meta_type) const; + const MetaObject& getMetaObject(uint32_t meta_type, int index) const; protected: PtrArray _meta_data; // TODO: should be replaced with list of unique_ptr diff --git a/core/indigo-core/molecule/smiles_saver.h b/core/indigo-core/molecule/smiles_saver.h index bb71cc0683..adba2530d3 100644 --- a/core/indigo-core/molecule/smiles_saver.h +++ b/core/indigo-core/molecule/smiles_saver.h @@ -102,7 +102,7 @@ namespace indigo void _writeAtom(int idx, bool aromatic, bool lowercase, int chirality) const; void _writeChirality(int chirality) const; void _writeCharge(int charge) const; - void _writeSmartsAtom(int idx, QueryMolecule::Atom* atom, int chirality, int depth, bool has_or_parent) const; + void _writeSmartsAtom(int idx, QueryMolecule::Atom* atom, int chirality, int depth, bool has_or_parent, bool has_not_parent) const; void _writeSmartsBond(int idx, QueryMolecule::Bond* bond, bool has_or_parent) const; void _markCisTrans(); void _banSlashes(); diff --git a/core/indigo-core/molecule/src/base_molecule.cpp b/core/indigo-core/molecule/src/base_molecule.cpp index 6b7ba467d5..705976f0ac 100644 --- a/core/indigo-core/molecule/src/base_molecule.cpp +++ b/core/indigo-core/molecule/src/base_molecule.cpp @@ -244,7 +244,7 @@ void BaseMolecule::_mergeWithSubmolecule_Sub(BaseMolecule& mol, const Array int i; // XYZ - _xyz.resize(vertexEnd()); + _xyz.expandFill(vertexEnd(), Vec3f(0, 0, 0)); if (!(skip_flags & SKIP_XYZ)) { if (vertexCount() == 0) diff --git a/core/indigo-core/molecule/src/metadata_storage.cpp b/core/indigo-core/molecule/src/metadata_storage.cpp index 004c33380f..9f7d430935 100644 --- a/core/indigo-core/molecule/src/metadata_storage.cpp +++ b/core/indigo-core/molecule/src/metadata_storage.cpp @@ -39,7 +39,7 @@ void MetaDataStorage::clone(const MetaDataStorage& other) addMetaObject(meta[i]->clone()); } -const MetaObject& MetaDataStorage::getMetaObject(std::uint32_t meta_type, int index) const +const MetaObject& MetaDataStorage::getMetaObject(uint32_t meta_type, int index) const { switch (meta_type) { @@ -61,7 +61,7 @@ const MetaObject& MetaDataStorage::getMetaObject(std::uint32_t meta_type, int in } } -int MetaDataStorage::getMetaCount(std::uint32_t meta_type) const +int MetaDataStorage::getMetaCount(uint32_t meta_type) const { switch (meta_type) { diff --git a/core/indigo-core/molecule/src/molecule_auto_loader.cpp b/core/indigo-core/molecule/src/molecule_auto_loader.cpp index 201932d036..95fde3fe69 100644 --- a/core/indigo-core/molecule/src/molecule_auto_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_auto_loader.cpp @@ -188,18 +188,37 @@ void MoleculeAutoLoader::_loadMolecule(BaseMolecule& mol, bool query) { properties.clear(); + auto local_scanner = _scanner; // local scanner only for binary format + // chack for base64 + uint8_t base64_id[] = "base64::"; + std::unique_ptr base64_scanner; + if (local_scanner->length() >= (sizeof(base64_id) - 1)) + { + byte id[sizeof(base64_id) - 1]; + long long pos = local_scanner->tell(); + local_scanner->readCharsFix(sizeof(base64_id) - 1, (char*)id); + if (std::equal(std::begin(id), std::end(id), std::begin(base64_id))) + { + Array base64_data; + local_scanner->readAll(base64_data); + base64_scanner = std::make_unique(base64_data, true); + local_scanner = base64_scanner.get(); + } + local_scanner->seek(pos, SEEK_SET); + } + // check for GZip format - if (_scanner->length() >= 2LL) + if (local_scanner->length() >= 2LL) { byte id[2]; - long long pos = _scanner->tell(); + long long pos = local_scanner->tell(); - _scanner->readCharsFix(2, (char*)id); - _scanner->seek(pos, SEEK_SET); + local_scanner->readCharsFix(2, (char*)id); + local_scanner->seek(pos, SEEK_SET); if (id[0] == 0x1f && id[1] == 0x8b) { - GZipScanner gzscanner(*_scanner); + GZipScanner gzscanner(*local_scanner); QS_DEF(Array, buf); gzscanner.readAll(buf); @@ -221,6 +240,22 @@ void MoleculeAutoLoader::_loadMolecule(BaseMolecule& mol, bool query) } } + // check for CDX format + { + if (local_scanner->findWord("VjCD0100")) + { + MoleculeCdxLoader loader(*local_scanner); + loader.stereochemistry_options = stereochemistry_options; + if (query) + throw Error("CDX queries not supported yet"); + loader.loadMolecule(mol.asMolecule()); + + properties.copy(loader.properties); + + return; + } + } + // check for MDLCT format { QS_DEF(Array, buf); @@ -431,21 +466,6 @@ void MoleculeAutoLoader::_loadMolecule(BaseMolecule& mol, bool query) } } - // check for CDX format - { - if (_scanner->findWord("VjCD0100")) - { - MoleculeCdxLoader loader(*_scanner); - loader.stereochemistry_options = stereochemistry_options; - if (query) - throw Error("CDX queries not supported yet"); - loader.loadMolecule(mol.asMolecule()); - - properties.copy(loader.properties); - - return; - } - } // default is Molfile format { diff --git a/core/indigo-core/molecule/src/smiles_saver.cpp b/core/indigo-core/molecule/src/smiles_saver.cpp index b2cdee1949..c0bf11c06d 100644 --- a/core/indigo-core/molecule/src/smiles_saver.cpp +++ b/core/indigo-core/molecule/src/smiles_saver.cpp @@ -534,7 +534,7 @@ void SmilesSaver::_saveMolecule() if (!smarts_mode) _writeAtom(v_idx, _atoms[v_idx].aromatic, _atoms[v_idx].lowercase, _atoms[v_idx].chirality); else if (_qmol != 0) - _writeSmartsAtom(v_idx, &_qmol->getAtom(v_idx), _atoms[v_idx].chirality, 0, false); + _writeSmartsAtom(v_idx, &_qmol->getAtom(v_idx), _atoms[v_idx].chirality, 0, false, false); else throw Error("SMARTS format availble for query only!"); @@ -860,7 +860,7 @@ void SmilesSaver::_writeCharge(int charge) const _output.printf("-"); } -void SmilesSaver::_writeSmartsAtom(int idx, QueryMolecule::Atom* atom, int chirality, int depth, bool has_or_parent) const +void SmilesSaver::_writeSmartsAtom(int idx, QueryMolecule::Atom* atom, int chirality, int depth, bool has_or_parent, bool has_not_parent) const { int i; @@ -871,7 +871,7 @@ void SmilesSaver::_writeSmartsAtom(int idx, QueryMolecule::Atom* atom, int chira { case QueryMolecule::OP_NOT: { _output.writeChar('!'); - _writeSmartsAtom(idx, (QueryMolecule::Atom*)atom->children[0], chirality, depth + 1, has_or_parent); + _writeSmartsAtom(idx, (QueryMolecule::Atom*)atom->children[0], chirality, depth + 1, has_or_parent, true); break; } case QueryMolecule::OP_AND: { @@ -879,7 +879,7 @@ void SmilesSaver::_writeSmartsAtom(int idx, QueryMolecule::Atom* atom, int chira { if (i > 0) _output.writeChar(has_or_parent ? '&' : ';'); - _writeSmartsAtom(idx, (QueryMolecule::Atom*)atom->children[i], chirality, depth + 1, has_or_parent); + _writeSmartsAtom(idx, (QueryMolecule::Atom*)atom->children[i], chirality, depth + 1, has_or_parent, has_not_parent); } break; } @@ -887,8 +887,8 @@ void SmilesSaver::_writeSmartsAtom(int idx, QueryMolecule::Atom* atom, int chira for (i = 0; i < atom->children.size(); i++) { if (i > 0) - _output.printf(","); - _writeSmartsAtom(idx, (QueryMolecule::Atom*)atom->children[i], chirality, depth + 1, true); + _output.printf(has_not_parent ? "!" : ","); + _writeSmartsAtom(idx, (QueryMolecule::Atom*)atom->children[i], chirality, depth + 1, true, has_not_parent); } break; } diff --git a/core/render2d/src/render_common.cpp b/core/render2d/src/render_common.cpp index 027442e971..0c8ba942a4 100644 --- a/core/render2d/src/render_common.cpp +++ b/core/render2d/src/render_common.cpp @@ -151,6 +151,14 @@ void AtomDesc::clear() pseudo.clear(); memset(implHPosWeights, 0, sizeof(implHPosWeights)); upperSin = lowerSin = rightSin = leftSin = 0; + pos.set(0, 0); + boundBoxMin.set(0, 0); + boundBoxMax.set(0, 0); + type = 0; + label = queryLabel = 0; + leftMargin = rightMargin = 0; + ypos = 0; + height = 0; } Sgroup::Sgroup() @@ -181,6 +189,10 @@ void BondEnd::clear() rnei = lnei = -1; offset = 0; width = 0; + aid = 0; + bid = 0; + rnei = lnei = -1; + dir = lnorm = p = {0, 0}; } IMPL_ERROR(BondDescr, "molrender bond description"); @@ -192,6 +204,7 @@ BondDescr::BondDescr() void BondDescr::clear() { + be2 = be1 = -1; type = -1; queryType = -1; inRing = false; @@ -206,6 +219,10 @@ void BondDescr::clear() tiTopology = -1; topology = 0; reactingCenter = RC_UNMARKED; + lineOnTheRight = false; + isShort = false; + length = 0; + norm = dir = vb = ve = center = {0, 0}; } int BondDescr::getBondEnd(int aid) const @@ -242,6 +259,9 @@ void MoleculeRenderData::clear() atoms.clear(); bonds.clear(); bondends.clear(); + brackets.clear(); + rSiteAttachmentIndices.clear(); + attachmentPoints.clear(); graphitems.clear(); rings.clear(); textitems.clear(); diff --git a/core/render2d/src/render_single.cpp b/core/render2d/src/render_single.cpp index 88bd0391aa..6181b655cb 100644 --- a/core/render2d/src/render_single.cpp +++ b/core/render2d/src/render_single.cpp @@ -36,7 +36,7 @@ using namespace indigo; IMPL_ERROR(RenderSingle, "RenderSingle"); RenderSingle::RenderSingle(RenderContext& rc, RenderItemFactory& factory, const CanvasOptions& cnvOpt, int bondLength, bool bondLengthSet) - : Render(rc, factory, cnvOpt, bondLength, bondLengthSet) + : comment(-1), Render(rc, factory, cnvOpt, bondLength, bondLengthSet) { } diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index 3b6fcb8c9b..035d213936 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -247,6 +247,7 @@ enum OEXT_KER, OEXT_CDX, OEXT_CDXML, + OEXT_SMI, OEXT_OTHER }; @@ -333,7 +334,8 @@ int parseParams(Params* p, int argc, char* argv[]) } p->file_to_load = argv[1]; - if (strcasecmp(p->infile_ext, "mol") == 0 || strcasecmp(p->infile_ext, "ket") == 0 || strcasecmp(p->infile_ext, "xml") == 0) + if (strcasecmp(p->infile_ext, "cdx") == 0 || strcasecmp(p->infile_ext, "mol") == 0 || strcasecmp(p->infile_ext, "ket") == 0 || + strcasecmp(p->infile_ext, "xml") == 0) p->mode = MODE_SINGLE_MOLECULE; else if (strcasecmp(p->infile_ext, "rxn") == 0 || strcasecmp(p->infile_ext, "ker") == 0) p->mode = MODE_SINGLE_REACTION; @@ -841,6 +843,7 @@ int main(int argc, char* argv[]) indigoSetErrorHandler(onError, 0); indigoSetOption("ignore-stereochemistry-errors", "on"); + indigoSetOption("molfile-saving-mode", "3000"); if (parseParams(&p, argc, argv) < 0) return -1; @@ -860,6 +863,8 @@ int main(int argc, char* argv[]) p.out_ext = OEXT_KET; else if (strcmp(p.outfile_ext, "ker") == 0) p.out_ext = OEXT_KER; + else if (strcmp(p.outfile_ext, "smi") == 0) + p.out_ext = OEXT_SMI; // guess whether to layout or render by extension p.action = ACTION_LAYOUT; @@ -896,6 +901,25 @@ int main(int argc, char* argv[]) indigoSaveMolfileToFile(obj, p.outfile); else if (p.out_ext == OEXT_KET) indigoSaveJsonToFile(obj, p.outfile); + else if (p.out_ext == OEXT_SMI) + { + char* pMol; + if (p.query_set) + pMol = indigoSmarts(obj); + else + pMol = indigoSmiles(obj); + FILE* fp = fopen(p.outfile, "w+"); + if (fp) + { + fputs(pMol, fp); + fclose(fp); + } + else + { + fprintf(stderr, "can not write: %s\n", p.outfile); + return -1; + } + } else indigoSaveCmlToFile(obj, p.outfile); }