// // Copyright (C) 2021 Greg Landrum // // @@ All Rights Reserved @@ // This file is part of the RDKit. // The contents are covered by the terms of the BSD license // which is included in the file license.txt, found at the root // of the RDKit source tree. // #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include #include #include #include #include #ifdef RDK_BUILD_INCHI_SUPPORT #include #endif #include #include "cffiwrapper.h" namespace bj = boost::json; using namespace RDKit; #if (defined(__GNUC__) || defined(__GNUG__)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion-null" #endif namespace { char *str_to_c(const std::string &str, size_t *len = nullptr) { if (len) { *len = 0; } char *res; res = (char *)malloc(str.size() + 1); if (res) { if (len) { *len = str.size(); } memcpy(res, str.c_str(), str.size()); res[str.size()] = '\0'; } return res; } char *str_to_c(const char *str) { char *res; res = (char *)malloc(strlen(str) + 1); if (res) { strcpy(res, str); } return res; } } // namespace void mol_to_pkl( const ROMol &mol, char **mol_pkl, size_t *mol_pkl_sz, unsigned int propFlags = PicklerOps::PropertyPickleOptions::AllProps ^ PicklerOps::PropertyPickleOptions::ComputedProps) { std::string pkl; MolPickler::pickleMol(mol, pkl, propFlags); free(*mol_pkl); *mol_pkl = str_to_c(pkl, mol_pkl_sz); } RWMol mol_from_pkl(const char *pkl, size_t pkl_sz) { if (!pkl || !pkl_sz) { return RWMol(); } std::string mol_pkl(pkl, pkl_sz); RWMol res(mol_pkl); res.setProp(common_properties::_StereochemDone, 1, true); return res; } ChemicalReaction rxn_from_pkl(const char *pkl, size_t pkl_sz) { if (!pkl || !pkl_sz) { return ChemicalReaction(); } std::string rxn_pkl(pkl, pkl_sz); ChemicalReaction res(rxn_pkl); return res; } #ifdef PT_OPT_GET #undef PT_OPT_GET #endif #define PT_OPT_GET(opt) opt = pt.get(#opt, opt); namespace { SmilesWriteParams smiles_helper(const char *details_json) { SmilesWriteParams params; updateSmilesWriteParamsFromJSON(params, details_json); return params; } std::string cxsmiles_helper(const char *pkl, size_t pkl_sz, const char *details_json) { if (!pkl || !pkl_sz) { return ""; } auto params = smiles_helper(details_json); auto mol = mol_from_pkl(pkl, pkl_sz); std::uint32_t cxSmilesFields = SmilesWrite::CXSmilesFields::CX_ALL; unsigned int restoreBondDirs = RestoreBondDirOptionClear; updateCXSmilesFieldsFromJSON(cxSmilesFields, restoreBondDirs, details_json); return MolToCXSmiles(mol, params, cxSmilesFields, static_cast(restoreBondDirs)); } char *get_molblock_common(const char *pkl, size_t pkl_sz, const char *details_json, MinimalLib::MDLVersion forceMDLVersion) { if (!pkl || !pkl_sz) { return nullptr; } auto mol = mol_from_pkl(pkl, pkl_sz); auto data = MinimalLib::molblock_helper(mol, details_json, forceMDLVersion); return str_to_c(data); } } // namespace extern "C" char *get_smiles(const char *pkl, size_t pkl_sz, const char *details_json) { if (!pkl || !pkl_sz) { return nullptr; } auto params = smiles_helper(details_json); auto mol = mol_from_pkl(pkl, pkl_sz); auto data = MolToSmiles(mol, params); return str_to_c(data); } extern "C" char *get_smarts(const char *pkl, size_t pkl_sz, const char *details_json) { if (!pkl || !pkl_sz) { return nullptr; } auto params = smiles_helper(details_json); auto mol = mol_from_pkl(pkl, pkl_sz); auto data = MolToSmarts(mol, params.doIsomericSmiles, params.rootedAtAtom); return str_to_c(data); } extern "C" char *get_cxsmiles(const char *pkl, size_t pkl_sz, const char *details_json) { if (!pkl || !pkl_sz) { return nullptr; } auto data = cxsmiles_helper(pkl, pkl_sz, details_json); return str_to_c(data); } extern "C" char *get_cxsmarts(const char *pkl, size_t pkl_sz, const char *details_json) { if (!pkl || !pkl_sz) { return nullptr; } auto params = smiles_helper(details_json); auto mol = mol_from_pkl(pkl, pkl_sz); auto data = MolToCXSmarts(mol, params.doIsomericSmiles); return str_to_c(data); } extern "C" char *get_molblock(const char *pkl, size_t pkl_sz, const char *details_json) { return get_molblock_common(pkl, pkl_sz, details_json, MinimalLib::MDLVersion::AUTO); } extern "C" char *get_v3kmolblock(const char *pkl, size_t pkl_sz, const char *details_json) { return get_molblock_common(pkl, pkl_sz, details_json, MinimalLib::MDLVersion::V3000); } extern "C" char *get_v2kmolblock(const char *pkl, size_t pkl_sz, const char *details_json) { return get_molblock_common(pkl, pkl_sz, details_json, MinimalLib::MDLVersion::V2000); } extern "C" char *get_json(const char *pkl, size_t pkl_sz, const char *) { if (!pkl || !pkl_sz) { return nullptr; } auto mol = mol_from_pkl(pkl, pkl_sz); auto data = MolInterchange::MolToJSONData(mol); return str_to_c(data); } extern "C" void free_ptr(char *ptr) { if (ptr) { free(ptr); } } extern "C" char *get_svg(const char *pkl, size_t pkl_sz, const char *details_json) { if (!pkl || !pkl_sz) { return nullptr; } auto mol = mol_from_pkl(pkl, pkl_sz); unsigned int width = MinimalLib::d_defaultWidth; unsigned int height = MinimalLib::d_defaultHeight; return str_to_c(MinimalLib::mol_to_svg(mol, width, height, details_json)); } extern "C" char *get_rxn_svg(const char *pkl, size_t pkl_sz, const char *details_json) { if (!pkl || !pkl_sz) { return nullptr; } auto rxn = rxn_from_pkl(pkl, pkl_sz); unsigned int width = MinimalLib::d_defaultWidth; unsigned int height = MinimalLib::d_defaultHeight; return str_to_c(MinimalLib::rxn_to_svg(rxn, width, height, details_json)); } #ifdef RDK_BUILD_INCHI_SUPPORT extern "C" char *get_inchi(const char *pkl, size_t pkl_sz, const char *details_json) { if (!pkl || !pkl_sz) { return nullptr; } auto mol = mol_from_pkl(pkl, pkl_sz); ExtraInchiReturnValues rv; auto options = MinimalLib::parse_inchi_options(details_json); return str_to_c( MolToInchi(mol, rv, !options.empty() ? options.c_str() : nullptr)); } extern "C" char *get_inchi_for_molblock(const char *ctab, const char *details_json) { if (!ctab) { return str_to_c(""); } ExtraInchiReturnValues rv; auto options = MinimalLib::parse_inchi_options(details_json); return str_to_c( MolBlockToInchi(ctab, rv, !options.empty() ? options.c_str() : nullptr)); } extern "C" char *get_inchikey_for_inchi(const char *inchi) { if (!inchi) { return str_to_c(""); } return str_to_c(InchiToInchiKey(inchi)); } #endif extern "C" char *get_mol(const char *input, size_t *pkl_sz, const char *details_json) { std::unique_ptr mol{MinimalLib::mol_from_input(input, details_json)}; if (!mol) { *pkl_sz = 0; return nullptr; } unsigned int propFlags = PicklerOps::PropertyPickleOptions::AllProps ^ PicklerOps::PropertyPickleOptions::ComputedProps; MinimalLib::updatePropertyPickleOptionsFromJSON(propFlags, details_json); std::string pkl; MolPickler::pickleMol(*mol, pkl, propFlags); return str_to_c(pkl, pkl_sz); } extern "C" char *get_qmol(const char *input, size_t *pkl_sz, const char *details_json) { std::unique_ptr mol{MinimalLib::qmol_from_input(input, details_json)}; if (!mol) { *pkl_sz = 0; return nullptr; } static const unsigned int propFlags = PicklerOps::PropertyPickleOptions::AllProps ^ PicklerOps::PropertyPickleOptions::ComputedProps; std::string pkl; MolPickler::pickleMol(*mol, pkl, propFlags); return str_to_c(pkl, pkl_sz); } extern "C" char *get_rxn(const char *input, size_t *pkl_sz, const char *details_json) { std::unique_ptr rxn{ MinimalLib::rxn_from_input(input, details_json)}; if (!rxn) { *pkl_sz = 0; return nullptr; } unsigned int propFlags = PicklerOps::PropertyPickleOptions::AllProps ^ PicklerOps::PropertyPickleOptions::ComputedProps; std::string pkl; ReactionPickler::pickleReaction(*rxn, pkl, propFlags); return str_to_c(pkl, pkl_sz); } extern "C" char **get_mol_frags(const char *pkl, size_t pkl_sz, size_t **frags_pkl_sz_array, size_t *num_frags, const char *details_json, char **mappings_json) { if (!pkl || !pkl_sz || !frags_pkl_sz_array || !num_frags) { return nullptr; } *frags_pkl_sz_array = nullptr; *num_frags = 0; auto mol = mol_from_pkl(pkl, pkl_sz); std::vector frags; std::vector> fragsMolAtomMapping; bool sanitizeFrags = true; bool copyConformers = true; if (details_json) { std::string json = details_json; MinimalLib::get_mol_frags_details(json, sanitizeFrags, copyConformers); } std::vector molFrags; try { molFrags = MolOps::getMolFrags(mol, sanitizeFrags, &frags, &fragsMolAtomMapping, copyConformers); } catch (...) { } if (molFrags.empty()) { return nullptr; } char **molPklArray = (char **)malloc(sizeof(char *) * molFrags.size()); if (!molPklArray) { return nullptr; } *frags_pkl_sz_array = (size_t *)malloc(sizeof(size_t) * molFrags.size()); if (!*frags_pkl_sz_array) { free(molPklArray); return nullptr; } memset(molPklArray, 0, sizeof(char *) * molFrags.size()); *num_frags = molFrags.size(); for (size_t i = 0; i < molFrags.size(); ++i) { mol_to_pkl(*molFrags[i], &molPklArray[i], &(*frags_pkl_sz_array)[i]); } if (mappings_json) { auto res = MinimalLib::get_mol_frags_mappings(frags, fragsMolAtomMapping); *mappings_json = str_to_c(res); } return molPklArray; } extern "C" char *version() { return str_to_c(rdkitVersion); } extern "C" char *get_substruct_match(const char *mol_pkl, size_t mol_pkl_sz, const char *query_pkl, size_t query_pkl_sz, const char *options_json) { if (!mol_pkl || !mol_pkl_sz || !query_pkl || !query_pkl_sz) { return nullptr; } auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz); auto query = mol_from_pkl(query_pkl, query_pkl_sz); SubstructMatchParameters params; if (options_json) { std::string json(options_json); updateSubstructMatchParamsFromJSON(params, json); } params.maxMatches = 1; std::string res = "{}"; auto matches = SubstructMatch(mol, query, params); if (!matches.empty()) { const auto &match = matches[0]; bj::object doc; MinimalLib::get_sss_json(mol, query, match, doc); res = bj::serialize(doc); } return str_to_c(res); } extern "C" char *get_substruct_matches(const char *mol_pkl, size_t mol_pkl_sz, const char *query_pkl, size_t query_pkl_sz, const char *options_json) { if (!mol_pkl || !mol_pkl_sz || !query_pkl || !query_pkl_sz) { return nullptr; } auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz); auto query = mol_from_pkl(query_pkl, query_pkl_sz); SubstructMatchParameters params; if (options_json) { std::string json(options_json); updateSubstructMatchParamsFromJSON(params, json); } std::string res = "{}"; auto matches = SubstructMatch(mol, query, params); if (!matches.empty()) { bj::array doc; for (const auto &match : matches) { bj::object bjMatch; MinimalLib::get_sss_json(mol, query, match, bjMatch); doc.push_back(bjMatch); } res = bj::serialize(doc); } return str_to_c(res); } extern "C" char *get_descriptors(const char *mol_pkl, size_t mol_pkl_sz) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz); return str_to_c(MinimalLib::get_descriptors(mol)); } extern "C" char *get_morgan_fp(const char *mol_pkl, size_t mol_pkl_sz, const char *details_json) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::morgan_fp_as_bitvect( mol_from_pkl(mol_pkl, mol_pkl_sz), details_json); auto res = BitVectToText(*fp); return str_to_c(res); } catch (...) { return nullptr; } } extern "C" char *get_morgan_fp_as_bytes(const char *mol_pkl, size_t mol_pkl_sz, size_t *nbytes, const char *details_json) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::morgan_fp_as_bitvect( mol_from_pkl(mol_pkl, mol_pkl_sz), details_json); auto res = BitVectToBinaryText(*fp); return str_to_c(res, nbytes); } catch (...) { return nullptr; } } extern "C" char *get_rdkit_fp(const char *mol_pkl, size_t mol_pkl_sz, const char *details_json) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::rdkit_fp_as_bitvect(mol_from_pkl(mol_pkl, mol_pkl_sz), details_json); auto res = BitVectToText(*fp); return str_to_c(res); } catch (...) { return nullptr; } } extern "C" char *get_rdkit_fp_as_bytes(const char *mol_pkl, size_t mol_pkl_sz, size_t *nbytes, const char *details_json) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::rdkit_fp_as_bitvect(mol_from_pkl(mol_pkl, mol_pkl_sz), details_json); auto res = BitVectToBinaryText(*fp); return str_to_c(res, nbytes); } catch (...) { return nullptr; } } extern "C" char *get_pattern_fp(const char *mol_pkl, size_t mol_pkl_sz, const char *details_json) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::pattern_fp_as_bitvect( mol_from_pkl(mol_pkl, mol_pkl_sz), details_json); auto res = BitVectToText(*fp); return str_to_c(res); } catch (...) { return nullptr; } } extern "C" char *get_pattern_fp_as_bytes(const char *mol_pkl, size_t mol_pkl_sz, size_t *nbytes, const char *details_json) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::pattern_fp_as_bitvect( mol_from_pkl(mol_pkl, mol_pkl_sz), details_json); auto res = BitVectToBinaryText(*fp); return str_to_c(res, nbytes); } catch (...) { return nullptr; } } extern "C" char *get_topological_torsion_fp(const char *mol_pkl, size_t mol_pkl_sz, const char *details_json) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::topological_torsion_fp_as_bitvect( mol_from_pkl(mol_pkl, mol_pkl_sz), details_json); auto res = BitVectToText(*fp); return str_to_c(res); } catch (...) { return nullptr; } } extern "C" char *get_topological_torsion_fp_as_bytes(const char *mol_pkl, size_t mol_pkl_sz, size_t *nbytes, const char *details_json) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::topological_torsion_fp_as_bitvect( mol_from_pkl(mol_pkl, mol_pkl_sz), details_json); auto res = BitVectToBinaryText(*fp); return str_to_c(res, nbytes); } catch (...) { return nullptr; } } extern "C" char *get_atom_pair_fp(const char *mol_pkl, size_t mol_pkl_sz, const char *details_json) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::atom_pair_fp_as_bitvect( mol_from_pkl(mol_pkl, mol_pkl_sz), details_json); auto res = BitVectToText(*fp); return str_to_c(res); } catch (...) { return nullptr; } } extern "C" char *get_atom_pair_fp_as_bytes(const char *mol_pkl, size_t mol_pkl_sz, size_t *nbytes, const char *details_json) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::atom_pair_fp_as_bitvect( mol_from_pkl(mol_pkl, mol_pkl_sz), details_json); auto res = BitVectToBinaryText(*fp); return str_to_c(res, nbytes); } catch (...) { return nullptr; } } extern "C" char *get_maccs_fp(const char *mol_pkl, size_t mol_pkl_sz) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::maccs_fp_as_bitvect(mol_from_pkl(mol_pkl, mol_pkl_sz)); auto res = BitVectToText(*fp); return str_to_c(res); } catch (...) { return nullptr; } } extern "C" char *get_maccs_fp_as_bytes(const char *mol_pkl, size_t mol_pkl_sz, size_t *nbytes) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::maccs_fp_as_bitvect(mol_from_pkl(mol_pkl, mol_pkl_sz)); auto res = BitVectToBinaryText(*fp); return str_to_c(res, nbytes); } catch (...) { return nullptr; } } #ifdef RDK_BUILD_AVALON_SUPPORT extern "C" char *get_avalon_fp(const char *mol_pkl, size_t mol_pkl_sz, const char *details_json) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::avalon_fp_as_bitvect( mol_from_pkl(mol_pkl, mol_pkl_sz), details_json); auto res = BitVectToText(*fp); return str_to_c(res); } catch (...) { return nullptr; } } extern "C" char *get_avalon_fp_as_bytes(const char *mol_pkl, size_t mol_pkl_sz, size_t *nbytes, const char *details_json) { if (!mol_pkl || !mol_pkl_sz) { return nullptr; } try { auto fp = MinimalLib::avalon_fp_as_bitvect( mol_from_pkl(mol_pkl, mol_pkl_sz), details_json); auto res = BitVectToBinaryText(*fp); return str_to_c(res, nbytes); } catch (...) { return nullptr; } } #endif extern "C" void prefer_coordgen(short val) { #ifdef RDK_BUILD_COORDGEN_SUPPORT RDDepict::preferCoordGen = val; #endif }; extern "C" short has_coords(const char *mol_pkl, size_t mol_pkl_sz) { short res = 0; if (mol_pkl && mol_pkl_sz) { auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz); res = (mol.getNumConformers() > 0); if (res) { res = mol.getConformer().is3D() ? 3 : 2; } } return res; } extern "C" short set_2d_coords(char **mol_pkl, size_t *mol_pkl_sz) { if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz) { return 0; } auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz); RDDepict::compute2DCoords(mol); mol_to_pkl(mol, mol_pkl, mol_pkl_sz); return 1; } extern "C" short set_2d_coords_aligned(char **mol_pkl, size_t *mol_pkl_sz, const char *template_pkl, size_t template_sz, const char *details_json, char **match_json) { if (match_json) { *match_json = nullptr; } if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz || !template_pkl || !template_sz || !template_pkl || !template_sz) { return 0; } auto templ = mol_from_pkl(template_pkl, template_sz); if (!templ.getNumConformers()) { return 0; } auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz); auto match = MinimalLib::generate_aligned_coords(mol, templ, details_json); if (match.empty()) { return 0; } else { mol_to_pkl(mol, mol_pkl, mol_pkl_sz); if (match_json) { *match_json = str_to_c(match); } return 1; } }; extern "C" short set_3d_coords(char **mol_pkl, size_t *mol_pkl_sz, const char *params_json) { if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz) { return 0; } auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz); std::string json; if (params_json) { json = params_json; } DGeomHelpers::EmbedParameters ps = DGeomHelpers::srETKDGv3; if (!json.empty()) { DGeomHelpers::updateEmbedParametersFromJSON(ps, json); } int res = DGeomHelpers::EmbedMolecule(mol, ps); if (res >= 0) { ++res; } // if we have a coordMap then be sure to clear up the memory that // updateEmbedParametersFromJSON() allocated for it if (ps.coordMap) { delete ps.coordMap; } mol_to_pkl(mol, mol_pkl, mol_pkl_sz); return (short)res; } extern "C" short add_hs(char **mol_pkl, size_t *mol_pkl_sz) { if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz) { return 0; } auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz); MolOps::addHs(mol); // we don't need the properties that sets: for (auto atom : mol.atoms()) { if (atom->getAtomicNum() == 1) { atom->clearProp(common_properties::isImplicit); } } mol_to_pkl(mol, mol_pkl, mol_pkl_sz); return 1; } extern "C" short remove_all_hs(char **mol_pkl, size_t *mol_pkl_sz) { if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz) { return 0; } auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz); MolOps::removeAllHs(mol); mol_to_pkl(mol, mol_pkl, mol_pkl_sz); return 1; } extern "C" short remove_hs(char **mol_pkl, size_t *mol_pkl_sz, const char *details_json) { if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz) { return 0; } auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz); MolOps::RemoveHsParameters ps; bool sanitize = true; MinimalLib::updateRemoveHsParametersFromJSON(ps, sanitize, details_json); MolOps::removeHs(mol, ps, sanitize); mol_to_pkl(mol, mol_pkl, mol_pkl_sz); return 1; } // standardization namespace { template short standardize_func(char **mol_pkl, size_t *mol_pkl_sz, const char *details_json, T func) { if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz) { return 0; } auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz); std::string json; if (details_json) { json = details_json; } std::unique_ptr res(func(mol, json)); mol_to_pkl(*res, mol_pkl, mol_pkl_sz); return 1; } } // namespace extern "C" short cleanup(char **mol_pkl, size_t *mol_pkl_sz, const char *details_json) { return standardize_func(mol_pkl, mol_pkl_sz, details_json, MinimalLib::do_cleanup); }; extern "C" short normalize(char **mol_pkl, size_t *mol_pkl_sz, const char *details_json) { return standardize_func(mol_pkl, mol_pkl_sz, details_json, MinimalLib::do_normalize); }; extern "C" short canonical_tautomer(char **mol_pkl, size_t *mol_pkl_sz, const char *details_json) { return standardize_func(mol_pkl, mol_pkl_sz, details_json, MinimalLib::do_canonical_tautomer); }; extern "C" short charge_parent(char **mol_pkl, size_t *mol_pkl_sz, const char *details_json) { return standardize_func(mol_pkl, mol_pkl_sz, details_json, MinimalLib::do_charge_parent); }; extern "C" short reionize(char **mol_pkl, size_t *mol_pkl_sz, const char *details_json) { return standardize_func(mol_pkl, mol_pkl_sz, details_json, MinimalLib::do_reionize); }; extern "C" short neutralize(char **mol_pkl, size_t *mol_pkl_sz, const char *details_json) { return standardize_func(mol_pkl, mol_pkl_sz, details_json, MinimalLib::do_neutralize); }; extern "C" short fragment_parent(char **mol_pkl, size_t *mol_pkl_sz, const char *details_json) { return standardize_func(mol_pkl, mol_pkl_sz, details_json, MinimalLib::do_fragment_parent); }; // chirality extern "C" short use_legacy_stereo_perception(short value) { short was = Chirality::getUseLegacyStereoPerception(); Chirality::setUseLegacyStereoPerception(value); return was; } extern "C" short allow_non_tetrahedral_chirality(short value) { short was = Chirality::getAllowNontetrahedralChirality(); Chirality::setAllowNontetrahedralChirality(value); return was; } std::unique_ptr MinimalLib::LoggerStateSingletons::d_instance; extern "C" short enable_logging() { return MinimalLib::LogHandle::enableLogging(); } extern "C" short enable_logger(const char *log_name) { return MinimalLib::LogHandle::enableLogging(log_name); } extern "C" short disable_logging() { return MinimalLib::LogHandle::disableLogging(); } extern "C" short disable_logger(const char *log_name) { return MinimalLib::LogHandle::disableLogging(log_name); } extern "C" void *set_log_tee(const char *log_name) { return MinimalLib::LogHandle::setLogTee(log_name); } extern "C" void *set_log_capture(const char *log_name) { return MinimalLib::LogHandle::setLogCapture(log_name); } extern "C" short destroy_log_handle(void **log_handle) { if (!log_handle || !*log_handle) { return 0; } auto lh = reinterpret_cast(*log_handle); delete lh; *log_handle = nullptr; return 1; } extern "C" char *get_log_buffer(void *log_handle) { return log_handle ? str_to_c(reinterpret_cast(log_handle) ->getBuffer()) : nullptr; } extern "C" short clear_log_buffer(void *log_handle) { if (log_handle) { reinterpret_cast(log_handle)->clearBuffer(); return 1; } return 0; } extern "C" short has_prop(const char *mol_pkl, size_t mol_pkl_sz, const char *key) { auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz); return mol.hasProp(key); } extern "C" char **get_prop_list(const char *mol_pkl, size_t mol_pkl_sz, short includePrivate, short includeComputed) { auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz); auto propList = mol.getPropList(includePrivate, includeComputed); std::string propNames; for (const auto &prop : propList) { propNames += prop + ","; } auto resLen = sizeof(char *) * (propList.size() + 1); char **res = (char **)malloc(resLen); if (!res) { return nullptr; } memset(res, 0, resLen); for (size_t i = 0; i < propList.size(); ++i) { res[i] = strdup(propList.at(i).c_str()); if (!res[i]) { while (i--) { free(res[i]); } return nullptr; } } return res; } extern "C" void set_prop(char **mol_pkl, size_t *mol_pkl_sz, const char *key, const char *val, short computed) { auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz); std::string valAsString(val); mol.setProp(key, valAsString, computed); mol_to_pkl(mol, mol_pkl, mol_pkl_sz); } extern "C" char *get_prop(const char *mol_pkl, size_t mol_pkl_sz, const char *key) { auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz); if (!mol.hasProp(key)) { return nullptr; } std::string val; mol.getProp(key, val); return strdup(val.c_str()); } extern "C" short clear_prop(char **mol_pkl, size_t *mol_pkl_sz, const char *key) { auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz); short res = mol.hasProp(key); if (res) { mol.clearProp(key); mol_to_pkl(mol, mol_pkl, mol_pkl_sz); } return res; } extern "C" void keep_props(char **mol_pkl, size_t *mol_pkl_sz, const char *details_json) { auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz); unsigned int propFlags = PicklerOps::PropertyPickleOptions::AllProps ^ PicklerOps::PropertyPickleOptions::ComputedProps; MinimalLib::updatePropertyPickleOptionsFromJSON(propFlags, details_json); mol_to_pkl(mol, mol_pkl, mol_pkl_sz, propFlags); } extern "C" short add_mol_to_png_blob(char **png_blob, size_t *png_blob_sz, const char *pkl, size_t pkl_sz, const char *details_json) { if (!png_blob || !*png_blob || !png_blob_sz || !*png_blob_sz || !pkl || !pkl_sz) { return 0; } PNGMetadataParams params; MinimalLib::updatePNGMetadataParamsFromJSON(params, details_json); std::string pngString(*png_blob, *png_blob_sz); try { auto mol = mol_from_pkl(pkl, pkl_sz); auto updatedPngString = addMolToPNGString(mol, pngString, params); auto updated_png_blob = static_cast(malloc(updatedPngString.size())); if (!updated_png_blob) { return 0; } memcpy(updated_png_blob, updatedPngString.data(), updatedPngString.size()); free(*png_blob); *png_blob = updated_png_blob; *png_blob_sz = updatedPngString.size(); } catch (...) { return 0; } return 1; } extern "C" short get_mol_from_png_blob(const char *png_blob, size_t png_blob_sz, char **pkl, size_t *pkl_sz, const char *details_json) { if (!png_blob || !png_blob_sz || !pkl || !pkl_sz) { return 0; } std::string pngString(png_blob, png_blob_sz); auto mols = MinimalLib::get_mols_from_png_blob_internal(pngString, true, details_json); if (mols.empty()) { return 0; } char *pkl_local = nullptr; size_t pkl_sz_local = 0; mol_to_pkl(*mols.front(), &pkl_local, &pkl_sz_local); if (pkl_local && pkl_sz_local) { *pkl = pkl_local; *pkl_sz = pkl_sz_local; return 1; } return 0; } extern "C" short get_mols_from_png_blob(const char *png_blob, size_t png_blob_sz, char ***pkl_array, size_t **pkl_sz_array, const char *details_json) { if (!png_blob || !png_blob_sz || !pkl_array || !pkl_sz_array) { return 0; } std::string pngString(png_blob, png_blob_sz); auto mols = MinimalLib::get_mols_from_png_blob_internal(pngString, false, details_json); if (mols.empty()) { return 0; } char **pkl_array_local = nullptr; size_t *pkl_sz_array_local = nullptr; size_t mol_array_len = mols.size() + 1; pkl_array_local = (char **)malloc(mol_array_len * sizeof(char *)); if (pkl_array_local) { memset(pkl_array_local, 0, mol_array_len * sizeof(char *)); pkl_sz_array_local = (size_t *)malloc(mol_array_len * sizeof(size_t)); } if (pkl_sz_array_local) { memset(pkl_sz_array_local, 0, mol_array_len * sizeof(size_t)); short i = 0; for (const auto &mol : mols) { mol_to_pkl(*mol, &pkl_array_local[i], &pkl_sz_array_local[i]); if (pkl_array_local[i] && pkl_sz_array_local[i]) { ++i; } else { break; } } if (i == static_cast(mols.size())) { *pkl_array = pkl_array_local; *pkl_sz_array = pkl_sz_array_local; return i; } } free_mol_array(&pkl_array_local, &pkl_sz_array_local); return 0; } extern "C" void free_mol_array(char ***pkl_array, size_t **pkl_sz_array) { if (pkl_array && *pkl_array) { for (size_t i = 0; (*pkl_array)[i]; ++i) { free((*pkl_array)[i]); (*pkl_array)[i] = NULL; } free(*pkl_array); *pkl_array = NULL; } if (pkl_sz_array && *pkl_sz_array) { free(*pkl_sz_array); *pkl_sz_array = NULL; } } #if (defined(__GNUC__) || defined(__GNUG__)) #pragma GCC diagnostic pop #endif