// $Id$ // // Copyright (C) 2001-2013 Greg Landrum and Rational Discovery LLC // // @@ 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. // #include #include #include #include #include #include #include #include #include #include #include using boost::int32_t; using boost::uint32_t; namespace RDKit { const int32_t MolPickler::versionMajor = 7; const int32_t MolPickler::versionMinor = 2; const int32_t MolPickler::versionPatch = 0; const int32_t MolPickler::endianId = 0xDEADBEEF; void streamWrite(std::ostream &ss, const std::string &what) { unsigned int l = rdcast(what.length()); ss.write((const char *)&l, sizeof(l)); ss.write(what.c_str(), sizeof(char) * l); }; void streamWrite(std::ostream &ss, MolPickler::Tags tag) { unsigned char tmp = static_cast(tag); streamWrite(ss, tmp); } template void streamWrite(std::ostream &ss, MolPickler::Tags tag, const T &what) { streamWrite(ss, tag); streamWrite(ss, what); }; template void streamRead(std::istream &ss, T &obj, int version) { RDUNUSED_PARAM(version); streamRead(ss, obj); } void streamRead(std::istream &ss, std::string &what, int version) { RDUNUSED_PARAM(version); unsigned int l; ss.read((char *)&l, sizeof(l)); char *buff = new char[l + 1]; ss.read(buff, sizeof(char) * l); buff[l] = 0; what = buff; delete[] buff; }; void streamRead(std::istream &ss, MolPickler::Tags &tag, int version) { if (version < 7000) { int32_t tmp; streamRead(ss, tmp, version); tag = static_cast(tmp); } else { unsigned char tmp; streamRead(ss, tmp, version); tag = static_cast(tmp); } } namespace { using namespace Queries; template void pickleQuery(std::ostream &ss, const Query *query) { PRECONDITION(query, "no query"); streamWrite(ss, query->getDescription()); if (query->getNegation()) streamWrite(ss, MolPickler::QUERY_ISNEGATED); int32_t queryVal; // if (typeid(*query)==typeid(ATOM_BOOL_QUERY)){ // streamWrite(ss,QUERY_BOOL); if (typeid(*query) == typeid(AndQuery)) { streamWrite(ss, MolPickler::QUERY_AND); } else if (typeid(*query) == typeid(OrQuery)) { streamWrite(ss, MolPickler::QUERY_OR); } else if (typeid(*query) == typeid(XOrQuery)) { streamWrite(ss, MolPickler::QUERY_XOR); } else if (typeid(*query) == typeid(EqualityQuery)) { streamWrite(ss, MolPickler::QUERY_EQUALS); queryVal = static_cast *>(query) ->getVal(); streamWrite(ss, MolPickler::QUERY_VALUE, queryVal); queryVal = static_cast *>(query) ->getTol(); streamWrite(ss, queryVal); } else if (typeid(*query) == typeid(GreaterQuery)) { streamWrite(ss, MolPickler::QUERY_GREATER); queryVal = static_cast *>(query) ->getVal(); streamWrite(ss, MolPickler::QUERY_VALUE, queryVal); queryVal = static_cast *>(query) ->getTol(); streamWrite(ss, queryVal); } else if (typeid(*query) == typeid(GreaterEqualQuery)) { streamWrite(ss, MolPickler::QUERY_GREATEREQUAL); queryVal = static_cast *>(query) ->getVal(); streamWrite(ss, MolPickler::QUERY_VALUE, queryVal); queryVal = static_cast *>(query) ->getTol(); streamWrite(ss, queryVal); } else if (typeid(*query) == typeid(LessQuery)) { streamWrite(ss, MolPickler::QUERY_LESS); queryVal = static_cast *>(query)->getVal(); streamWrite(ss, MolPickler::QUERY_VALUE, queryVal); queryVal = static_cast *>(query)->getTol(); streamWrite(ss, queryVal); } else if (typeid(*query) == typeid(LessEqualQuery)) { streamWrite(ss, MolPickler::QUERY_LESSEQUAL); queryVal = static_cast *>(query) ->getVal(); streamWrite(ss, MolPickler::QUERY_VALUE, queryVal); queryVal = static_cast *>(query) ->getTol(); streamWrite(ss, queryVal); } else if (typeid(*query) == typeid(RangeQuery)) { streamWrite(ss, MolPickler::QUERY_RANGE); queryVal = static_cast *>(query) ->getLower(); streamWrite(ss, MolPickler::QUERY_VALUE, queryVal); queryVal = static_cast *>(query) ->getUpper(); streamWrite(ss, queryVal); queryVal = static_cast *>(query)->getTol(); streamWrite(ss, queryVal); char ends; bool lowerOpen, upperOpen; boost::tie(lowerOpen, upperOpen) = static_cast *>(query) ->getEndsOpen(); ends = 0 | (rdcast(lowerOpen) << 1) | rdcast(upperOpen); streamWrite(ss, ends); } else if (typeid(*query) == typeid(SetQuery)) { streamWrite(ss, MolPickler::QUERY_SET); queryVal = static_cast *>(query)->size(); streamWrite(ss, MolPickler::QUERY_VALUE, queryVal); typename SetQuery::CONTAINER_TYPE::const_iterator cit; for (cit = static_cast *>(query) ->beginSet(); cit != static_cast *>(query)->endSet(); ++cit) { queryVal = *cit; streamWrite(ss, queryVal); } } else if (typeid(*query) == typeid(AtomRingQuery)) { streamWrite(ss, MolPickler::QUERY_ATOMRING); queryVal = static_cast *>(query) ->getVal(); streamWrite(ss, MolPickler::QUERY_VALUE, queryVal); queryVal = static_cast *>(query) ->getTol(); streamWrite(ss, queryVal); } else if (typeid(*query) == typeid(RecursiveStructureQuery)) { streamWrite(ss, MolPickler::QUERY_RECURSIVE); streamWrite(ss, MolPickler::QUERY_VALUE); MolPickler::pickleMol( ((const RecursiveStructureQuery *)query)->getQueryMol(), ss); } else if (typeid(*query) == typeid(Query)) { streamWrite(ss, MolPickler::QUERY_NULL); } else { throw MolPicklerException("do not know how to pickle part of the query."); } // now the children: streamWrite(ss, MolPickler::QUERY_NUMCHILDREN, static_cast(query->endChildren() - query->beginChildren())); typename Query::CHILD_VECT_CI cit; for (cit = query->beginChildren(); cit != query->endChildren(); ++cit) { pickleQuery(ss, cit->get()); } } void finalizeQueryFromDescription(Query *query, Atom const *owner) { RDUNUSED_PARAM(owner); std::string descr = query->getDescription(); Query *tmpQuery; if (descr == "AtomRingBondCount") { query->setDataFunc(queryAtomRingBondCount); } else if (descr == "AtomHasRingBond") { query->setDataFunc(queryAtomHasRingBond); } else if (descr == "AtomRingSize") { tmpQuery = makeAtomInRingOfSizeQuery( static_cast(query)->getVal()); query->setDataFunc(tmpQuery->getDataFunc()); delete tmpQuery; } else if (descr == "AtomMinRingSize") { query->setDataFunc(queryAtomMinRingSize); } else if (descr == "AtomRingBondCount") { query->setDataFunc(queryAtomRingBondCount); } else if (descr == "AtomImplicitValence") { query->setDataFunc(queryAtomImplicitValence); } else if (descr == "AtomTotalValence") { query->setDataFunc(queryAtomTotalValence); } else if (descr == "AtomAtomicNum") { query->setDataFunc(queryAtomNum); } else if (descr == "AtomExplicitDegree") { query->setDataFunc(queryAtomExplicitDegree); } else if (descr == "AtomTotalDegree") { query->setDataFunc(queryAtomTotalDegree); } else if (descr == "AtomHCount") { query->setDataFunc(queryAtomHCount); } else if (descr == "AtomImplicitHCount") { query->setDataFunc(queryAtomImplicitHCount); } else if (descr == "AtomHasImplicitH") { query->setDataFunc(queryAtomHasImplicitH); } else if (descr == "AtomIsAromatic") { query->setDataFunc(queryAtomAromatic); } else if (descr == "AtomIsAliphatic") { query->setDataFunc(queryAtomAliphatic); } else if (descr == "AtomUnsaturated") { query->setDataFunc(queryAtomUnsaturated); } else if (descr == "AtomMass") { query->setDataFunc(queryAtomMass); } else if (descr == "AtomIsotope") { query->setDataFunc(queryAtomIsotope); } else if (descr == "AtomFormalCharge") { query->setDataFunc(queryAtomFormalCharge); } else if (descr == "AtomHybridization") { query->setDataFunc(queryAtomHybridization); } else if (descr == "AtomInRing") { query->setDataFunc(queryIsAtomInRing); } else if (descr == "AtomInNRings") { query->setDataFunc(queryIsAtomInNRings); } else if (descr == "AtomNull") { query->setDataFunc(nullDataFun); query->setMatchFunc(nullQueryFun); } else if (descr == "AtomInNRings" || descr == "RecursiveStructure") { // don't need to do anything here because the classes // automatically have everything set } else if (descr == "AtomAnd" || descr == "AtomOr" || descr == "AtomXor") { // don't need to do anything here because the classes // automatically have everything set } else { throw MolPicklerException("Do not know how to finalize query: '" + descr + "'"); } } void finalizeQueryFromDescription(Query *query, Bond const *owner) { RDUNUSED_PARAM(owner); std::string descr = query->getDescription(); Query *tmpQuery; if (descr == "BondRingSize") { tmpQuery = makeBondInRingOfSizeQuery( static_cast(query)->getVal()); query->setDataFunc(tmpQuery->getDataFunc()); delete tmpQuery; } else if (descr == "BondMinRingSize") { query->setDataFunc(queryBondMinRingSize); } else if (descr == "BondOrder") { query->setDataFunc(queryBondOrder); } else if (descr == "BondDir") { query->setDataFunc(queryBondDir); } else if (descr == "BondInRing") { query->setDataFunc(queryIsBondInRing); } else if (descr == "BondInNRings") { query->setDataFunc(queryIsBondInNRings); } else if (descr == "BondNull") { query->setDataFunc(nullDataFun); query->setMatchFunc(nullQueryFun); } else if (descr == "BondAnd" || descr == "BondOr" || descr == "BondXor") { // don't need to do anything here because the classes // automatically have everything set } else { throw MolPicklerException("Do not know how to finalize query: '" + descr + "'"); } } template Query *buildBaseQuery(std::istream &ss, T const *owner, MolPickler::Tags tag, int version) { PRECONDITION(owner, "no query"); std::string descr; Query *res = 0; int32_t val; int32_t nMembers; switch (tag) { case MolPickler::QUERY_AND: res = new AndQuery(); break; case MolPickler::QUERY_OR: res = new OrQuery(); break; case MolPickler::QUERY_XOR: res = new XOrQuery(); break; case MolPickler::QUERY_EQUALS: res = new EqualityQuery(); streamRead(ss, tag, version); if (tag != MolPickler::QUERY_VALUE) { throw MolPicklerException( "Bad pickle format: QUERY_VALUE tag not found."); } streamRead(ss, val, version); static_cast *>(res)->setVal(val); streamRead(ss, val, version); static_cast *>(res)->setTol(val); break; case MolPickler::QUERY_GREATER: res = new GreaterQuery(); streamRead(ss, tag, version); if (tag != MolPickler::QUERY_VALUE) { throw MolPicklerException( "Bad pickle format: QUERY_VALUE tag not found."); } streamRead(ss, val, version); static_cast *>(res)->setVal(val); streamRead(ss, val, version); static_cast *>(res)->setTol(val); break; case MolPickler::QUERY_GREATEREQUAL: res = new GreaterEqualQuery(); streamRead(ss, tag, version); if (tag != MolPickler::QUERY_VALUE) { throw MolPicklerException( "Bad pickle format: QUERY_VALUE tag not found."); } streamRead(ss, val, version); static_cast *>(res)->setVal(val); streamRead(ss, val, version); static_cast *>(res)->setTol(val); break; case MolPickler::QUERY_LESS: res = new LessQuery(); streamRead(ss, tag, version); if (tag != MolPickler::QUERY_VALUE) { throw MolPicklerException( "Bad pickle format: QUERY_VALUE tag not found."); } streamRead(ss, val, version); static_cast *>(res)->setVal(val); streamRead(ss, val, version); static_cast *>(res)->setTol(val); break; case MolPickler::QUERY_LESSEQUAL: res = new LessEqualQuery(); streamRead(ss, tag, version); if (tag != MolPickler::QUERY_VALUE) { throw MolPicklerException( "Bad pickle format: QUERY_VALUE tag not found."); } streamRead(ss, val, version); static_cast *>(res)->setVal(val); streamRead(ss, val, version); static_cast *>(res)->setTol(val); break; case MolPickler::QUERY_RANGE: res = new RangeQuery(); streamRead(ss, tag, version); if (tag != MolPickler::QUERY_VALUE) { throw MolPicklerException( "Bad pickle format: QUERY_VALUE tag not found."); } streamRead(ss, val, version); static_cast *>(res)->setLower(val); streamRead(ss, val, version); static_cast *>(res)->setUpper(val); streamRead(ss, val, version); static_cast *>(res)->setTol(val); break; case MolPickler::QUERY_SET: res = new SetQuery(); streamRead(ss, tag, version); if (tag != MolPickler::QUERY_VALUE) { throw MolPicklerException( "Bad pickle format: QUERY_VALUE tag not found."); } streamRead(ss, nMembers); while (nMembers > 0) { streamRead(ss, val, version); static_cast *>(res)->insert(val); --nMembers; } break; case MolPickler::QUERY_NULL: res = new Query(); break; default: throw MolPicklerException("unknown query-type tag encountered"); } POSTCONDITION(res, "no match found"); return res; } Query *unpickleQuery(std::istream &ss, Atom const *owner, int version) { PRECONDITION(owner, "no query"); std::string descr; bool isNegated = false; Query *res; streamRead(ss, descr, version); MolPickler::Tags tag; streamRead(ss, tag, version); if (tag == MolPickler::QUERY_ISNEGATED) { isNegated = true; streamRead(ss, tag, version); } int32_t val; ROMol *tmpMol; switch (tag) { case MolPickler::QUERY_ATOMRING: res = new AtomRingQuery(); streamRead(ss, tag, version); if (tag != MolPickler::QUERY_VALUE) { throw MolPicklerException( "Bad pickle format: QUERY_VALUE tag not found."); } streamRead(ss, val, version); static_cast *>(res)->setVal(val); streamRead(ss, val, version); static_cast *>(res)->setTol(val); break; case MolPickler::QUERY_RECURSIVE: streamRead(ss, tag, version); if (tag != MolPickler::QUERY_VALUE) { throw MolPicklerException( "Bad pickle format: QUERY_VALUE tag not found."); } tmpMol = new ROMol(); MolPickler::molFromPickle(ss, tmpMol); res = new RecursiveStructureQuery(tmpMol); break; default: res = buildBaseQuery(ss, owner, tag, version); break; } CHECK_INVARIANT(res, "no query!"); res->setNegation(isNegated); res->setDescription(descr); finalizeQueryFromDescription(res, owner); // read in the children: streamRead(ss, tag, version); if (tag != MolPickler::QUERY_NUMCHILDREN) { throw MolPicklerException( "Bad pickle format: QUERY_NUMCHILDREN tag not found."); } unsigned char numChildren; streamRead(ss, numChildren, version); while (numChildren > 0) { Query *child = unpickleQuery(ss, owner, version); res->addChild(Query::CHILD_TYPE(child)); --numChildren; } return res; } Query *unpickleQuery(std::istream &ss, Bond const *owner, int version) { PRECONDITION(owner, "no query"); std::string descr; bool isNegated = false; Query *res; streamRead(ss, descr, version); MolPickler::Tags tag; streamRead(ss, tag, version); if (tag == MolPickler::QUERY_ISNEGATED) { isNegated = true; streamRead(ss, tag, version); } res = buildBaseQuery(ss, owner, tag, version); CHECK_INVARIANT(res, "no query!"); res->setNegation(isNegated); res->setDescription(descr); finalizeQueryFromDescription(res, owner); // read in the children: streamRead(ss, tag, version); if (tag != MolPickler::QUERY_NUMCHILDREN) { throw MolPicklerException( "Bad pickle format: QUERY_NUMCHILDREN tag not found."); } unsigned char numChildren; streamRead(ss, numChildren, version); while (numChildren > 0) { Query *child = unpickleQuery(ss, owner, version); res->addChild(Query::CHILD_TYPE(child)); --numChildren; } return res; } void pickleAtomPDBResidueInfo(std::ostream &ss, const AtomPDBResidueInfo *info) { PRECONDITION(info, "no info"); if (info->getSerialNumber()) streamWrite(ss, MolPickler::ATOM_PDB_RESIDUE_SERIALNUMBER, info->getSerialNumber()); if (info->getAltLoc() != "") streamWrite(ss, MolPickler::ATOM_PDB_RESIDUE_ALTLOC, info->getAltLoc()); if (info->getResidueName() != "") streamWrite(ss, MolPickler::ATOM_PDB_RESIDUE_RESIDUENAME, info->getResidueName()); if (info->getResidueNumber()) streamWrite(ss, MolPickler::ATOM_PDB_RESIDUE_RESIDUENUMBER, info->getResidueNumber()); if (info->getChainId() != "") streamWrite(ss, MolPickler::ATOM_PDB_RESIDUE_CHAINID, info->getChainId()); if (info->getInsertionCode() != "") streamWrite(ss, MolPickler::ATOM_PDB_RESIDUE_INSERTIONCODE, info->getInsertionCode()); if (info->getOccupancy()) streamWrite(ss, MolPickler::ATOM_PDB_RESIDUE_OCCUPANCY, info->getOccupancy()); if (info->getTempFactor()) streamWrite(ss, MolPickler::ATOM_PDB_RESIDUE_TEMPFACTOR, info->getTempFactor()); if (info->getIsHeteroAtom()) streamWrite(ss, MolPickler::ATOM_PDB_RESIDUE_ISHETEROATOM, static_cast(info->getIsHeteroAtom())); if (info->getSecondaryStructure()) streamWrite(ss, MolPickler::ATOM_PDB_RESIDUE_SECONDARYSTRUCTURE, info->getSecondaryStructure()); if (info->getSegmentNumber()) streamWrite(ss, MolPickler::ATOM_PDB_RESIDUE_SEGMENTNUMBER, info->getSegmentNumber()); } void unpickleAtomPDBResidueInfo(std::istream &ss, AtomPDBResidueInfo *info, int version) { PRECONDITION(info, "no info"); std::string sval; double dval; char cval; unsigned int uival; int ival; MolPickler::Tags tag = MolPickler::BEGIN_ATOM_MONOMER; while (tag != MolPickler::END_ATOM_MONOMER) { streamRead(ss, tag, version); switch (tag) { case MolPickler::ATOM_PDB_RESIDUE_SERIALNUMBER: streamRead(ss, ival, version); info->setSerialNumber(ival); break; case MolPickler::ATOM_PDB_RESIDUE_ALTLOC: streamRead(ss, sval, version); info->setAltLoc(sval); break; case MolPickler::ATOM_PDB_RESIDUE_RESIDUENAME: streamRead(ss, sval, version); info->setResidueName(sval); break; case MolPickler::ATOM_PDB_RESIDUE_RESIDUENUMBER: streamRead(ss, ival, version); info->setResidueNumber(ival); break; case MolPickler::ATOM_PDB_RESIDUE_CHAINID: streamRead(ss, sval, version); info->setChainId(sval); break; case MolPickler::ATOM_PDB_RESIDUE_INSERTIONCODE: streamRead(ss, sval, version); info->setInsertionCode(sval); break; case MolPickler::ATOM_PDB_RESIDUE_OCCUPANCY: streamRead(ss, dval, version); info->setOccupancy(dval); break; case MolPickler::ATOM_PDB_RESIDUE_TEMPFACTOR: streamRead(ss, dval, version); info->setTempFactor(dval); break; case MolPickler::ATOM_PDB_RESIDUE_ISHETEROATOM: streamRead(ss, cval, version); info->setIsHeteroAtom(cval); break; case MolPickler::ATOM_PDB_RESIDUE_SECONDARYSTRUCTURE: streamRead(ss, uival, version); info->setSecondaryStructure(uival); break; case MolPickler::ATOM_PDB_RESIDUE_SEGMENTNUMBER: streamRead(ss, uival, version); info->setSegmentNumber(uival); break; case MolPickler::END_ATOM_MONOMER: break; default: throw MolPicklerException( "unrecognized tag while parsing atom peptide residue info"); } } } void pickleAtomMonomerInfo(std::ostream &ss, const AtomMonomerInfo *info) { PRECONDITION(info, "no info"); streamWrite(ss, info->getName()); streamWrite(ss, static_cast(info->getMonomerType())); switch (info->getMonomerType()) { case AtomMonomerInfo::UNKNOWN: case AtomMonomerInfo::OTHER: break; case AtomMonomerInfo::PDBRESIDUE: pickleAtomPDBResidueInfo(ss, static_cast(info)); break; default: throw MolPicklerException("unrecognized MonomerType"); } } AtomMonomerInfo *unpickleAtomMonomerInfo(std::istream &ss, int version) { MolPickler::Tags tag; std::string nm; streamRead(ss, nm, version); unsigned int typ; streamRead(ss, typ, version); AtomMonomerInfo *res; switch (typ) { case AtomMonomerInfo::UNKNOWN: case AtomMonomerInfo::OTHER: res = new AtomMonomerInfo(RDKit::AtomMonomerInfo::AtomMonomerType(typ), nm); streamRead(ss, tag, version); if (tag != MolPickler::END_ATOM_MONOMER) throw MolPicklerException( "did not find expected end of atom monomer info"); break; case AtomMonomerInfo::PDBRESIDUE: res = static_cast(new AtomPDBResidueInfo(nm)); unpickleAtomPDBResidueInfo(ss, static_cast(res), version); break; default: throw MolPicklerException("unrecognized MonomerType"); } return res; } } // end of anonymous namespace void MolPickler::pickleMol(const ROMol *mol, std::ostream &ss) { PRECONDITION(mol, "empty molecule"); streamWrite(ss, endianId); streamWrite(ss, static_cast(VERSION)); streamWrite(ss, versionMajor); streamWrite(ss, versionMinor); streamWrite(ss, versionPatch); #ifndef OLD_PICKLE if (mol->getNumAtoms() > 255) { _pickle(mol, ss); } else { _pickle(mol, ss); } #else _pickleV1(mol, ss); #endif } void MolPickler::pickleMol(const ROMol *mol, std::string &res) { PRECONDITION(mol, "empty molecule"); std::stringstream ss(std::ios_base::binary | std::ios_base::out | std::ios_base::in); MolPickler::pickleMol(mol, ss); res = ss.str(); } // NOTE: if the mol passed in here already has atoms and bonds, they will // be left intact. The side effect is that ALL atom and bond bookmarks // will be blown out by the end of this process. void MolPickler::molFromPickle(std::istream &ss, ROMol *mol) { PRECONDITION(mol, "empty molecule"); int32_t tmpInt; mol->clearAllAtomBookmarks(); mol->clearAllBondBookmarks(); streamRead(ss, tmpInt); if (tmpInt != endianId) { throw MolPicklerException( "Bad pickle format: bad endian ID or invalid file format"); } streamRead(ss, tmpInt); if (static_cast(tmpInt) != VERSION) { throw MolPicklerException("Bad pickle format: no version tag"); } int32_t majorVersion, minorVersion, patchVersion; streamRead(ss, majorVersion); streamRead(ss, minorVersion); streamRead(ss, patchVersion); if (majorVersion > versionMajor || (majorVersion == versionMajor && minorVersion > versionMinor)) { BOOST_LOG(rdWarningLog) << "Depickling from a version number (" << majorVersion << "." << minorVersion << ")" << "that is higher than our version (" << versionMajor << "." << versionMinor << ").\nThis probably won't work." << std::endl; } majorVersion = 1000 * majorVersion + minorVersion * 10 + patchVersion; if (majorVersion == 1) { _depickleV1(ss, mol); } else { int32_t numAtoms; streamRead(ss, numAtoms, majorVersion); if (numAtoms > 255) { _depickle(ss, mol, majorVersion, numAtoms); } else { _depickle(ss, mol, majorVersion, numAtoms); } } mol->clearAllAtomBookmarks(); mol->clearAllBondBookmarks(); if (majorVersion < 4000) { // FIX for issue 220 - probably better to change the pickle format later MolOps::assignStereochemistry(*mol, true); } } void MolPickler::molFromPickle(const std::string &pickle, ROMol *mol) { PRECONDITION(mol, "empty molecule"); std::stringstream ss(std::ios_base::binary | std::ios_base::out | std::ios_base::in); ss.write(pickle.c_str(), pickle.length()); MolPickler::molFromPickle(ss, mol); } //-------------------------------------- // // Molecules // //-------------------------------------- template void MolPickler::_pickle(const ROMol *mol, std::ostream &ss) { PRECONDITION(mol, "empty molecule"); int32_t tmpInt; bool includeAtomCoords = true; std::map atomIdxMap; tmpInt = static_cast(mol->getNumAtoms()); streamWrite(ss, tmpInt); tmpInt = static_cast(mol->getNumBonds()); streamWrite(ss, tmpInt); char flag = 0; if (includeAtomCoords) flag |= 0x1 << 7; streamWrite(ss, flag); // ------------------- // // Write Atoms // // ------------------- streamWrite(ss, BEGINATOM); ROMol::ConstAtomIterator atIt; int nWritten = 0; for (atIt = mol->beginAtoms(); atIt != mol->endAtoms(); ++atIt) { _pickleAtom(ss, *atIt); atomIdxMap[(*atIt)->getIdx()] = nWritten; nWritten++; } // ------------------- // // Write Bonds // // ------------------- streamWrite(ss, BEGINBOND); for (unsigned int i = 0; i < mol->getNumBonds(); i++) { _pickleBond(ss, mol->getBondWithIdx(i), atomIdxMap); } // ------------------- // // Write Rings (if present) // // ------------------- const RingInfo *ringInfo = mol->getRingInfo(); if (ringInfo && ringInfo->isInitialized()) { streamWrite(ss, BEGINSSSR); _pickleSSSR(ss, ringInfo, atomIdxMap); } // pickle the conformations if necessary if (includeAtomCoords) { streamWrite(ss, BEGINCONFS); tmpInt = static_cast(mol->getNumConformers()); streamWrite(ss, tmpInt); ROMol::ConstConformerIterator ci; for (ci = mol->beginConformers(); ci != mol->endConformers(); ++ci) { const Conformer *conf = ci->get(); _pickleConformer(ss, conf); } } streamWrite(ss, ENDMOL); } template void MolPickler::_depickle(std::istream &ss, ROMol *mol, int version, int numAtoms) { PRECONDITION(mol, "empty molecule"); bool directMap = mol->getNumAtoms() == 0; Tags tag; int32_t tmpInt; // int numAtoms,numBonds; int numBonds; bool haveQuery = false; streamRead(ss, tmpInt, version); numBonds = tmpInt; // did we include coordinates bool includeCoords = false; if (version >= 3000) { char flag; streamRead(ss, flag, version); if (flag & 0x1 << 7) includeCoords = true; } // ------------------- // // Read Atoms // // ------------------- streamRead(ss, tag, version); if (tag != BEGINATOM) { throw MolPicklerException("Bad pickle format: BEGINATOM tag not found."); } Conformer *conf = 0; if ((version >= 2000 && version < 3000) && includeCoords) { // there can only one conformation - since the poositions were stored on // the atoms themselves in this version conf = new Conformer(numAtoms); mol->addConformer(conf, true); } for (int i = 0; i < numAtoms; i++) { RDGeom::Point3D pos; Atom *atom = _addAtomFromPickle(ss, mol, pos, version, directMap); if ((version >= 2000 && version < 3000) && includeCoords) { // this is a older pickle so we go the pos conf->setAtomPos(i, pos); } if (!directMap) { mol->setAtomBookmark(atom, i); } if (atom->hasQuery()) { haveQuery = true; } } // ------------------- // // Read Bonds // // ------------------- streamRead(ss, tag, version); if (tag != BEGINBOND) { throw MolPicklerException("Bad pickle format: BEGINBOND tag not found."); } for (int i = 0; i < numBonds; i++) { Bond *bond = _addBondFromPickle(ss, mol, version, directMap); if (!directMap) { mol->setBondBookmark(bond, i); } } // ------------------- // // Read Rings (if needed) // // ------------------- streamRead(ss, tag, version); if (tag == BEGINSSSR) { _addRingInfoFromPickle(ss, mol, version, directMap); streamRead(ss, tag, version); } if (tag == BEGINCONFS) { // read in the conformation streamRead(ss, tmpInt, version); int i; for (i = 0; i < tmpInt; i++) { Conformer *conf = _conformerFromPickle(ss, version); mol->addConformer(conf); } streamRead(ss, tag, version); } if (tag != ENDMOL) { throw MolPicklerException("Bad pickle format: ENDMOL tag not found."); } if (haveQuery) { // we didn't read any property info for atoms with associated // queries. update their property caches // (was sf.net Issue 3316407) for (ROMol::AtomIterator atIt = mol->beginAtoms(); atIt != mol->endAtoms(); atIt++) { Atom *atom = *atIt; if (atom->hasQuery()) { atom->updatePropertyCache(false); } } } } //-------------------------------------- // // Atoms // //-------------------------------------- namespace { bool getAtomMapNumber(const Atom *atom, int &mapNum) { PRECONDITION(atom, "bad atom"); if (!atom->hasProp(common_properties::molAtomMapNumber)) return false; bool res = true; int tmpInt; try { atom->getProp(common_properties::molAtomMapNumber, tmpInt); } catch (boost::bad_any_cast &) { const std::string &tmpSVal = atom->getProp(common_properties::molAtomMapNumber); try { tmpInt = boost::lexical_cast(tmpSVal); } catch (boost::bad_lexical_cast &) { res = false; } } if (res) mapNum = tmpInt; return res; } } // T refers to the type of the atom indices written template void MolPickler::_pickleAtom(std::ostream &ss, const Atom *atom) { PRECONDITION(atom, "empty atom"); char tmpChar; unsigned char tmpUchar; signed char tmpSchar; int tmpInt; char flags; tmpUchar = atom->getAtomicNum() % 256; streamWrite(ss, tmpUchar); flags = 0; if (atom->getIsAromatic()) flags |= 0x1 << 6; if (atom->getNoImplicit()) flags |= 0x1 << 5; if (atom->hasQuery()) flags |= 0x1 << 4; if (getAtomMapNumber(atom, tmpInt)) flags |= 0x1 << 3; if (atom->hasProp(common_properties::dummyLabel)) flags |= 0x1 << 2; if (atom->getMonomerInfo()) flags |= 0x1 << 1; streamWrite(ss, flags); if (!atom->hasQuery()) { std::stringstream tss(std::ios_base::binary | std::ios_base::out | std::ios_base::in); int32_t propFlags = 0; // tmpFloat=atom->getMass()-PeriodicTable::getTable()->getAtomicWeight(atom->getAtomicNum()); // if(fabs(tmpFloat)>.0001){ // propFlags |= 1; // streamWrite(tss,tmpFloat); // } tmpSchar = static_cast(atom->getFormalCharge()); if (tmpSchar != 0) { propFlags |= 1 << 1; streamWrite(tss, tmpSchar); } tmpChar = static_cast(atom->getChiralTag()); if (tmpChar != 0) { propFlags |= 1 << 2; streamWrite(tss, tmpChar); } tmpChar = static_cast(atom->getHybridization()); if (tmpChar != static_cast(Atom::SP3)) { propFlags |= 1 << 3; streamWrite(tss, tmpChar); } tmpChar = static_cast(atom->getNumExplicitHs()); if (tmpChar != 0) { propFlags |= 1 << 4; streamWrite(tss, tmpChar); } if (atom->d_explicitValence > 0) { tmpChar = static_cast(atom->d_explicitValence); propFlags |= 1 << 5; streamWrite(tss, tmpChar); } if (atom->d_implicitValence > 0) { tmpChar = static_cast(atom->d_implicitValence); propFlags |= 1 << 6; streamWrite(tss, tmpChar); } tmpChar = static_cast(atom->getNumRadicalElectrons()); if (tmpChar != 0) { propFlags |= 1 << 7; streamWrite(tss, tmpChar); } unsigned int tmpuint = atom->getIsotope(); if (tmpuint > 0) { propFlags |= 1 << 8; streamWrite(tss, tmpuint); } streamWrite(ss, propFlags); ss.write(tss.str().c_str(), tss.str().size()); } else { streamWrite(ss, BEGINQUERY); pickleQuery(ss, static_cast(atom)->getQuery()); streamWrite(ss, ENDQUERY); } if (getAtomMapNumber(atom, tmpInt)) { tmpChar = static_cast(tmpInt % 256); streamWrite(ss, ATOM_MAPNUMBER, tmpChar); } if (atom->hasProp(common_properties::dummyLabel)) { streamWrite(ss, ATOM_DUMMYLABEL, atom->getProp(common_properties::dummyLabel)); } if (atom->getMonomerInfo()) { streamWrite(ss, BEGIN_ATOM_MONOMER); pickleAtomMonomerInfo(ss, atom->getMonomerInfo()); streamWrite(ss, END_ATOM_MONOMER); } } template void MolPickler::_pickleConformer(std::ostream &ss, const Conformer *conf) { PRECONDITION(conf, "empty conformer"); char tmpChr = static_cast(conf->is3D()); streamWrite(ss, tmpChr); int32_t tmpInt = static_cast(conf->getId()); streamWrite(ss, tmpInt); T tmpT = static_cast(conf->getNumAtoms()); streamWrite(ss, tmpT); const RDGeom::POINT3D_VECT &pts = conf->getPositions(); for (RDGeom::POINT3D_VECT_CI pti = pts.begin(); pti != pts.end(); pti++) { float tmpFloat; tmpFloat = static_cast(pti->x); streamWrite(ss, tmpFloat); tmpFloat = static_cast(pti->y); streamWrite(ss, tmpFloat); tmpFloat = static_cast(pti->z); streamWrite(ss, tmpFloat); } } template Conformer *MolPickler::_conformerFromPickle(std::istream &ss, int version) { float tmpFloat; bool is3D = true; if (version > 4000) { char tmpChr; streamRead(ss, tmpChr, version); is3D = static_cast(tmpChr); } int tmpInt; streamRead(ss, tmpInt, version); unsigned int cid = static_cast(tmpInt); T tmpT; streamRead(ss, tmpT, version); unsigned int numAtoms = static_cast(tmpT); Conformer *conf = new Conformer(numAtoms); conf->setId(cid); conf->set3D(is3D); for (unsigned int i = 0; i < numAtoms; i++) { streamRead(ss, tmpFloat, version); conf->getAtomPos(i).x = static_cast(tmpFloat); streamRead(ss, tmpFloat, version); conf->getAtomPos(i).y = static_cast(tmpFloat); streamRead(ss, tmpFloat, version); conf->getAtomPos(i).z = static_cast(tmpFloat); } return conf; } template Atom *MolPickler::_addAtomFromPickle(std::istream &ss, ROMol *mol, RDGeom::Point3D &pos, int version, bool directMap) { RDUNUSED_PARAM(directMap); PRECONDITION(mol, "empty molecule"); float x, y, z; char tmpChar; unsigned char tmpUchar; signed char tmpSchar; char flags; Tags tag; Atom *atom = 0; int atomicNum = 0; streamRead(ss, tmpUchar, version); atomicNum = tmpUchar; bool hasQuery = false; streamRead(ss, flags, version); if (version > 5000) { hasQuery = flags & 0x1 << 4; } if (!hasQuery) { atom = new Atom(atomicNum); } else { atom = new QueryAtom(); if (atomicNum) { // can't set this in the constructor because that builds a // query and we're going to take care of that later: atom->setAtomicNum(atomicNum); } } atom->setIsAromatic(flags & 0x1 << 6); atom->setNoImplicit(flags & 0x1 << 5); bool hasAtomMap = 0, hasDummyLabel = 0; if (version >= 6020) { hasAtomMap = flags & 0x1 << 3; hasDummyLabel = flags & 0x1 << 2; } bool hasMonomerInfo = 0; if (version >= 7020) { hasMonomerInfo = flags & 0x1 << 1; } // are coordinates present? if (flags & 0x1 << 7) { streamRead(ss, x, version); pos.x = static_cast(x); streamRead(ss, y, version); pos.y = static_cast(y); streamRead(ss, z, version); pos.z = static_cast(z); } if (version <= 5000 || !hasQuery) { if (version < 7000) { if (version < 6030) { streamRead(ss, tmpSchar, version); // FIX: technically should be handling this in order to maintain true // backwards compatibility // atom->setMass(PeriodicTable::getTable()->getAtomicWeight(atom->getAtomicNum())+ // static_cast(tmpSchar)); } else { float tmpFloat; streamRead(ss, tmpFloat, version); // FIX: technically should be handling this in order to maintain true // backwards compatibility // atom->setMass(tmpFloat); } streamRead(ss, tmpSchar, version); atom->setFormalCharge(static_cast(tmpSchar)); streamRead(ss, tmpChar, version); atom->setChiralTag(static_cast(tmpChar)); streamRead(ss, tmpChar, version); atom->setHybridization(static_cast(tmpChar)); streamRead(ss, tmpChar, version); atom->setNumExplicitHs(static_cast(tmpChar)); streamRead(ss, tmpChar, version); atom->d_explicitValence = tmpChar; streamRead(ss, tmpChar, version); atom->d_implicitValence = tmpChar; if (version > 6000) { streamRead(ss, tmpChar, version); atom->d_numRadicalElectrons = static_cast(tmpChar); } } else { int propFlags; streamRead(ss, propFlags, version); if (propFlags & 1) { float tmpFloat; streamRead(ss, tmpFloat, version); int iso = static_cast(floor(tmpFloat + atom->getMass() + .0001)); atom->setIsotope(iso); } if (propFlags & (1 << 1)) { streamRead(ss, tmpSchar, version); } else { tmpSchar = 0; } atom->setFormalCharge(static_cast(tmpSchar)); if (propFlags & (1 << 2)) { streamRead(ss, tmpChar, version); } else { tmpChar = 0; } atom->setChiralTag(static_cast(tmpChar)); if (propFlags & (1 << 3)) { streamRead(ss, tmpChar, version); } else { tmpChar = Atom::SP3; } atom->setHybridization(static_cast(tmpChar)); if (propFlags & (1 << 4)) { streamRead(ss, tmpChar, version); } else { tmpChar = 0; } atom->setNumExplicitHs(tmpChar); if (propFlags & (1 << 5)) { streamRead(ss, tmpChar, version); } else { tmpChar = 0; } atom->d_explicitValence = tmpChar; if (propFlags & (1 << 6)) { streamRead(ss, tmpChar, version); } else { tmpChar = 0; } atom->d_implicitValence = tmpChar; if (propFlags & (1 << 7)) { streamRead(ss, tmpChar, version); } else { tmpChar = 0; } atom->d_numRadicalElectrons = static_cast(tmpChar); atom->d_isotope = 0; if (propFlags & (1 << 8)) { unsigned int tmpuint; streamRead(ss, tmpuint, version); atom->setIsotope(tmpuint); } } } else if (version > 5000) { // we have a query: streamRead(ss, tag, version); if (tag != BEGINQUERY) { throw MolPicklerException("Bad pickle format: BEGINQUERY tag not found."); } static_cast(atom)->setQuery(unpickleQuery(ss, atom, version)); streamRead(ss, tag, version); if (tag != ENDQUERY) { throw MolPicklerException("Bad pickle format: ENDQUERY tag not found."); } atom->setNumExplicitHs(0); } if (version > 5000) { if (version < 6020) { unsigned int sPos = rdcast(ss.tellg()); Tags tag; streamRead(ss, tag, version); if (tag == ATOM_MAPNUMBER) { int tmpInt; streamRead(ss, tmpChar, version); tmpInt = tmpChar; atom->setProp(common_properties::molAtomMapNumber, tmpInt); } else { ss.seekg(sPos); } } else { if (hasAtomMap) { Tags tag; streamRead(ss, tag, version); if (tag != ATOM_MAPNUMBER) { throw MolPicklerException( "Bad pickle format: ATOM_MAPNUMBER tag not found."); } int tmpInt; streamRead(ss, tmpChar, version); tmpInt = tmpChar; atom->setProp(common_properties::molAtomMapNumber, tmpInt); } if (hasDummyLabel) { streamRead(ss, tag, version); if (tag != ATOM_DUMMYLABEL) { throw MolPicklerException( "Bad pickle format: ATOM_DUMMYLABEL tag not found."); } std::string tmpStr; streamRead(ss, tmpStr, version); atom->setProp(common_properties::dummyLabel, tmpStr); } } } if (version >= 7020) { if (hasMonomerInfo) { streamRead(ss, tag, version); if (tag != BEGIN_ATOM_MONOMER) { throw MolPicklerException( "Bad pickle format: BEGIN_ATOM_MONOMER tag not found."); } atom->setMonomerInfo(unpickleAtomMonomerInfo(ss, version)); } } mol->addAtom(atom, false, true); return atom; } //-------------------------------------- // // Bonds // //-------------------------------------- template void MolPickler::_pickleBond(std::ostream &ss, const Bond *bond, std::map &atomIdxMap) { PRECONDITION(bond, "empty bond"); T tmpT; char tmpChar; char flags; tmpT = static_cast(atomIdxMap[bond->getBeginAtomIdx()]); streamWrite(ss, tmpT); tmpT = static_cast(atomIdxMap[bond->getEndAtomIdx()]); streamWrite(ss, tmpT); flags = 0; if (bond->getIsAromatic()) flags |= 0x1 << 6; if (bond->getIsConjugated()) flags |= 0x1 << 5; if (bond->hasQuery()) flags |= 0x1 << 4; if (bond->getBondType() != Bond::SINGLE) flags |= 0x1 << 3; if (bond->getBondDir() != Bond::NONE) flags |= 0x1 << 2; if (bond->getStereo() != Bond::STEREONONE) flags |= 0x1 << 1; streamWrite(ss, flags); if (bond->getBondType() != Bond::SINGLE) { tmpChar = static_cast(bond->getBondType()); streamWrite(ss, tmpChar); } if (bond->getBondDir() != Bond::NONE) { tmpChar = static_cast(bond->getBondDir()); streamWrite(ss, tmpChar); } // write info about the stereochemistry: if (bond->getStereo() != Bond::STEREONONE) { tmpChar = static_cast(bond->getStereo()); streamWrite(ss, tmpChar); const INT_VECT &stereoAts = bond->getStereoAtoms(); tmpChar = rdcast(stereoAts.size()); streamWrite(ss, tmpChar); for (INT_VECT_CI idxIt = stereoAts.begin(); idxIt != stereoAts.end(); ++idxIt) { tmpT = static_cast(*idxIt); streamWrite(ss, tmpT); } } if (bond->hasQuery()) { streamWrite(ss, BEGINQUERY); pickleQuery(ss, static_cast(bond)->getQuery()); streamWrite(ss, ENDQUERY); } } template Bond *MolPickler::_addBondFromPickle(std::istream &ss, ROMol *mol, int version, bool directMap) { PRECONDITION(mol, "empty molecule"); char tmpChar; char flags; int begIdx, endIdx; T tmpT; Bond *bond = NULL; streamRead(ss, tmpT, version); if (directMap) { begIdx = tmpT; } else { begIdx = mol->getAtomWithBookmark(static_cast(tmpT))->getIdx(); } streamRead(ss, tmpT, version); if (directMap) { endIdx = tmpT; } else { endIdx = mol->getAtomWithBookmark(static_cast(tmpT))->getIdx(); } streamRead(ss, flags, version); bool hasQuery = flags & 0x1 << 4; if (version <= 5000 || (version <= 7000 && !hasQuery) || version > 7000) { bond = new Bond(); bond->setIsAromatic(flags & 0x1 << 6); bond->setIsConjugated(flags & 0x1 << 5); if (version < 7000) { streamRead(ss, tmpChar, version); bond->setBondType(static_cast(tmpChar)); streamRead(ss, tmpChar, version); bond->setBondDir(static_cast(tmpChar)); if (version > 3000) { streamRead(ss, tmpChar, version); Bond::BondStereo stereo = static_cast(tmpChar); bond->setStereo(stereo); if (stereo != Bond::STEREONONE) { streamRead(ss, tmpChar, version); for (char i = 0; i < tmpChar; ++i) { streamRead(ss, tmpT, version); bond->getStereoAtoms().push_back(static_cast(tmpT)); } } } } else { if (flags & (0x1 << 3)) { streamRead(ss, tmpChar, version); bond->setBondType(static_cast(tmpChar)); } else { bond->setBondType(Bond::SINGLE); } if (flags & (0x1 << 2)) { streamRead(ss, tmpChar, version); bond->setBondDir(static_cast(tmpChar)); } else { bond->setBondDir(Bond::NONE); } if (flags & (0x1 << 1)) { streamRead(ss, tmpChar, version); Bond::BondStereo stereo = static_cast(tmpChar); bond->setStereo(stereo); streamRead(ss, tmpChar, version); for (char i = 0; i < tmpChar; ++i) { streamRead(ss, tmpT, version); bond->getStereoAtoms().push_back(static_cast(tmpT)); } } else { bond->setStereo(Bond::STEREONONE); } } } if (version > 5000 && hasQuery) { Tags tag; if (bond) { Bond *tbond = bond; bond = new QueryBond(*bond); delete tbond; } else { bond = new QueryBond(); } // we have a query: streamRead(ss, tag, version); if (tag != BEGINQUERY) { throw MolPicklerException("Bad pickle format: BEGINQUERY tag not found."); } static_cast(bond)->setQuery(unpickleQuery(ss, bond, version)); streamRead(ss, tag, version); if (tag != ENDQUERY) { throw MolPicklerException("Bad pickle format: ENDQUERY tag not found."); } } if (bond) { bond->setBeginAtomIdx(begIdx); bond->setEndAtomIdx(endIdx); mol->addBond(bond, true); } return bond; } //-------------------------------------- // // Rings // //-------------------------------------- template void MolPickler::_pickleSSSR(std::ostream &ss, const RingInfo *ringInfo, std::map &atomIdxMap) { PRECONDITION(ringInfo, "missing ring info"); T tmpT; tmpT = ringInfo->numRings(); streamWrite(ss, tmpT); for (unsigned int i = 0; i < ringInfo->numRings(); i++) { INT_VECT ring; ring = ringInfo->atomRings()[i]; tmpT = static_cast(ring.size()); streamWrite(ss, tmpT); for (unsigned int j = 0; j < ring.size(); j++) { tmpT = static_cast(atomIdxMap[ring[j]]); streamWrite(ss, tmpT); } #if 0 ring = ringInfo->bondRings()[i]; tmpT = static_cast(ring.size()); streamWrite(ss,tmpT); for(unsigned int j=0;j(ring[j]); streamWrite(ss,tmpT); } #endif } } template void MolPickler::_addRingInfoFromPickle(std::istream &ss, ROMol *mol, int version, bool directMap) { PRECONDITION(mol, "empty molecule"); RingInfo *ringInfo = mol->getRingInfo(); if (!ringInfo->isInitialized()) ringInfo->initialize(); T numRings; streamRead(ss, numRings, version); if (numRings > 0) { ringInfo->preallocate(mol->getNumAtoms(), mol->getNumBonds()); for (unsigned int i = 0; i < static_cast(numRings); i++) { T tmpT; T ringSize; streamRead(ss, ringSize, version); INT_VECT atoms(static_cast(ringSize)); INT_VECT bonds(static_cast(ringSize)); for (unsigned int j = 0; j < static_cast(ringSize); j++) { streamRead(ss, tmpT, version); if (directMap) { atoms[j] = static_cast(tmpT); } else { atoms[j] = mol->getAtomWithBookmark(static_cast(tmpT))->getIdx(); } } if (version < 7000) { for (unsigned int j = 0; j < static_cast(ringSize); j++) { streamRead(ss, tmpT, version); if (directMap) { bonds[j] = static_cast(tmpT); } else { bonds[j] = mol->getBondWithBookmark(static_cast(tmpT))->getIdx(); } } } else { for (unsigned int j = 1; j < static_cast(ringSize); ++j) { bonds[j - 1] = mol->getBondBetweenAtoms(atoms[j - 1], atoms[j])->getIdx(); } bonds[ringSize - 1] = mol->getBondBetweenAtoms(atoms[0], atoms[ringSize - 1])->getIdx(); } ringInfo->addRing(atoms, bonds); } } } //-------------------------------------- // // Version 1 Pickler: // // NOTE: this is not 64bit clean, but it shouldn't be used anymore anyway // //-------------------------------------- void MolPickler::_pickleV1(const ROMol *mol, std::ostream &ss) { PRECONDITION(mol, "empty molecule"); ROMol::ConstAtomIterator atIt; const Conformer *conf = 0; if (mol->getNumConformers() > 0) { conf = &(mol->getConformer()); } for (atIt = mol->beginAtoms(); atIt != mol->endAtoms(); atIt++) { const Atom *atom = *atIt; streamWrite(ss, BEGINATOM); streamWrite(ss, ATOM_NUMBER, atom->getAtomicNum()); streamWrite(ss, ATOM_INDEX, atom->getIdx()); streamWrite(ss, ATOM_POS); RDGeom::Point3D p; if (conf) { p = conf->getAtomPos(atom->getIdx()); } streamWrite(ss, p.x); streamWrite(ss, p.y); streamWrite(ss, p.z); if (atom->getFormalCharge() != 0) { streamWrite(ss, ATOM_CHARGE, atom->getFormalCharge()); } if (atom->getNumExplicitHs() != 0) { streamWrite(ss, ATOM_NEXPLICIT, atom->getNumExplicitHs()); } if (atom->getChiralTag() != 0) { streamWrite(ss, ATOM_CHIRALTAG, atom->getChiralTag()); } if (atom->getIsAromatic()) { streamWrite(ss, ATOM_ISAROMATIC, static_cast(atom->getIsAromatic())); } streamWrite(ss, ENDATOM); } ROMol::ConstBondIterator bondIt; for (bondIt = mol->beginBonds(); bondIt != mol->endBonds(); bondIt++) { const Bond *bond = *bondIt; streamWrite(ss, BEGINBOND); streamWrite(ss, BOND_INDEX, bond->getIdx()); streamWrite(ss, BOND_BEGATOMIDX, bond->getBeginAtomIdx()); streamWrite(ss, BOND_ENDATOMIDX, bond->getEndAtomIdx()); streamWrite(ss, BOND_TYPE, bond->getBondType()); if (bond->getBondDir()) { streamWrite(ss, BOND_DIR, bond->getBondDir()); } streamWrite(ss, ENDBOND); } streamWrite(ss, ENDMOL); } void MolPickler::_depickleV1(std::istream &ss, ROMol *mol) { PRECONDITION(mol, "empty molecule"); Tags tag; Conformer *conf = new Conformer(); mol->addConformer(conf); streamRead(ss, tag, 1); while (tag != ENDMOL) { switch (tag) { case BEGINATOM: _addAtomFromPickleV1(ss, mol); break; case BEGINBOND: _addBondFromPickleV1(ss, mol); break; default: UNDER_CONSTRUCTION("bad tag in pickle"); } streamRead(ss, tag, 1); } mol->clearAllAtomBookmarks(); mol->clearAllBondBookmarks(); } void MolPickler::_addAtomFromPickleV1(std::istream &ss, ROMol *mol) { PRECONDITION(mol, "empty molecule"); Tags tag; int intVar; double dblVar; char charVar; int version = 1; streamRead(ss, tag, version); Atom *atom = new Atom(); Conformer &conf = mol->getConformer(); RDGeom::Point3D pos; while (tag != ENDATOM) { switch (tag) { case ATOM_INDEX: streamRead(ss, intVar, version); mol->setAtomBookmark(atom, intVar); break; case ATOM_NUMBER: streamRead(ss, intVar, version); atom->setAtomicNum(intVar); break; case ATOM_POS: streamRead(ss, pos.x, version); streamRead(ss, pos.y, version); streamRead(ss, pos.z, version); break; case ATOM_CHARGE: streamRead(ss, intVar, version); atom->setFormalCharge(intVar); break; case ATOM_NEXPLICIT: streamRead(ss, intVar, version); atom->setNumExplicitHs(intVar); break; case ATOM_CHIRALTAG: streamRead(ss, intVar, version); atom->setChiralTag(static_cast(intVar)); break; case ATOM_MASS: streamRead(ss, dblVar, version); // we don't need to set this anymore, but we do need to read it in order // to // maintain backwards compatibility break; case ATOM_ISAROMATIC: streamRead(ss, charVar, version); atom->setIsAromatic(charVar); break; default: ASSERT_INVARIANT(0, "bad tag in atom block of pickle"); } streamRead(ss, tag, version); } unsigned int id = mol->addAtom(atom, false, true); conf.setAtomPos(id, pos); } void MolPickler::_addBondFromPickleV1(std::istream &ss, ROMol *mol) { PRECONDITION(mol, "empty molecule"); Tags tag; int intVar, idx = -1; int version = 1; Bond::BondType bt; Bond::BondDir bd; streamRead(ss, tag, version); Bond *bond = new Bond(); while (tag != ENDBOND) { switch (tag) { case BOND_INDEX: streamRead(ss, idx, version); break; case BOND_BEGATOMIDX: streamRead(ss, intVar, version); bond->setBeginAtomIdx(mol->getAtomWithBookmark(intVar)->getIdx()); break; case BOND_ENDATOMIDX: streamRead(ss, intVar, version); bond->setEndAtomIdx(mol->getAtomWithBookmark(intVar)->getIdx()); break; case BOND_TYPE: streamRead(ss, bt, version); bond->setBondType(bt); break; case BOND_DIR: streamRead(ss, bd, version); bond->setBondDir(bd); break; default: ASSERT_INVARIANT(0, "bad tag in bond block of pickle"); } streamRead(ss, tag, version); } mol->addBond(bond, true); } };