Source code: joelib/io/types/JCAMP.java
1 ///////////////////////////////////////////////////////////////////////////////
2 // Filename: $RCSfile: JCAMP.java,v $
3 // Purpose: Reader/Writer for Undefined files.
4 // Language: Java
5 // Compiler: JDK 1.4
6 // Authors: Joerg K. Wegner
7 // Version: $Revision: 1.11 $
8 // $Date: 2003/08/22 15:56:18 $
9 // $Author: wegner $
10 //
11 // Copyright (c) Dept. Computer Architecture, University of Tuebingen, Germany
12 //
13 // This program is free software; you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation version 2 of the License.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 ///////////////////////////////////////////////////////////////////////////////
22 package joelib.io.types;
23
24 import cformat.PrintfStream;
25
26 import joelib.io.MoleculeFileType;
27
28 import joelib.jcamp.JCAMPData;
29 import joelib.jcamp.JCAMPDataBlock;
30
31 import joelib.molecule.JOEMol;
32
33 /*
34 * ==========================================================================*
35 * IMPORTS
36 * ==========================================================================
37 */
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.io.InputStreamReader;
41 import java.io.LineNumberReader;
42 import java.io.OutputStream;
43
44 import org.apache.log4j.Category;
45
46
47 /*
48 * ==========================================================================*
49 * CLASS DECLARATION
50 * ==========================================================================
51 */
52
53 /**
54 * A class to interpret JCAMP-DX data (JCAMP-CS is not implemented yet). The
55 * supported data types are XYPAIRS, XYDATA=(X++(Y..Y)), PEAK TABLE and LINK.
56 * <br>
57 * If you want load a file with multiple blocks or inner blocks you must use
58 * <code>JCampMultipleFile</code>.<br>
59 * This class can only load separated single blocks with one TITLE and END
60 * label !<br>
61 * <br>
62 *
63 * <ul>
64 * <li> ... The International Union of Pure and Applied Chemistry (IUPAC)
65 * took over responsibility from the Joint Commitee on Atomic and Molecular
66 * Physical Data (JCAMP) in 1995 ...<br>
67 * <a href="http://jcamp.isas-dortmund.de/">I U P A C<br>
68 * Committee on Printed and Electronic Publications <br>
69 * Working Party on Spectroscopic Data Standards (JCAMP-DX)</a> <br>
70 * <br>
71 *
72 * <li> <a href="http://wwwchem.uwimona.edu.jm:1104/software/jcampdx.html">
73 * The Department of Chemistry at the University of the West Indies</a>
74 * </ul>
75 *
76 * @author wegnerj
77 * @license GPL
78 * @cvsversion $Revision: 1.11 $, $Date: 2003/08/22 15:56:18 $
79 * @cite dl93
80 * @cite dw88
81 * @cite ghhjs91
82 * @cite lhdl94
83 * @cite dhl90
84 * @see joelib.jcamp.JCAMPParser
85 */
86 public class JCAMP implements MoleculeFileType
87 {
88 //~ Static fields/initializers /////////////////////////////////////////////
89
90 /*
91 * -------------------------------------------------------------------------*
92 * private static member variables
93 * -------------------------------------------------------------------------
94 */
95
96 /**
97 * Obtain a suitable logger.
98 */
99 private static Category logger = Category.getInstance(
100 "joelib.io.types.JCAMP");
101 private final static String description = new String(
102 "Joint Commitee on Atomic and Molecular Physical Data (JCAMP)");
103 private final static String[] extensions = new String[]{"jdx", "dx", "cs"};
104
105 //~ Instance fields ////////////////////////////////////////////////////////
106
107 // data type is chemical structure
108 private final String JCAMP_CHEMICAL_STRUCTURE = "JCAMP-CS";
109
110 // data type is spectra
111 private final String JCAMP_SPECTRA = "JCAMP-DX";
112
113 // marks start of data
114 private final String JCAMP_START = "TITLE";
115
116 // marks end of data
117 private final String JCAMP_STOP = "END";
118
119 // ... is link block
120 private final String LINK_TYPE = "LINK";
121
122 // data type ...
123 private final String LINK_TYPE_DATA = "DATA TYPE";
124 private JCAMPData jcamp;
125
126 // private String textBlock;
127 // private StringTokenizer textTokenizer = null;
128
129 /*
130 * -------------------------------------------------------------------------*
131 * private member variables
132 * -------------------------------------------------------------------------
133 */
134 private LineNumberReader lnr;
135 private PrintfStream ps;
136 private int jcampCount;
137
138 //~ Constructors ///////////////////////////////////////////////////////////
139
140 /*
141 * -------------------------------------------------------------------------*
142 * constructor
143 * -------------------------------------------------------------------------
144 */
145
146 /**
147 * Constructor for the Undefined object
148 */
149 public JCAMP()
150 {
151 }
152
153 //~ Methods ////////////////////////////////////////////////////////////////
154
155 public String getJCAMPData()
156 {
157 return (String) jcamp.getDXEntry(0).getBlockData();
158 }
159
160 /**
161 * Description of the Method
162 *
163 *@exception IOException Description of the Exception
164 */
165 public void closeReader() throws IOException
166 {
167 }
168
169 /**
170 * Description of the Method
171 *
172 *@exception IOException Description of the Exception
173 */
174 public void closeWriter() throws IOException
175 {
176 }
177
178 /**
179 * Description of the Method
180 *
181 *@param is Description of the Parameter
182 *@exception IOException Description of the Exception
183 */
184 public void initReader(InputStream is) throws IOException
185 {
186 lnr = new LineNumberReader(new InputStreamReader(is));
187 jcampCount = 0;
188 }
189
190 /**
191 * Description of the Method
192 *
193 *@param os Description of the Parameter
194 *@exception IOException Description of the Exception
195 */
196 public void initWriter(OutputStream os) throws IOException
197 {
198 ps = new PrintfStream(os);
199 }
200
201 /*
202 * -------------------------------------------------------------------------*
203 * public static methods
204 * -------------------------------------------------------------------------
205 */
206
207 /**
208 * Description of the Method
209 *
210 *@return Description of the Return Value
211 */
212 public String inputDescription()
213 {
214 return description;
215 }
216
217 /**
218 * Description of the Method
219 *
220 *@return Description of the Return Value
221 */
222 public String[] inputFileExtensions()
223 {
224 return extensions;
225 }
226
227 /**
228 * Description of the Method
229 *
230 *@return Description of the Return Value
231 */
232 public String outputDescription()
233 {
234 return description;
235 }
236
237 /**
238 * Description of the Method
239 *
240 *@return Description of the Return Value
241 */
242 public String[] outputFileExtensions()
243 {
244 return extensions;
245 }
246
247 /**
248 * Reads an molecule entry as (unparsed) <tt>String</tt> representation.
249 *
250 * @return <tt>null</tt> if the reader contains no more
251 * relevant data. Otherwise the <tt>String</tt> representation of the
252 * whole molecule entry is returned.
253 * @exception IOException typical IOException
254 */
255 public String read() throws IOException
256 {
257 logger.error(
258 "Reading JCAMP data as String representation is not implemented yet !!!");
259
260 return null;
261 }
262
263 /**
264 * Description of the Method
265 *
266 *@param mol Description of the Parameter
267 *@return Description of the Return Value
268 *@exception IOException Description of the Exception
269 */
270 public boolean read(JOEMol mol) throws IOException
271 {
272 return read(mol, null);
273 }
274
275 /**
276 * Description of the Method
277 *
278 *@param mol Description of the Parameter
279 *@param title Description of the Parameter
280 *@return Description of the Return Value
281 *@exception IOException Description of the Exception
282 */
283 public boolean read(JOEMol mol, String title) throws IOException
284 {
285 // start parsing
286 jcamp = new JCAMPData();
287
288 JCAMPDataBlock dataBlock = null;
289
290 do
291 {
292 jcampCount++;
293 dataBlock = resolveJCAMPBlocks(0, null, jcampCount);
294 addDataBlock(dataBlock);
295 }
296 while (dataBlock != null);
297
298 return (false);
299 }
300
301 /**
302 * Description of the Method
303 *
304 *@return Description of the Return Value
305 */
306 public boolean readable()
307 {
308 return true;
309 }
310
311 public boolean skipReaderEntry() throws IOException
312 {
313 return skipReaderEntry(1);
314 }
315
316 /**
317 * Description of the Method
318 *
319 *@return Description of the Return Value
320 *@exception IOException Description of the Exception
321 */
322 public boolean skipReaderEntry(int actualDepth) throws IOException
323 {
324 String line;
325 int depth = 0;
326
327 while ((line = lnr.readLine()) != null)
328 {
329 if ((line.length() > 0) && (line.charAt(0) == '#') &&
330 (line.indexOf(JCAMP_STOP) != -1))
331 {
332 depth++;
333 }
334
335 if (depth == actualDepth)
336 {
337 break;
338 }
339 }
340
341 return true;
342 }
343
344 /**
345 * Description of the Method
346 *
347 *@param mol Description of the Parameter
348 *@return Description of the Return Value
349 *@exception IOException Description of the Exception
350 */
351 public boolean write(JOEMol mol) throws IOException
352 {
353 return write(mol, null);
354 }
355
356 /**
357 * Description of the Method
358 *
359 *@param mol Description of the Parameter
360 *@param title Description of the Parameter
361 *@return Description of the Return Value
362 *@exception IOException Description of the Exception
363 */
364 public boolean write(JOEMol mol, String title) throws IOException
365 {
366 return (false);
367 }
368
369 /**
370 * Description of the Method
371 *
372 *@return Description of the Return Value
373 */
374 public boolean writeable()
375 {
376 return false;
377 }
378
379 /**
380 * Adds a JCAMP block.
381 *
382 *@param block The feature to be added to the DataBlock attribute
383 *@return Description of the Return Value
384 */
385 private boolean addDataBlock(JCAMPDataBlock block)
386 {
387 if (block != null)
388 {
389 if (block.getBlockType() == JCAMPDataBlock.CS_TYPE)
390 {
391 jcamp.addCSEntry(block);
392
393 // System.out.println("CS_ID: " + block.getBlockID());
394 // System.out.println("CS:\n" + block.getBlockData());
395 }
396 else if (block.getBlockType() == JCAMPDataBlock.DX_TYPE)
397 {
398 jcamp.addDXEntry(block);
399
400 // System.out.println("DX_ID: " + block.getBlockID());
401 // System.out.println("DX:\n" + block.getBlockData());
402 }
403 else if (block.getBlockType() == JCAMPDataBlock.LINK_TYPE)
404 {
405 jcamp.addLinkEntry(block);
406
407 // System.out.println("LINK_ID: " + block.getBlockID());
408 // System.out.println("LINK:\n" + block.getBlockData());
409 }
410 }
411
412 return true;
413 }
414
415 /*
416 * -------------------------------------------------------------------------*
417 * private methods
418 * -------------------------------------------------------------------------
419 */
420
421 /**
422 * Gets the single JCAMP data blocks.
423 *
424 *@param _depth Description of the Parameter
425 *@param previousLine Description of the Parameter
426 *@param blockID Description of the Parameter
427 *@return Description of the Return Value
428 *@exception IOException Description of the Exception
429 */
430 private JCAMPDataBlock resolveJCAMPBlocks(int _depth, String previousLine,
431 int blockID) throws IOException
432 {
433 // now parse the whole file contents
434 String label = null;
435 String data = null;
436 StringBuffer tempBuffer = new StringBuffer(20000);
437 int depth = _depth;
438 JCAMPDataBlock dataBlock = new JCAMPDataBlock();
439
440 boolean firstLabelTreated = false;
441 String nextLine = null;
442 boolean goOn = true;
443
444 // while (textTokenizer.hasMoreTokens())
445 while (goOn)
446 {
447 if (firstLabelTreated || (previousLine == null))
448 {
449 // get next line
450 nextLine = lnr.readLine();
451
452 if (nextLine == null)
453 {
454 goOn = false;
455
456 continue;
457 }
458
459 // nextLine = textTokenizer.nextToken();
460 // jump over empty lines
461 if (nextLine.equals(""))
462 {
463 continue;
464 }
465
466 nextLine = JCAMPDataBlock.removeCommentsInLine(nextLine);
467 }
468 else
469 {
470 nextLine = previousLine;
471 }
472
473 //is label line or data line?
474 if ((nextLine.charAt(0) == '#') && (nextLine.charAt(1) == '#'))
475 {
476 // try to determine the data type of one TITLE ... END data set
477 label = JCAMPDataBlock.getLabelInLine(nextLine);
478
479 if (label != null)
480 {
481 // is LINK type ?
482 if (label.equals(LINK_TYPE_DATA))
483 {
484 data = JCAMPDataBlock.getDataInLine(nextLine);
485
486 if ((data != null) && data.equals(LINK_TYPE))
487 {
488 // overwrite DX or CS type already defined WITHOUT WARNING
489 dataBlock.setBlockType(JCAMPDataBlock.LINK_TYPE);
490 }
491 else
492 {
493 // check for IR, MS, UV - spectra type ... if you want ...
494 // and store it as 'DATA TYPE'
495 }
496 }
497
498 // is CS type ?
499 else if (label.equals(JCAMP_CHEMICAL_STRUCTURE))
500 {
501 // set only if undefined
502 if (dataBlock.getBlockType() == JCAMPDataBlock.UNDEFINED_TYPE)
503 {
504 dataBlock.setBlockType(JCAMPDataBlock.CS_TYPE);
505 }
506 }
507
508 // is DX type ?
509 else if (label.equals(JCAMP_SPECTRA))
510 {
511 // set only if undefined
512 if (dataBlock.getBlockType() == JCAMPDataBlock.UNDEFINED_TYPE)
513 {
514 dataBlock.setBlockType(JCAMPDataBlock.DX_TYPE);
515 }
516 }
517
518 // nested data block ?
519 else if (label.equals(JCAMP_START))
520 {
521 depth++;
522
523 if (depth == 2)
524 {
525 JCAMPDataBlock nestedDataBlock;
526 nestedDataBlock = resolveJCAMPBlocks(depth,
527 nextLine, blockID);
528 addDataBlock(nestedDataBlock);
529 depth--;
530
531 continue;
532 }
533 else if (depth > 3)
534 {
535 return null;
536 }
537 }
538
539 // finsh data block
540 else if (label.equals(JCAMP_STOP))
541 {
542 // add uncommented data to buffer
543 tempBuffer.append(nextLine + "\n");
544 dataBlock.setBlockData(tempBuffer.toString(), depth);
545 tempBuffer.delete(0, tempBuffer.length());
546 dataBlock.setBlockID(blockID);
547
548 return dataBlock;
549 }
550 }
551 }
552
553 // add uncommented data to buffer
554 tempBuffer.append(nextLine + "\n");
555
556 firstLabelTreated = true;
557 }
558
559 return null;
560 }
561 }
562 ///////////////////////////////////////////////////////////////////////////////
563 // END OF FILE.
564 ///////////////////////////////////////////////////////////////////////////////