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;
}
}