package uk.ac.leeds.ccg.shapefile; import java.io.*; import java.net.*; import java.util.*; import java.lang.*; import cmp.LEDataStream.*; /** * * This class represnts an ESRI Shape file.

* You construct it with a file name, and later * you can read the file's propertys, i.e. Sizes, Types, and the data itself.

* Copyright 1998 by James Macgill.

* * Version 1.0beta1.1 (added construct with inputstream) * 1.0beta1.2 (made Shape type constants public 18/Aug/98) * * This class supports the Shape file as set out in :-
* "ESRI(r) Shapefile - A Technical Description"
* 'An ESRI White Paper . May 1997'

* * This code is coverd by the GPL. * * Mail the Author */ public class Shapefile implements Serializable { // Some constants private final static boolean DEBUG=false; static final int SHAPEFILE_ID = 9994; static final int VERSION = 1000; public static final int NULL = 0; public static final int POINT = 1; public static final int ARC = 3; public static final int POLYGON = 5; public static final int MULTIPOINT = 8; public static final int ARC_M = 23; public static final int UNDEFINED = -1; //Types 2,4,6,7 and 9 were undefined at time or writeing protected ShapefileHeader mainHeader; protected Vector records; /** * Creates and initialised a shapefile from disk * @param filename The filename (including path) of the shapefile */ public Shapefile(String filename) throws java.io.IOException,ShapefileException { if(DEBUG)System.out.println("---->uk.ac.leeds.ccg.shapefile.Shapefile constructed. Will identify itself as Sf-->"); InputStream in = new FileInputStream(filename); LEDataInputStream sfile = new LEDataInputStream(in); init(sfile); } /** * Creates and initialises a shapefile from a url * @param url The url of the shapefile */ public Shapefile(URL url) throws java.io.IOException,ShapefileException { if(DEBUG)System.out.println("---->uk.ac.leeds.ccg.shapefile.Shapefile constructed. Will identify itself as Sf-->"); URLConnection uc = url.openConnection(); int len = uc.getContentLength(); if(len <=0){ throw new IOException("Sf-->File feched from URL "+url+" was of zero length or could not be found"); } byte data[]; data = new byte[len]; BufferedInputStream in = new BufferedInputStream(uc.getInputStream()); int j=0,k=0; while(kWarning, Shapefile format ("+mainHeader.getVersion()+") older that supported ("+VERSION+"), attempting to read anyway");} if(mainHeader.getVersion() > VERSION){System.err.println("Sf-->Warning, Shapefile format ("+mainHeader.getVersion()+") newer that supported ("+VERSION+"), attempting to read anyway");} records = new Vector(); ShapefileShape body; RecordHeader header; int type=mainHeader.getShapeType(); try{ for(;;){ header = new RecordHeader(file); switch(type){ case(POINT): body = new ShapePoint(file); break; case(ARC): body = new ShapeArc(file); break; case(POLYGON): body = new ShapePolygon(file); break; case(ARC_M): body = new ShapeArcM(file); break; default: throw new ShapeTypeNotSupportedException("Sf-->Shape type "+getShapeTypeDescription()+" ["+type+"] not suported"); } records.addElement(new ShapeRecord(header,body)); } } catch(EOFException e){ if(DEBUG)System.out.println("Finished reading "+records.size()+" shapes now at EOF"); } } /** * Saves a shapefile to and output stream. * @param file A LEDataInputStream that conects to the shapefile to read */ public synchronized void writeShapefile(OutputStream os) throws IOException { LEDataOutputStream file = null; try{ BufferedOutputStream out = new BufferedOutputStream(os); file = new LEDataOutputStream(out); }catch(Exception e){System.err.println(e);} //System.out.println("Writing header"); mainHeader.write(file); int pos = 50; // header length in WORDS //records; //body; //header; if(DEBUG)System.out.println("Sf-->Saving "+records.size()); for(int i=0;iReading index Record"); //ShapeRecord item = (ShapeRecord)records.elementAt(i); //if(DEBUG)System.out.println("Sf-->Offset"+file.readShort()); //len = item.header.getContentLength(); //if(DEBUG)System.out.println("Sf-->Length"+file.readShort()); //if(DEBUG)System.out.println("Sf-->"+pos+" "+len); //pos+=len; //} file.close(); } } class ShapefileHeader implements Serializable{ private final static boolean DEBUG=false; private int fileCode = -1; private int fileLength = -1; private int indexLength = -1; private int version = -1; private int shapeType = -1; private double[] bounds = new double[4]; public ShapefileHeader(LEDataInputStream file) throws IOException { file.setLittleEndianMode(false); fileCode = file.readInt(); if(DEBUG)System.out.println("Sfh->Filecode "+fileCode); if ( fileCode != Shapefile.SHAPEFILE_ID ) System.err.println("Sfh->WARNING filecode "+fileCode+" not a match for documented shapefile code "+Shapefile.SHAPEFILE_ID); //throw new IOException("File ID in header not that of a Shapefile (Found "+ fileCode+" : Expected "+Shapefile.SHAPEFILE_ID+")"); //file.skipBytes(20);//Skip unused part of header for(int i=0;i<5;i++){ int tmp = file.readInt(); if(DEBUG)System.out.println("Sfh->blank "+tmp); } fileLength = file.readInt(); if(DEBUG)System.out.println("Sfh->***************IN FileLength" +fileLength); file.setLittleEndianMode(true); version=file.readInt(); shapeType=file.readInt(); if(DEBUG)System.out.println("Sfh->IN Type" +shapeType); //read in the bounding box for(int i = 0;i<4;i++){ bounds[i]=file.readDouble(); } //skip remaining unused bytes file.setLittleEndianMode(false);//well they may not be unused forever... file.skipBytes(32); } public ShapefileHeader(int shapeType,double[] bbox,ShapefileShape[] shapes){ if(DEBUG)System.out.println("Sfh->ShapefileHeader constructed with type "+shapeType); this.shapeType = shapeType; version = Shapefile.VERSION; fileCode = Shapefile.SHAPEFILE_ID; bounds = bbox; fileLength = 0; for(int i=0;i********************OUT fileLength = "+fileLength); } public void setFileLength(int fileLength){ this.fileLength = fileLength; } public void setBounds(double[] bbox){ bounds = bbox; } public void write(LEDataOutputStream file)throws IOException { int pos = 0; file.setLittleEndianMode(false); file.writeInt(fileCode); pos+=4; for(int i=0;i<5;i++){ file.writeInt(0);//Skip unused part of header pos+=4; } file.writeInt(fileLength); pos+=4; file.setLittleEndianMode(true); file.writeInt(version); pos+=4; file.writeInt(shapeType); pos+=4; //read in the bounding box for(int i = 0;i<4;i++){ pos+=8; file.writeDouble(bounds[i]); } //skip remaining unused bytes //file.setLittleEndianMode(false);//well they may not be unused forever... for(int i=0;i<4;i++){ file.writeDouble(0.0);//Skip unused part of header pos+=8; } if(DEBUG)System.out.println("Sfh->Position "+pos); } public void writeToIndex(LEDataOutputStream file)throws IOException { int pos = 0; file.setLittleEndianMode(false); file.writeInt(fileCode); pos+=4; for(int i=0;i<5;i++){ file.writeInt(0);//Skip unused part of header pos+=4; } file.writeInt(indexLength); pos+=4; file.setLittleEndianMode(true); file.writeInt(version); pos+=4; file.writeInt(shapeType); pos+=4; //write the bounding box for(int i = 0;i<4;i++){ pos+=8; file.writeDouble(bounds[i]); } //skip remaining unused bytes //file.setLittleEndianMode(false);//well they may not be unused forever... for(int i=0;i<4;i++){ file.writeDouble(0.0);//Skip unused part of header pos+=8; } if(DEBUG)System.out.println("Sfh->Index Position "+pos); } public int getShapeType(){ return shapeType; } public int getVersion(){ return version; } public double[] getBounds(){ return bounds; } public String toString() { String res = new String("Sf-->type "+fileCode+" size "+fileLength+" version "+ version + " Shape Type "+shapeType); return res; } } class ShapeRecord implements Serializable { RecordHeader header; ShapefileShape shape; int mainindex = -1; public ShapeRecord(RecordHeader header,ShapefileShape shape){ this.header=header; this.shape=shape; } public ShapeRecord(int index,ShapefileShape shape){ this.header = new RecordHeader(index,shape); this.shape = shape; } public int getShapeType(){ return shape.getShapeType(); } public ShapefileShape getShape(){ return shape; } } class RecordHeader implements Serializable{ private int recordNumber = -1; private int contentLength = -1; public RecordHeader(LEDataInputStream file)throws IOException { file.setLittleEndianMode(false); recordNumber=file.readInt(); contentLength=file.readInt(); //System.out.println("In contentLength = "+recordNumber+" "+contentLength); } public RecordHeader(int count,ShapefileShape shape){ recordNumber = count; contentLength = shape.getLength(); //System.out.println("OUT contentLength = "+recordNumber+" "+contentLength); } public void write(LEDataOutputStream file)throws IOException { file.setLittleEndianMode(false); file.writeInt(recordNumber); file.writeInt(contentLength); } public int getRecordNumber(){ return recordNumber; } public int getContentLength(){ return contentLength; } }