001/* 002 * Copyright 2006 - 2013 003 * Stefan Balev <stefan.balev@graphstream-project.org> 004 * Julien Baudry <julien.baudry@graphstream-project.org> 005 * Antoine Dutot <antoine.dutot@graphstream-project.org> 006 * Yoann Pigné <yoann.pigne@graphstream-project.org> 007 * Guilhelm Savin <guilhelm.savin@graphstream-project.org> 008 * 009 * This file is part of GraphStream <http://graphstream-project.org>. 010 * 011 * GraphStream is a library whose purpose is to handle static or dynamic 012 * graph, create them from scratch, file or any source and display them. 013 * 014 * This program is free software distributed under the terms of two licenses, the 015 * CeCILL-C license that fits European law, and the GNU Lesser General Public 016 * License. You can use, modify and/ or redistribute the software under the terms 017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following 018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by 019 * the Free Software Foundation, either version 3 of the License, or (at your 020 * option) any later version. 021 * 022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 024 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 025 * 026 * You should have received a copy of the GNU Lesser General Public License 027 * along with this program. If not, see <http://www.gnu.org/licenses/>. 028 * 029 * The fact that you are presently reading this means that you have had 030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. 031 */ 032package org.graphstream.stream.file; 033 034import java.io.File; 035import java.io.FileReader; 036import java.io.IOException; 037import java.io.RandomAccessFile; 038 039import javax.xml.stream.FactoryConfigurationError; 040import javax.xml.stream.XMLEventReader; 041import javax.xml.stream.XMLInputFactory; 042import javax.xml.stream.XMLStreamException; 043import javax.xml.stream.events.XMLEvent; 044 045/** 046 * File source factory. 047 * 048 * <p> 049 * A graph reader factory allow to create readers according to a given file. It 050 * both tries to read the start of the file to infer its type (works well for 051 * file formats with a magic cookie or header), and if it fails it tries to look 052 * at the file name extension. 053 * </p> 054 */ 055public class FileSourceFactory { 056 /** 057 * Create a file input for the given file name. 058 * 059 * <p> 060 * This method first tests if the file is a regular file and is readable. If 061 * so, it opens it and reads the magic cookie to test the known file formats 062 * that can be inferred from their header. If it works, it returns a file 063 * input for the format. Else it looks at the file name extension, and 064 * returns a file input for the extension. Finally if all fail, it throws a 065 * NotFoundException. 066 * </p> 067 * 068 * <p> 069 * Notice that this method only creates the file input and does not connect 070 * it to a graph. 071 * </p> 072 * 073 * @param fileName 074 * Name of the graph file. 075 * @return A graph reader suitable for the fileName graph format. 076 * @throws IOException 077 * If the file is not readable or accessible. 078 */ 079 public static FileSource sourceFor(String fileName) throws IOException { 080 File file = new File(fileName); 081 082 if (!file.isFile()) 083 throw new IOException("not a regular file '" + fileName + "'"); 084 085 if (!file.canRead()) 086 throw new IOException("not a readable file '" + fileName + "'"); 087 088 // Try to read the beginning of the file. 089 090 RandomAccessFile in = new RandomAccessFile(fileName, "r"); 091 092 byte b[] = new byte[10]; 093 int n = in.read(b, 0, 10); 094 095 // System.err.printf( "[" ); 096 // for( int i=0; i<n; ++i ) 097 // { 098 // System.err.printf( "%c", (char)b[i] ); 099 // } 100 // System.err.printf( "]%n" ); 101 102 in.close(); 103 104 // Surely match a DGS file, as DGS files are well done and have a 105 // signature. 106 107 if (n >= 3 && b[0] == 'D' && b[1] == 'G' && b[2] == 'S') { 108 if (n >= 6 && b[3] == '0' && b[4] == '0') { 109 if (b[5] == '1' || b[5] == '2') { 110 return new FileSourceDGS1And2(); 111 } else if (b[5] == '3' || b[5] == '4') { 112 return new FileSourceDGS(); 113 } 114 } 115 } 116 117 // Maybe match a GML file as most GML files begin by the line "graph [", 118 // but not sure, you may create a GML file that starts by a comment, an 119 // empty line, with any kind of spaces, etc. 120 121 if (n >= 7 && b[0] == 'g' && b[1] == 'r' && b[2] == 'a' && b[3] == 'p' 122 && b[4] == 'h' && b[5] == ' ' && b[6] == '[') { 123 return new org.graphstream.stream.file.FileSourceGML(); 124 } 125 126 if (n >= 4 && b[0] == '(' && b[1] == 't' && b[2] == 'l' && b[3] == 'p') 127 return new FileSourceTLP(); 128 129 // The web reader. 130 131 String flc = fileName.toLowerCase(); 132 133 // If we did not found anything, we try with the filename extension ... 134 135 if (flc.endsWith(".dgs")) { 136 return new FileSourceDGS(); 137 } 138 139 if (flc.endsWith(".gml") || flc.endsWith(".dgml")) { 140 return new org.graphstream.stream.file.FileSourceGML(); 141 } 142 143 if (flc.endsWith(".net")) { 144 return new FileSourcePajek(); 145 } 146 147 if (flc.endsWith(".chaco") || flc.endsWith(".graph")) { 148 // return new GraphReaderChaco(); 149 } 150 151 if (flc.endsWith(".dot")) { 152 return new org.graphstream.stream.file.FileSourceDOT(); 153 } 154 155 if (flc.endsWith(".edge")) { 156 return new FileSourceEdge(); 157 } 158 159 if (flc.endsWith(".lgl")) { 160 return new FileSourceLGL(); 161 } 162 163 if (flc.endsWith(".ncol")) { 164 return new FileSourceNCol(); 165 } 166 167 if (flc.endsWith(".tlp")) { 168 return new FileSourceTLP(); 169 } 170 171 if (flc.endsWith(".xml")) { 172 String root = getXMLRootElement(fileName); 173 174 if (root.equalsIgnoreCase("gexf")) 175 return new FileSourceGEXF(); 176 177 return new FileSourceGraphML(); 178 } 179 180 if (flc.endsWith(".gexf")) { 181 return new FileSourceGEXF(); 182 } 183 184 return null; 185 } 186 187 public static String getXMLRootElement(String fileName) throws IOException { 188 FileReader stream = new FileReader(fileName); 189 XMLEventReader reader; 190 XMLEvent e; 191 String root; 192 193 try { 194 reader = XMLInputFactory.newInstance().createXMLEventReader(stream); 195 196 do { 197 e = reader.nextEvent(); 198 } while (!e.isStartElement() && !e.isEndDocument()); 199 200 if (e.isEndDocument()) 201 throw new IOException( 202 "document ended before catching root element"); 203 204 root = e.asStartElement().getName().getLocalPart(); 205 reader.close(); 206 stream.close(); 207 208 return root; 209 } catch (XMLStreamException ex) { 210 throw new IOException(ex); 211 } catch (FactoryConfigurationError ex) { 212 throw new IOException(ex); 213 } 214 } 215}