/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2006 by:
EXSE, Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53177 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.io.shpapi;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import org.deegree.model.spatialschema.ByteUtils;
/**
* Class representing an ESRI Shape File.
* <p>
* Uses class ShapeUtils modified from the original package
* com.bbn.openmap.layer.shape <br>
* Copyright (C) 1998 BBN Corporation 10 Moulton St. Cambridge, MA 02138 <br>
*
*
* @version 31.07.2000
* @author Andreas Poth
*/
public class IndexFile {
private static final String _shx = ".shx";
private RandomAccessFile raf;
/**
* The length of an index record. (8 byte)
*/
private static final int INDEX_RECORD_LENGTH = 8;
/**
* array which holds the content of .shx-file:
*/
private IndexRecord[] indexArray = null;
/**
* IndexFileHeader is equal to ShapeFileHeader
*/
private FileHeader fh;
/**
* minimum bounding rectangle of the shape-file
*/
private SHPEnvelope fileMBR;
/**
* number of Records in .shp, .shx., .dbf has to be identical
*/
private int RecordNum;
/**
* file position offset
*/
private long offset;
/**
* length of the indexfile
*/
private int filelength = 0;
/**
* Construct a IndexFile from a file name.
*/
public IndexFile(String url) throws IOException {
/*
* creates raf
*/
raf = new RandomAccessFile(url + _shx, "r");
/*
* construct Header as ShapeFileHeader
*/
fh = new FileHeader(raf);
fileMBR = fh.getFileMBR();
/*
* construct indexArray
*/
setIndexArray();
}
/**
* Construct a IndexFile from a file name.
*/
public IndexFile(String url, String rwflag) throws IOException {
// delete file if it exists
File file = new File(url + _shx);
if (rwflag.indexOf('w') > -1 && file.exists())
{
file.delete();
FileOutputStream os = new FileOutputStream(file, false);
os.close();
}
file = null;
raf = new RandomAccessFile(url + _shx, rwflag);
// if the 2nd arg is true an empty header will be
// written by FileHeader
fh = new FileHeader(raf, rwflag.indexOf('w') > -1);
fileMBR = fh.getFileMBR();
offset = raf.length();
if (offset < 100)
{
offset = ShapeConst.SHAPE_FILE_HEADER_LENGTH;
}
setIndexArray();
}
public void close() {
try {
raf.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* method: writeHeader(int filelength, byte shptype,SHPEnvelope mbr) <BR>
* Writes a header into the index file. <BR>
*/
public void writeHeader(int shptype, SHPEnvelope mbr) throws IOException {
byte[] header = new byte[ShapeConst.SHAPE_FILE_HEADER_LENGTH];
ByteUtils.writeBEInt(header, 0, ShapeConst.SHAPE_FILE_CODE);
ByteUtils.writeBEInt(header, 24, filelength);
ByteUtils.writeLEInt(header, 28, ShapeConst.SHAPE_FILE_VERSION);
ByteUtils.writeLEInt(header, 32, shptype);
ShapeUtils.writeBox(header, 36, mbr);
raf.seek(0);
raf.write(header, 0, ShapeConst.SHAPE_FILE_HEADER_LENGTH);
}
/**
* method: getFileMBR() <BR>
* returns the minimum bounding rectangle of the shape-file <BR>
*/
public SHPEnvelope getFileMBR() {
return fileMBR;
}
/**
* method: setIndexArray() <BR>
* local constructor for local field indexArray <BR>
*/
private void setIndexArray() throws IOException {
byte[] recBuf = new byte[INDEX_RECORD_LENGTH];
long rafPos = ShapeConst.SHAPE_FILE_HEADER_LENGTH;
int iaIndex = 0;
ArrayList indexArrayVector = new ArrayList(10000);
raf.seek(rafPos);
// loop over index records, until EOF
while (raf.read(recBuf, 0, INDEX_RECORD_LENGTH) != -1) {
IndexRecord ir = new IndexRecord(recBuf);
// set ArrayVector item as index record
indexArrayVector.add(ir);
// array index adjustment
++iaIndex;
// filepos adjustment
rafPos = rafPos + INDEX_RECORD_LENGTH;
raf.seek(rafPos);
} // end of while
// iaIndex holds Record Number
RecordNum = iaIndex;
// copy vector into indexArray
indexArray = (IndexRecord[]) indexArrayVector.toArray(new IndexRecord[RecordNum]);
}
/**
* method: getIndexArray() <BR>
* clones local field indexArray <BR>
*/
public IndexRecord[] getIndexArray() {
return indexArray;
}
/**
* method: getRecordNum() <BR>
* function to get number of Records <BR>
*/
public int getRecordNum() {
return RecordNum;
}
/**
* methode: getRecordOffset (int RecNo) <BR>
* function to get Record offset by Record number <BR>
*/
public int getRecordOffset(int RecNo) {
if (RecNo >= 0) {
return indexArray[RecNo].offset;
}
return -1;
}
/**
* method: getRecordLength (int RecNo) <BR>
* function to get Record Length by Record number <BR>
*/
public int getRecordLength(int RecNo) {
if (RecNo >= 0) {
return indexArray[RecNo].length;
}
return -1;
}
/**
* method: getIndexRecord (int RecNo) <BR>
* function to get Index Record by Record number <BR>
*/
public IndexRecord getIndexRecord(int RecNo) {
IndexRecord ir = new IndexRecord();
if (RecNo >= 0) {
return ir = indexArray[RecNo];
}
return ir;
}
/**
* appends an index record to the indexfile
*/
public void appendRecord(IndexRecord record, SHPEnvelope mbr)
throws IOException
{
offset = raf.length();
raf.seek(offset);
raf.write(record.writeIndexRecord());
offset = offset + INDEX_RECORD_LENGTH;
//actualize mbr
if (fileMBR.west > mbr.west) {
fileMBR.west = mbr.west;
}
if (fileMBR.east < mbr.east) {
fileMBR.east = mbr.east;
}
if (fileMBR.south > mbr.south) {
fileMBR.south = mbr.south;
}
if (fileMBR.north < mbr.north) {
fileMBR.north = mbr.north;
}
raf.seek(36);
raf.write(fileMBR.writeLESHPEnvelope());
//actualize file length
filelength = (int) offset / 2;
}
}
/*
* Last changes:
* $Log: IndexFile.java,v $
* Revision 1.12 2006/07/12 14:46:14 poth
* comment footer added
*
* Revision 1.11 2006/05/29 16:16:15 poth
* code simplification
*
* Revision 1.10 2006/04/06 20:25:23 poth
* *** empty log message ***
*
* Revision 1.9 2006/04/04 20:39:41 poth
* *** empty log message ***
*
* Revision 1.8 2006/03/30 21:20:24 poth
* *** empty log message ***
*
* Revision 1.7 2006/01/16 20:36:39 poth
* *** empty log message ***
*
* Revision 1.6 2005/09/23 14:50:17 deshmukh
* @deshmukh
*
* 23.09.05: Added ShapeDatastore.java
* ShapeDatastoreTest.java
* Changes made to datastores.properties
* added the type SHAPE
*
* Revision 1.5 2005/02/14 11:19:43 friebe
* fix javadoc errors
*
* 17.12.1999 ap: import clauses added <BR>
* 31.07.2000 ap: method writeIndexFileHeader(SHPEnvelope mbr) added <BR>
* 31.07.2000 ap: method appendRecord(IndexRecord record, SHPEnvelope mbr) added
*//* ********************************************************************
Changes to this class. What the people have been up to:
$Log: IndexFile.java,v $
Revision 1.12 2006/07/12 14:46:14 poth
comment footer added
********************************************************************** */