pir format ambiguity and todo regarding 'format override' parameter
[jalview.git] / src / jalview / io / IdentifyFile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
3  * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
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  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.io;
20
21 import java.io.*;
22 import java.net.*;
23
24 /**
25  * DOCUMENT ME!
26  * 
27  * @author $author$
28  * @version $Revision$
29  */
30 public class IdentifyFile
31 {
32   /**
33    * Identify a datasource's file content.
34    * 
35    * @note Do not use this method for stream sources - create a FileParse object
36    *       instead.
37    * 
38    * @param file
39    *                DOCUMENT ME!
40    * @param protocol
41    *                DOCUMENT ME!
42    * @return ID String
43    */
44   public String Identify(String file, String protocol)
45   {
46     String emessage = "UNIDENTIFIED FILE PARSING ERROR";
47     FileParse parser = null;
48     try
49     {
50       parser = new FileParse(file, protocol);
51       if (parser.isValid())
52       {
53         return Identify(parser);
54       }
55     } catch (Exception e)
56     {
57       System.err.println("Error whilst identifying");
58       e.printStackTrace(System.err);
59       emessage = e.getMessage();
60     }
61     if (parser != null)
62       return parser.errormessage;
63     return emessage;
64   }
65
66   public String Identify(FileParse source)
67   {
68     return Identify(source, true); // preserves original behaviour prior to
69                                     // version 2.3
70   }
71
72   /**
73    * Identify contents of source, closing it or resetting source to start
74    * afterwards.
75    * 
76    * @param source
77    * @param closeSource
78    * @return filetype string
79    */
80   public String Identify(FileParse source, boolean closeSource)
81   {
82     String reply = "PFAM";
83     String data;
84     int length = 0;
85     boolean lineswereskipped = false;
86     boolean isBinary = false; // true if length is non-zero and non-printable
87                               // characters are encountered
88     try
89     {
90       if (!closeSource)
91       {
92         source.mark();
93       }
94       while ((data = source.nextLine()) != null)
95       {
96         length += data.length();
97         if (!lineswereskipped)
98         {
99           for (int i = 0; !isBinary && i < data.length(); i++)
100           {
101             char c = data.charAt(i);
102             isBinary = (c < 32 && c != '\t' && c != '\n' && c != '\r'
103                     && c != 5 && c != 27); // nominal binary character filter
104                                             // excluding CR, LF, tab,DEL and ^E
105                                             // for certain blast ids
106           }
107         }
108         if (isBinary)
109         {
110           // jar files are special - since they contain all sorts of random
111           // characters.
112           if (source.inFile != null)
113           {
114             String fileStr = source.inFile.getName();
115             // possibly a Jalview archive.
116             if (fileStr.lastIndexOf(".jar") > -1
117                     || fileStr.lastIndexOf(".zip") > -1)
118             {
119               reply = "Jalview";
120             }
121           }
122           if (!lineswereskipped && data.startsWith("PK"))
123           {
124             reply = "Jalview"; // archive.
125             break;
126           }
127         }
128         data = data.toUpperCase();
129
130         if ((data.indexOf("# STOCKHOLM") > -1))
131         {
132           reply = "STH";
133
134           break;
135         }
136
137         if ((data.length() < 1) || (data.indexOf("#") == 0))
138         {
139           lineswereskipped = true;
140           continue;
141         }
142
143         if (data.indexOf("PILEUP") > -1)
144         {
145           reply = "PileUp";
146
147           break;
148         }
149
150         if ((data.indexOf("//") == 0)
151                 || ((data.indexOf("!!") > -1) && (data.indexOf("!!") < data
152                         .indexOf("_MULTIPLE_ALIGNMENT "))))
153         {
154           reply = "MSF";
155
156           break;
157         }
158         else if (data.indexOf("CLUSTAL") > -1)
159         {
160           reply = "CLUSTAL";
161
162           break;
163         }
164         else if (data.indexOf(">") > -1)
165         {
166           // FASTA, PIR file or BLC file
167           boolean checkPIR = false;
168           if ((data.indexOf(">P1;") > -1) || (data.indexOf(">DL;") > -1))
169           {
170             // watch for PIR file attributes
171             checkPIR = true;
172             reply = "PIR";
173           }
174           // could also be BLC file, read next line to confirm
175           data = source.nextLine();
176
177           if (data.indexOf(">") > -1)
178           {
179             reply = "BLC";
180           }
181           else
182           {
183             // Is this a single line BLC file?
184             source.nextLine();
185             String data2 = source.nextLine();
186             if (data2 != null && data.indexOf("*") > -1)
187             {
188               if (data.indexOf("*") == data2.indexOf("*"))
189               {
190               reply = "BLC";
191               }
192               // otherwise can still possibly be a PIR file
193             }
194             else
195             {
196               reply = "FASTA";
197               // TODO : AMSA File is indicated if there is annotation in the
198               // FASTA file - but FASTA will automatically generate this at the
199               // mo.
200               break;
201             }
202           }
203           // TODO final check for PIR content. require >P1;title\n<blah>\nterminated sequence to occur at least once. 
204           // the PIR/fasta ambiguity may be the use case that is needed to have a 'Parse as type XXX' parameter for the applet/application.
205           break;
206         }
207         else if (data.indexOf("HEADER") == 0 || data.indexOf("ATOM") == 0)
208         {
209           reply = "PDB";
210           break;
211         }
212         else if (!lineswereskipped && data.charAt(0) != '*'
213                 && data.charAt(0) != ' '
214                 && data.indexOf(":") < data.indexOf(",")) // &&
215                                                           // data.indexOf(",")<data.indexOf(",",
216                                                           // data.indexOf(",")))
217         {
218           // file looks like a concise JNet file
219           reply = "JnetFile";
220           break;
221         }
222
223         lineswereskipped = true; // this means there was some junk before any
224                                   // key file signature
225       }
226       if (closeSource)
227       {
228         source.close();
229       }
230       else
231       {
232         source.reset(); // so the file can be parsed from the beginning again.
233       }
234     } catch (Exception ex)
235     {
236       System.err.println("File Identification failed!\n" + ex);
237       return source.errormessage;
238     }
239     if (length == 0)
240     {
241       System.err
242               .println("File Identification failed! - Empty file was read.");
243       return "EMPTY DATA FILE";
244     }
245     return reply;
246   }
247
248   public static void main(String[] args)
249   {
250     for (int i = 0; args != null && i < args.length; i++)
251     {
252       IdentifyFile ider = new IdentifyFile();
253       String type = ider.Identify(args[i], AppletFormatAdapter.FILE);
254       System.out.println("Type of " + args[i] + " is " + type);
255     }
256     if (args == null || args.length == 0)
257     {
258       System.err.println("Usage: <Filename> [<Filename> ...]");
259     }
260   }
261 }