1
/**********************************************************************
2
Copyright (C) 2006 by Fredrik Wallner
3
Some portions Copyright (C) 2006-2007 by Geoffrey Hutchsion
4
Some portions Copyright (C) 2004 by Chris Morley
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation version 2 of the License.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
14
***********************************************************************/
16
#include <openbabel/babelconfig.h>
17
#include <openbabel/obmolecformat.h>
18
#include <openbabel/reaction.h>
19
#include "chemdrawcdx.h"
28
static inline unsigned short bswap_16(unsigned short x) {
29
return (x>>8) | (x<<8);
32
static inline unsigned int bswap_32(unsigned int x) {
33
return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16));
36
static inline unsigned long long bswap_64(unsigned long long x) {
37
return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32));
40
// Macs -- need to use Apple macros to deal with Universal binaries correctly
42
#include <machine/endian.h>
43
#if BYTE_ORDER == BIG_ENDIAN
44
# define READ_INT16(stream,data) \
45
(stream).read ((char*)&data, sizeof(data)); \
46
data = bswap_16 (data);
47
# define READ_INT32(stream,data) \
48
(stream).read ((char*)&data, sizeof(data)); \
49
data = bswap_32 (data);
50
#else BYTE_ORDER == LITTLE_ENDIAN
51
# define READ_INT16(stream,data) \
52
(stream).read ((char*)&data, sizeof(data));
53
# define READ_INT32(stream,data) \
54
(stream).read ((char*)&data, sizeof(data));
59
// defined in babelconfig.h by autoconf (portable to Solaris, BSD, Linux)
60
#ifdef WORDS_BIGENDIAN
61
# define READ_INT16(stream,data) \
62
(stream).read ((char*)&data, sizeof(data)); \
63
data = bswap_16 (data);
64
# define READ_INT32(stream,data) \
65
(stream).read ((char*)&data, sizeof(data)); \
66
data = bswap_32 (data);
68
# define READ_INT16(stream,data) \
69
(stream).read ((char*)&data, sizeof(data));
70
# define READ_INT32(stream,data) \
71
(stream).read ((char*)&data, sizeof(data));
73
// end endian / bigendian issues (on non-Mac systems)
75
// end Apple/non-Apple systems
81
class ChemDrawBinaryFormat : public OBMoleculeFormat
84
//Register this format type ID in the constructor
85
ChemDrawBinaryFormat()
87
OBConversion::RegisterFormat("cdx",this, "chemical/x-cdx");
90
virtual const char* Description() //required
93
"ChemDraw binary format\n"
97
//Optional URL where the file format is specified
98
virtual const char* SpecificationURL()
99
{return "http://www.cambridgesoft.com/services/documentation/sdk/chemdraw/cdx/IntroCDX.htm";};
101
virtual const char* GetMIMEType()
102
{ return "chemical/x-cdx"; };
104
/* Flags() can return be any of the following combined by |
105
or be omitted if none apply
106
NOTREADABLE READONEONLY NOTWRITABLE WRITEONEONLY */
107
virtual unsigned int Flags()
109
return READBINARY|NOTWRITABLE;
112
////////////////////////////////////////////////////
113
/// Declarations for the "API" interface functions. Definitions are below
114
virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv);
115
OBBase* ReadObject(OBConversion* pConv);
116
// virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
126
cdBond(UINT32 bgn, UINT32 e, int ord, int st = 0) : begin(bgn), end (e), order(ord), stereo(st) {}
131
int readFragment(istream *ifs, UINT32 fragmentId,
132
OBMol *pmol, map<UINT32, int> &atoms, list<cdBond> &bonds);
133
int readNode(istream *ifs, UINT32 nodeId, OBMol *pmol,
134
map<UINT32, int> &atoms, list<cdBond> &bonds,
136
int readBond(istream *ifs, UINT32 nodeId, OBMol *pmol, list<cdBond> &bonds);
137
int readGeneric(istream *ifs, UINT32 objId);
138
const char* getName(istream *ifs, UINT32 size);
141
////////////////////////////////////////////////////
143
//Make an instance of the format class
144
ChemDrawBinaryFormat theChemDrawBinaryFormat;
146
/////////////////////////////////////////////////////////////////
147
bool ChemDrawBinaryFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
149
OBMol* pmol = pOb->CastAndClear<OBMol>();
153
istream& ifs = *pConv->GetInStream();
154
char buffer[BUFF_SIZE];
155
char errorMsg[BUFF_SIZE];
159
map<UINT32, int> atoms;
161
list<cdBond>::const_iterator bondsIter;
167
if (!ifs.good() || ifs.peek() == EOF)
172
pmol->SetTitle(pConv->GetTitle());
174
if((int)ifs.tellg() == 0) // Beginning of file
176
ifs.read(buffer,kCDX_HeaderStringLen);
177
if(strncmp(buffer, kCDX_HeaderString, kCDX_HeaderStringLen) == 0) // File header
179
ifs.seekg (kCDX_HeaderLength - kCDX_HeaderStringLen, ios_base::cur); // Discard rest of header.
183
cout << "Invalid file, no ChemDraw Header" << endl; // No header, error.
184
ifs.seekg(0, ios_base::end);
190
READ_INT16 (ifs, tag);
191
if(tag & kCDXTag_Object) // Object
193
READ_INT32 (ifs, id);
194
snprintf(errorMsg, BUFF_SIZE, "Object ID: %08X in root has type: %04X\n", id, tag);
195
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
197
if(tag == kCDXObj_Fragment)
199
if(readFragment(&ifs, id, pmol, atoms, bonds) != 0)
201
obErrorLog.ThrowError(__FUNCTION__, "Error reading fragment", obWarning);
205
prevBond = cdBond(0,0,0);
206
for (bondsIter=bonds.begin(); bondsIter != bonds.end(); bondsIter++)
208
// printf("Bond between %08X (%d) and %08x (%d)\n", bondsIter->begin, atoms[bondsIter->begin], bondsIter->end, atoms[bondsIter->end]);
209
if(atoms[bondsIter->begin] == -1)
211
// printf("Bond starts at a non-atom\n");
212
if(atoms[bondsIter->end] == -1)
214
// printf("Bond between two non-atoms pushed back\n");
215
if((prevBond.begin == bondsIter->begin) && (prevBond.end == bondsIter->end))
217
obErrorLog.ThrowError(__FUNCTION__, "Can't assign all bonds!", obDebug);
220
bonds.push_back(*bondsIter);
223
atoms[bondsIter->begin] = atoms[bondsIter->end];
225
else if(atoms[bondsIter->end] == -1)
226
atoms[bondsIter->end] = atoms[bondsIter->begin];
230
switch (bondsIter->stereo)
232
case kCDXBondDisplay_WedgedHashBegin:
233
case kCDXBondDisplay_WedgeEnd:
234
flags = OB_HASH_BOND;
236
case kCDXBondDisplay_WedgedHashEnd:
237
case kCDXBondDisplay_WedgeBegin:
238
flags = OB_WEDGE_BOND;
242
pmol->AddBond(atoms[bondsIter->begin], atoms[bondsIter->end], bondsIter->order, flags);
244
prevBond = *bondsIter;
248
else if ((tag == kCDXObj_Graphic) || (tag == kCDXObj_Text)
249
|| (tag == kCDXObj_BracketedGroup)
250
|| (tag == kCDXObj_BracketAttachment)
251
|| (tag == kCDXObj_CrossingBond)
252
|| (tag == kCDXObj_ReactionStep)
253
|| (tag == kCDXObj_Curve)
254
|| (tag == kCDXObj_EmbeddedObject))
255
{ // Objects that can be ignored
256
readGeneric(&ifs, id);
258
else if((tag == kCDXObj_Page) || ( tag == kCDXObj_Group))
259
{ // Objects where the header can be ignored
264
snprintf(errorMsg, BUFF_SIZE, "New object in root, type %04X\n", tag);
265
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
268
else if(tag == 0) // End of object
272
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
278
READ_INT16 (ifs ,size);
282
pmol->SetTitle(getName(&ifs, size));
284
case kCDXProp_FontTable:
285
case kCDXProp_BoundingBox:
286
case kCDXProp_Window_Position:
287
case kCDXProp_Window_Size:
288
case kCDXProp_Atom_ShowQuery:
289
case kCDXProp_Atom_ShowStereo:
290
case kCDXProp_Atom_ShowAtomNumber:
291
case kCDXProp_Bond_ShowQuery:
292
case kCDXProp_Bond_ShowStereo:
293
case kCDXProp_MacPrintInfo:
294
case kCDXProp_DrawingSpaceType:
296
case kCDXProp_Height:
297
case kCDXProp_PageOverlap:
298
case kCDXProp_Magnification:
299
case kCDXProp_ChainAngle:
300
case kCDXProp_BondSpacing:
301
case kCDXProp_BondSpacingAbs:
302
case kCDXProp_BondLength:
303
case kCDXProp_BoldWidth:
304
case kCDXProp_LineWidth:
305
case kCDXProp_MarginWidth:
306
case kCDXProp_HashSpacing:
307
case kCDXProp_LabelStyle:
308
case kCDXProp_CaptionStyle:
309
case kCDXProp_CaptionJustification:
310
case kCDXProp_LabelJustification:
311
case kCDXProp_FractionalWidths:
312
case kCDXProp_LabelLineHeight:
313
case kCDXProp_CaptionLineHeight:
314
case kCDXProp_Window_IsZoomed:
315
case kCDXProp_WidthPages:
316
case kCDXProp_HeightPages:
317
case kCDXProp_HeaderPosition:
318
case kCDXProp_FooterPosition:
319
case kCDXProp_PrintTrimMarks:
320
case kCDXProp_PrintMargins:
321
case kCDXProp_ColorTable:
322
case kCDXProp_CreationProgram:
323
case kCDXProp_Group_Integral:
324
ifs.seekg(size, ios_base::cur);
326
default: // some unknown tag
327
ifs.seekg(size, ios_base::cur);
328
snprintf(errorMsg, BUFF_SIZE, "Root Tag: %04X\tSize: %04X\n", tag, size);
329
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
335
pmol->SetDimension(2);
341
OBBase* ChemDrawBinaryFormat::ReadObject(OBConversion* pConv)
343
istream& ifs = *pConv->GetInStream();
344
char buffer[BUFF_SIZE];
345
char errorMsg[BUFF_SIZE];
349
map<UINT32, int> atoms;
351
list<cdBond>::const_iterator bondsIter;
357
if((int)ifs.tellg() == 0) // Beginning of file
359
ifs.read(buffer,kCDX_HeaderStringLen);
360
if(strncmp(buffer, kCDX_HeaderString, kCDX_HeaderStringLen) == 0) // File header
362
ifs.seekg (kCDX_HeaderLength - kCDX_HeaderStringLen, ios_base::cur); // Discard rest of header.
366
cout << "Invalid file, no ChemDraw Header" << endl; // No header, error.
367
ifs.seekg(0, ios_base::end);
373
READ_INT16 (ifs, tag);
374
if(tag & kCDXTag_Object) // Object
376
READ_INT32 (ifs, id);
377
snprintf(errorMsg, BUFF_SIZE, "Object ID: %08X in root has type: %04X\n", id, tag);
378
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
380
if(tag == kCDXObj_Fragment)
382
OBMol *pmol = new OBMol();
390
pmol->SetTitle(pConv->GetTitle());
391
if(readFragment(&ifs, id, pmol, atoms, bonds) != 0)
393
obErrorLog.ThrowError(__FUNCTION__, "Error reading fragment", obWarning);
398
prevBond = cdBond(0,0,0);
399
for (bondsIter=bonds.begin(); bondsIter != bonds.end(); bondsIter++)
401
// printf("Bond between %08X (%d) and %08x (%d)\n", bondsIter->begin, atoms[bondsIter->begin], bondsIter->end, atoms[bondsIter->end]);
402
if(atoms[bondsIter->begin] == -1)
404
// printf("Bond starts at a non-atom\n");
405
if(atoms[bondsIter->end] == -1)
407
// printf("Bond between two non-atoms pushed back\n");
408
if((prevBond.begin == bondsIter->begin) && (prevBond.end == bondsIter->end))
410
obErrorLog.ThrowError(__FUNCTION__, "Can't assign all bonds!", obDebug);
413
bonds.push_back(*bondsIter);
416
atoms[bondsIter->begin] = atoms[bondsIter->end];
418
else if(atoms[bondsIter->end] == -1)
419
atoms[bondsIter->end] = atoms[bondsIter->begin];
423
switch (bondsIter->stereo)
425
case kCDXBondDisplay_WedgedHashBegin:
426
case kCDXBondDisplay_WedgeEnd:
427
flags = OB_HASH_BOND;
429
case kCDXBondDisplay_WedgedHashEnd:
430
case kCDXBondDisplay_WedgeBegin:
431
flags = OB_WEDGE_BOND;
435
pmol->AddBond(atoms[bondsIter->begin], atoms[bondsIter->end], bondsIter->order, flags);
437
prevBond = *bondsIter;
439
pmol->SetDimension(2);
443
else if (tag == kCDXObj_ReactionScheme)
445
readGeneric(&ifs, id);
446
puts("found a reaction");
447
return new OBReaction();
449
else if ((tag == kCDXObj_Graphic) || (tag == kCDXObj_Text)
450
|| (tag == kCDXObj_BracketedGroup)
451
|| (tag == kCDXObj_BracketAttachment)
452
|| (tag == kCDXObj_CrossingBond)
453
|| (tag == kCDXObj_Curve)
454
|| (tag == kCDXObj_EmbeddedObject))
455
{ // Objects that can be ignored
456
readGeneric(&ifs, id);
458
else if((tag == kCDXObj_Page) || ( tag == kCDXObj_Group))
459
{ // Objects where the header can be ignored
464
snprintf(errorMsg, BUFF_SIZE, "New object in root, type %04X\n", tag);
465
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
468
else if(tag == 0) // End of object
472
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
478
READ_INT16 (ifs ,size);
483
/*pmol->SetTitle(*/puts(getName(&ifs, size));//);
485
case kCDXProp_FontTable:
486
case kCDXProp_BoundingBox:
487
case kCDXProp_Window_Position:
488
case kCDXProp_Window_Size:
489
case kCDXProp_Atom_ShowQuery:
490
case kCDXProp_Atom_ShowStereo:
491
case kCDXProp_Atom_ShowAtomNumber:
492
case kCDXProp_Bond_ShowQuery:
493
case kCDXProp_Bond_ShowStereo:
494
case kCDXProp_MacPrintInfo:
495
case kCDXProp_DrawingSpaceType:
497
case kCDXProp_Height:
498
case kCDXProp_PageOverlap:
499
case kCDXProp_Magnification:
500
case kCDXProp_ChainAngle:
501
case kCDXProp_BondSpacing:
502
case kCDXProp_BondSpacingAbs:
503
case kCDXProp_BondLength:
504
case kCDXProp_BoldWidth:
505
case kCDXProp_LineWidth:
506
case kCDXProp_MarginWidth:
507
case kCDXProp_HashSpacing:
508
case kCDXProp_LabelStyle:
509
case kCDXProp_CaptionStyle:
510
case kCDXProp_CaptionJustification:
511
case kCDXProp_LabelJustification:
512
case kCDXProp_FractionalWidths:
513
case kCDXProp_LabelLineHeight:
514
case kCDXProp_CaptionLineHeight:
515
case kCDXProp_Window_IsZoomed:
516
case kCDXProp_WidthPages:
517
case kCDXProp_HeightPages:
518
case kCDXProp_HeaderPosition:
519
case kCDXProp_FooterPosition:
520
case kCDXProp_PrintTrimMarks:
521
case kCDXProp_PrintMargins:
522
case kCDXProp_ColorTable:
523
case kCDXProp_CreationProgram:
524
case kCDXProp_Group_Integral:
525
ifs.seekg(size, ios_base::cur);
527
default: // some unknown tag
528
ifs.seekg(size, ios_base::cur);
529
snprintf(errorMsg, BUFF_SIZE, "Root Tag: %04X\tSize: %04X\n", tag, size);
530
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
539
const char* ChemDrawBinaryFormat::getName(istream *ifs, UINT32 size)
545
// buff = new char[size];
546
READ_INT16 ((*ifs), temp);
549
buff = new char[size-1];
550
ifs->read(buff, size-2);
555
skipsize = temp * 10;
556
ifs->seekg(skipsize, ios_base::cur);
557
buff = new char[size-skipsize-1];
558
ifs->read(buff, size-skipsize-2);
559
buff[size-skipsize-2] = 0;
565
int get2DPosition(istream *ifs, UINT32 size, INT32 &x, INT32 &y)
570
READ_INT32 (*ifs, y);
571
READ_INT32 (*ifs, x);
573
// printf("2D coordinates - x: %d, y: %d\n", x, y);
577
UINT32 getBondStart(istream *ifs, UINT32 size)
584
READ_INT32 (*ifs, atomID);
585
// printf("Bond starts at atom nr: %08X\n", atomID);
589
UINT32 getBondEnd(istream *ifs, UINT32 size)
596
READ_INT32 (*ifs, atomID);
597
// printf("Bond ends at atom nr: %08X\n", atomID);
601
int getBondOrder(istream *ifs, UINT32 size)
608
READ_INT16 (*ifs, order);
609
// printf("Bond order is: %d\n", order);
613
int getBondDisplay(istream *ifs, UINT32 size)
620
READ_INT16 (*ifs, stereo);
621
// printf("Bond stereo is: %d\n", stereo);
625
int getNodeType(istream *ifs, UINT32 size)
632
READ_INT16 (*ifs, nodeType);
633
// printf("Node type is: %d\n", nodeType);
634
return (int) nodeType;
637
int getElement(istream *ifs, UINT32 size, OBAtom &atom)
644
READ_INT16 (*ifs, element);
645
atom.SetAtomicNum(element);
646
// printf("Atomic number: %d\n", element);
650
int getIsotope(istream *ifs, UINT32 size, OBAtom &atom)
657
READ_INT16 (*ifs, isotope);
658
atom.SetIsotope(isotope);
662
int getRadical(istream *ifs, UINT32 size, OBAtom &atom)
666
ifs->read((char *)&radical, size);
667
#if __BYTE_ORDER == __BIG_ENDIAN
668
radical = radical >> 24;
671
// cout << " Atomic radical " << size << " " << radical << endl;
675
atom.SetSpinMultiplicity(2);
678
atom.SetSpinMultiplicity(3);
683
break; // all singlets (current no way in OB to set diradical singlet)
689
int getCharge(istream *ifs, UINT32 size)
693
if(size == 4) // Bug in ChemDraw 8.0, see http://www.cambridgesoft.com/services/documentation/sdk/chemdraw/cdx/properties/Atom_Charge.htm
695
READ_INT32 (*ifs, charge);
700
ifs->read((char *)&charge, size);
701
#if __BYTE_ORDER == __BIG_ENDIAN
702
charge = charge >> 24;
708
// printf("Charge: %d\n",charge);
712
int getAtomHydrogens(istream *ifs, UINT32 size)
719
READ_INT16 (*ifs, hydrogens);
720
// printf("Number of explicit hydrogens: %d\n", hydrogens);
724
int readText(istream *ifs, UINT32 textId)
726
char errorMsg[BUFF_SIZE];
734
READ_INT16 (*ifs, tag);
735
if(tag & kCDXTag_Object) // Object
738
READ_INT32 (*ifs, id);
739
// printf("Object ID (in text-object %08X): %08X has type: %04X\n", textId, id, tag);
740
snprintf(errorMsg, BUFF_SIZE, "New object in text, type %04X\n", tag);
741
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
743
else if(tag == 0) // End of object
746
// printf("End of textobject %08X\n", textId);
750
READ_INT16 (*ifs, size);
751
// printf("Tag: %04X\tSize: %04X\n", tag, size);
754
default: ifs->seekg(size, ios_base::cur); break;
764
int ChemDrawBinaryFormat::readNode(istream *ifs, UINT32 nodeId,
765
OBMol *pmol, map<UINT32, int> &atoms,
766
list<cdBond> &bonds, UINT32 fragmentID)
768
char errorMsg[BUFF_SIZE];
775
// OBPairData *data = new OBPairData; // To hold ChemDraw's indexnr
778
// char strNodeId[20];
780
atom.SetAtomicNum(6);
781
// data->SetAttribute("nodeId");
782
// snprintf(strNodeId, 20, "%d", nodeId);
783
// data->SetValue(strNodeId);
784
// atom.SetData(data);
785
// if(atom.HasData("nodeId"))
787
// printf("Adding data to atom - attr: %s\tvalue: %s\n", dynamic_cast<OBPairData *> (atom.GetData("nodeId"))->GetAttribute().c_str(), dynamic_cast<OBPairData *> (atom.GetData("nodeId"))->GetValue().c_str());
790
// printf("No data added\n");
794
READ_INT16 (*ifs, tag);
795
if(tag & kCDXTag_Object) // Object
798
READ_INT32 (*ifs, id);
800
snprintf(errorMsg, BUFF_SIZE, "Object ID (in node %08X): %08X has type: %04X\n", nodeId, id, tag);
801
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
803
if(tag == kCDXObj_Fragment)
805
if(readFragment(ifs, id, pmol, atoms, bonds) != 0)
807
obErrorLog.ThrowError(__FUNCTION__, "Error reading fragment", obWarning);
810
bonds.push_back(cdBond(nodeId, id, 1));
813
else if(tag == kCDXObj_Text)
818
else if((tag == kCDXObj_ObjectTag))
819
{ // Objects to ignore
820
readGeneric(ifs, id);
823
else if(tag == kCDXObj_Group)
824
{ // Objects where we can ignore the header
828
snprintf(errorMsg, BUFF_SIZE, "New object in node, type %04X\n", tag);
829
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
832
else if(tag == 0) // End of object
835
// printf("End of Object, depth=%d\n", depth);
839
READ_INT16 (*ifs, size);
840
snprintf(errorMsg, BUFF_SIZE, "Node Tag: %04X\tSize: %04X\n", tag, size);
841
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
845
case kCDXProp_Atom_NumHydrogens:
846
getAtomHydrogens(ifs, size);
848
case kCDXProp_2DPosition:
849
get2DPosition(ifs, size, x, y);
850
atom.SetVector((double) x / 500000., (double) y / -500000.0, (double) 0.0);
852
case kCDXProp_Node_Element:
853
getElement(ifs, size, atom);
855
case kCDXProp_Atom_Charge:
856
atom.SetFormalCharge(getCharge(ifs, size));
858
case kCDXProp_Node_Type:
859
nodeType = getNodeType(ifs, size);
861
case kCDXProp_Atom_Isotope:
862
getIsotope(ifs, size, atom);
864
case kCDXProp_Atom_Radical:
865
getRadical(ifs, size, atom);
867
case kCDXProp_Atom_ElementList:
868
case kCDXProp_Atom_AbnormalValence:
870
case kCDXProp_IgnoreWarnings:
871
case kCDXProp_ChemicalWarning:
872
ifs->seekg(size, ios_base::cur);
873
break; // Maybe use? (any of the above properties)
874
case kCDXProp_MarginWidth:
875
case kCDXProp_ZOrder:
876
case kCDXProp_Atom_GenericNickname:
877
case kCDXProp_Atom_CIPStereochemistry: // maybe use for chirality
878
case kCDXProp_Atom_Geometry:
879
case kCDXProp_Atom_BondOrdering:
880
case kCDXProp_Node_LabelDisplay:
881
case kCDXProp_LabelStyle:
882
case kCDXProp_ForegroundColor:
883
case kCDXProp_BackgroundColor:
884
ifs->seekg(size, ios_base::cur);
886
default: // some unknown node tag
887
ifs->seekg(size, ios_base::cur);
888
snprintf(errorMsg, BUFF_SIZE, "Node Tag: %04X\tSize: %04X\n", tag, size);
889
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
895
// Check the data before returning...
898
case kCDXNodeType_Fragment:
901
case kCDXNodeType_ExternalConnectionPoint:
903
bonds.push_back(cdBond(nodeId,fragmentID,1));
906
atom2 = pmol->NewAtom();
907
atom2->SetVector(atom.GetVector());
908
atom2->SetFormalCharge(atom.GetFormalCharge());
909
atom2->SetAtomicNum(atom.GetAtomicNum());
910
if (atom.IsClockwise())
911
atom2->SetClockwiseStereo();
912
else if (atom.IsAntiClockwise())
913
atom2->SetAntiClockwiseStereo();
914
atoms[nodeId] = atom2->GetIdx();
917
return 0; // everything worked correctly
919
} // end while(ifs.good())
920
return -1; // file ended early
923
int ChemDrawBinaryFormat::readBond(istream *ifs, UINT32 bondId,
924
OBMol *pmol, list<cdBond> &bonds)
926
char errorMsg[BUFF_SIZE];
929
UINT32 id, bgnID, endID;
930
int depth = 1, order=1, stereo = 0;
934
READ_INT16 (*ifs, tag);
935
if(tag & kCDXTag_Object) // Object
938
READ_INT32 (*ifs, id);
939
snprintf(errorMsg, BUFF_SIZE, "Object ID (in bond %08X): %08X has type: %04X\n", bondId, id, tag);
940
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
942
if(tag == kCDXObj_Text)
949
snprintf(errorMsg, BUFF_SIZE, "New object in bond, type %04X\n", tag);
950
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
953
else if(tag == 0) // End of object
956
// printf("End of Object\n");
960
READ_INT16 (*ifs, size);
962
snprintf(errorMsg, BUFF_SIZE, "Bond Tag: %04X\tSize: %04X\n", tag, size);
963
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
967
case kCDXProp_Bond_Begin:
968
bgnID = getBondStart(ifs, size);
970
case kCDXProp_Bond_End:
971
endID = getBondEnd(ifs, size);
973
case kCDXProp_Bond_Order:
974
order = getBondOrder(ifs, size);
977
case 0xFFFF: // undefined, keep 1 for now
985
case 0x0080: // aromatic bond
988
default: // other cases are just not supported, keep 1
993
case kCDXProp_Bond_Display:
994
stereo = getBondDisplay(ifs, size);
995
break; // Stereo info
997
case kCDXProp_BondLength:
998
case kCDXProp_Bond_CIPStereochemistry:
999
case kCDXProp_Bond_BeginAttach:
1000
case kCDXProp_Bond_EndAttach:
1001
case kCDXProp_ChemicalWarning:
1002
ifs->seekg(size, ios_base::cur);
1003
break; // Maybe use? (any of the above cases)
1005
case kCDXProp_IgnoreWarnings:
1006
case kCDXProp_MarginWidth:
1007
case kCDXProp_Bond_Display2:
1008
case kCDXProp_Bond_DoublePosition:
1009
case kCDXProp_Bond_BondOrdering:
1010
case kCDXProp_BondSpacing:
1011
case kCDXProp_LineWidth:
1012
case kCDXProp_BoldWidth:
1013
case kCDXProp_HashSpacing:
1014
case kCDXProp_ZOrder:
1015
case kCDXProp_ForegroundColor:
1016
case kCDXProp_BackgroundColor:
1017
case kCDXProp_LabelStyle:
1018
ifs->seekg(size, ios_base::cur);
1021
default: // some unknown, undocumented property
1022
ifs->seekg(size, ios_base::cur);
1023
snprintf(errorMsg, BUFF_SIZE, "Bond Tag: %04X\tSize: %04X\n", tag, size);
1024
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
1030
bonds.push_back(cdBond(bgnID,endID,order,stereo));
1037
int ChemDrawBinaryFormat::readGeneric(istream *ifs, UINT32 objId)
1039
char errorMsg[BUFF_SIZE];
1047
READ_INT16 (*ifs, tag);
1048
if(tag & kCDXTag_Object) // Object
1051
READ_INT32 (*ifs, id);
1053
snprintf(errorMsg, BUFF_SIZE, "Object ID (in generic %08X): %08X has type: %04X\n", objId, id, tag);
1054
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
1056
if ((tag == kCDXObj_BracketAttachment)
1057
|| (tag == kCDXObj_CrossingBond)
1058
|| (tag == kCDXObj_BracketedGroup)
1059
|| (tag == kCDXObj_Text)
1060
|| (tag == kCDXObj_Fragment))
1061
{ // Objects to ignore (Fragment might be worth parsing)
1062
readGeneric(ifs, id);
1066
snprintf(errorMsg, BUFF_SIZE, "New object in generic, type %04X\n", tag);
1067
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
1070
else if(tag == 0) // End of object
1073
snprintf(errorMsg, BUFF_SIZE, "End of Object in generic %08X\n", objId);
1074
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
1078
READ_INT16 (*ifs, size);
1080
snprintf(errorMsg, BUFF_SIZE, "Generic Tag: %04X\tSize: %04X\n", tag, size);
1081
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
1085
ifs->seekg(size, ios_base::cur);
1089
if(depth < 1) // matched begin and end tags, so we're good
1094
return -1; // file ended while reading
1097
int ChemDrawBinaryFormat::readFragment(istream *ifs, UINT32 fragmentId,
1098
OBMol *pmol, map<UINT32, int> &atoms,
1099
list<cdBond> &bonds)
1101
char errorMsg[BUFF_SIZE];
1108
cerr<<"Reading "<<pmol<<endl;
1109
atoms[fragmentId] = -1;
1112
READ_INT16 ((*ifs), tag);
1113
if(tag & kCDXTag_Object) // Object
1116
READ_INT32 (*ifs, id);
1118
snprintf(errorMsg, BUFF_SIZE, "Object ID (in fragment %08X): %08X has type: %04X\n", fragmentId, id, tag);
1119
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
1121
if(tag == kCDXObj_Fragment)
1123
if(readFragment(ifs, id, pmol, atoms, bonds) != 0)
1125
obErrorLog.ThrowError(__FUNCTION__, "Error reading fragment", obWarning);
1129
else if(tag == kCDXObj_Node)
1131
readNode(ifs, id, pmol, atoms, bonds, fragmentId);
1134
else if(tag == kCDXObj_Bond)
1136
readBond(ifs, id, pmol, bonds);
1139
else if((tag == kCDXObj_Graphic) || (tag == kCDXObj_Text))
1140
{ // Objects that can be ignored
1141
readGeneric(ifs, id);
1144
// else if((tag == kCDXObj_Page) || ( tag == kCDXObj_Group))
1145
// { // Objects where the header can be ignored
1149
snprintf(errorMsg, BUFF_SIZE, "New object in fragment, type %04X\n", tag);
1150
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
1154
else if(tag == 0) // End of object
1160
READ_INT16 ((*ifs), size);
1163
case kCDXProp_Frag_ConnectionOrder:
1164
ifs->seekg(size, ios_base::cur);
1165
break; // Should use
1166
case kCDXProp_BoundingBox:
1167
ifs->seekg(size, ios_base::cur);
1170
ifs->seekg(size, ios_base::cur);
1171
snprintf(errorMsg, BUFF_SIZE, "Fragment Tag: %04X\tSize: %04X\n", tag, size);
1172
obErrorLog.ThrowError(__FUNCTION__, errorMsg, obDebug);
1179
cerr<<"Done reading "<<pmol<<endl;
1180
return 0; // all begin and end tags matched -- everything good
1183
return -1; // file ended before reading was finished
1186
} //namespace OpenBabel