1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/**********************************************************************
Copyright (C) 2004 by Chris Morley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
***********************************************************************/
/* This is a heavily commented template for a OpenBabel format class.
Format classes are plugins: no modifications are needed to existing code
to indroduce a new format. The code just needs to be compiled and linked
with the rest of the OpenBabel code.
Alternatively, they can be built (either singly or in groups) as DLLs
or shared libraries. [**Extra build info**]
Each file may contain more than one format.
This compilable, but non-functional example is for a format which
converts a molecule to and from OpenBabel's internal format OBMol.
The conversion framework can handle other types of object, provided
they are derived from OBBase, such as OBReaction, OBText.
For XML formats, extra support for the parsing is provided, see pubchem.cpp
as an example.
*/
#include <openbabel/babelconfig.h>
#include <openbabel/obmolecformat.h>
using namespace std;
namespace OpenBabel
{
class XXXFormat : public OBMoleculeFormat
// Derive directly from OBFormat for objects which are not molecules.
{
public:
//Register this format type ID in the constructor
XXXFormat()
{
/* XXX is the file extension and is case insensitive. A MIME type can be
added as an optional third parameter.
Multiple file extensions can be registered by adding extra statements.*/
OBConversion::RegisterFormat("XXX",this);
/* If there are any format specific options they should be registered here
so that the commandline interface works properly.
The first parameter is the option name. If it is a single letter it can be
concatinated with other single letter options. For output options it can be
multicharcter and is then written as --optionname on the command line.
The third parameter is the number of parameters the option takes. Currently
this is either 1 or 0 and if it is 0 can be omitted for output options.
The parameter is always text and needs to be parsed to extract a number.
Options can apply when writing - 4th parameter is OBConversion::OUTOPTIONS
or can be omitted as shown. A single letter output option is preceded
by -x on the command line.
Or options can apply to the input format - the 4th parameter is
OBConversion::INOPTIONS. They are then preceded by -a on the command line.
Each option letter may be reused in other formats, but within the same group,
INOPTIONS or OUTOPTIONS, must take the same number of parameters (0 or 1).
There will be an error message when OpenBabel runs if there are conflicts
between formats. A list of formats currently used (which may not be
comprehensive) is in docs/options.html.
*/
OBConversion::RegisterOptionParam("f", this, 1);
OBConversion::RegisterOptionParam("n", this);
OBConversion::RegisterOptionParam("s", this, 0, OBConversion::INOPTIONS);
}
/* The first line of the description should be a brief identifier, <40 chars, because
it is used in dropdown lists, etc. in some user interfaces. The rest is optional.
Describe any format specific options here. This text is parsed to provide
checkboxes, etc for the GUI (for details click the control menu),
so please try to keep to a similar form.
Write options are the most common, and the "Write" is optional.
The option f takes a text parameter, so that it is essential that the option
is registered in the constructor of the class.
Finish the options with a blank line as shown, if there are more than one
group of options, or if there are further comments after them.
*/
virtual const char* Description() //required
{
return
"XXX format\n"
"Some comments here, on as many lines as necessay\n"
"Write Options e.g. -xf3 \n"
" f# Number of (fictional) levels\n"
" n Omit (virtual) title\n\n"
"Read Options e.g. -as\n"
" s Consider single bonds only\n"
;
};
//Optional URL where the file format is specified
virtual const char* SpecificationURL(){ return ""; }
//Optional
virtual const char* GetMIMEType()
{ return "chemical/x-xxx"; };
/* Flags() can return be any of the following combined by |
or be omitted if none apply
NOTREADABLE READONEONLY NOTWRITABLE WRITEONEONLY DEFAULTFORMAT
READBINARY WRITEBINARY READXML ZEROATOMSOK*/
virtual unsigned int Flags()
{
return READONEONLY;
};
/* This optional function is for formats which can contain more than one
molecule. It is used to quickly position the input stream after the nth
molecule without have to convert and discard all the n molecules.
See obconversion.cpp for details and mdlformat.cpp for an example.*/
virtual int SkipObjects(int n, OBConversion* pConv)
{
return 0;
};
////////////////////////////////////////////////////
/// Declarations for the "API" interface functions. Definitions are below
virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv);
virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
private:
/* Add declarations for any local function or member variables used.
Generally only a single instance of a format class is used. Keep this in
mind if you employ member variables. */
};
////////////////////////////////////////////////////
//Make an instance of the format class
XXXFormat theXXXFormat;
/////////////////////////////////////////////////////////////////
bool XXXFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
{
OBMol* pmol = pOb->CastAndClear<OBMol>();
if(pmol==nullptr)
return false;
istream& ifs = *pConv->GetInStream();
pmol->BeginModify();
/** Parse the input stream and use the OpenBabel API to populate the OBMol **/
// To use an input option
if(pConv->IsOption("s",OBConversion::INOPTIONS))
{
//Code for when -as is specified
}
/* If the molecule has other than 3D coordinates for its atoms, it
is necessary to set the dimension to 0, or 2 */
int dim;
pmol->SetDimension(dim);
pmol->EndModify();
/* For multi-molecule formats, leave the input stream at the start of the
next molecule, ready for this routine to be called again.
/* Return true if ok. Returning false means discard the OBMol and stop
converting, unless the -e option is set. With a multi-molecule inputstream
this will skip the current molecule and continue with the next, if SkipObjects()
has been defined. If it has not, and continuation after errors is still required,
it is necessary to leave the input stream at the beginning of next object when
returning false;*/
return true;
}
////////////////////////////////////////////////////////////////
bool XXXFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
{
OBMol* pmol = dynamic_cast<OBMol*>(pOb);
if(pmol==nullptr)
return false;
ostream& ofs = *pConv->GetOutStream();
/** Write the representation of the OBMol molecule to the output stream **/
//To use an output option
if(!pConv->IsOption("n")) //OBConversion::OUTOPTIONS is the default
ofs << "Title = " << pmol->GetTitle() << endl;
//or if the option has a parameter
int levels=0;
const char* p = pConv->IsOption("f");
if(p) //p==nullptr if f option absent
levels = atoi(p);
// To find out whether this is the first molecule to be output...
if(pConv->GetOutputIndex()==1)
ofs << "The contents of this file were derived from " << pConv->GetInFilename() << endl;
// ... or the last
if(!pConv->IsLast())
ofs << "$$$$" << endl;
return true; //or false to stop converting
}
} //namespace OpenBabel