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