/**
* H2GIS is a library that brings spatial support to the H2 Database Engine
* <http://www.h2database.com>. H2GIS is developed by CNRS
* <http://www.cnrs.fr/>.
*
* This code is part of the H2GIS project. H2GIS 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;
* version 3.0 of the License.
*
* H2GIS 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 <http://www.gnu.org/licenses/>.
*
*
* For more information, please consult: <http://www.h2gis.org/>
* or contact directly: info_at_h2gis.org
*/
package org.h2gis.functions.io.shp.internal;
import org.h2gis.functions.io.utility.ReadBufferManager;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
/**
* IndexFile parser for .shx files.<br>
* For now, the creation of index files is done in the ShapefileWriter. But this
* can be used to access the index.<br>
* For details on the index file, see <br>
* <a href="http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf"><b>"ESRI(r)
* Shapefile - A Technical Description"</b><br> * <i>'An ESRI White Paper .
* May 1997'</i></a>
*
* @author Ian Schneider
* @see "http://svn.geotools.org/geotools/tags/2.3.1/plugin/shapefile/src/org/geotools/data/shapefile/shp/IndexFile.java"
*/
public class IndexFile {
private FileChannel channel;
private ReadBufferManager buf = null;
private int lastIndex = -1;
private int recOffset;
private int recLen;
private ShapefileHeader header = null;
/**
* Load the index file from the given channel.
*
* @param channel
* The channel to read from.
* @throws java.io.IOException
* If an error occurs.
*/
public IndexFile(FileChannel channel)
throws IOException {
readHeader(channel);
this.channel = channel;
this.buf = new ReadBufferManager(channel, 8 * 128);
}
/**
* Get the header of this index file.
*
* @return The header of the index file.
*/
public ShapefileHeader getHeader() {
return header;
}
private void readHeader(ReadableByteChannel channel) throws IOException {
ByteBuffer buffer = ByteBuffer.allocateDirect(100);
while (buffer.remaining() > 0) {
channel.read(buffer);
}
buffer.flip();
header = new ShapefileHeader();
header.read(buffer);
}
private void readRecord(int index) throws IOException {
int pos = 100 + index * 8;
this.recOffset = buf.getInt(pos);
this.recLen = buf.getInt(pos + 4);
this.lastIndex = index;
}
public void close() throws IOException {
if (channel != null && channel.isOpen()) {
channel.close();
}
this.buf = null;
}
/**
* Get the number of records in this index.
*
* @return The number of records.
*/
public int getRecordCount() {
return (header.getFileLength() * 2 - 100) / 8;
}
/**
* Get the offset of the record (in 16-bit words).
*
* @param index
* The index, from 0 to getRecordCount - 1
* @return The offset in 16-bit words.
* @throws java.io.IOException
*/
public int getOffset(int index) throws IOException {
int ret = -1;
if (this.lastIndex != index) {
this.readRecord(index);
}
ret = this.recOffset;
return 2 * ret;
}
/**
* Get the offset of the record (in real bytes, not 16-bit words).
*
* @param index
* The index, from 0 to getRecordCount - 1
* @return The offset in bytes.
* @throws java.io.IOException
*/
public int getOffsetInBytes(int index) throws IOException {
return this.getOffset(index) * 2;
}
/**
* Get the content length of the given record in bytes, not 16 bit words.
*
* @param index
* The index, from 0 to getRecordCount - 1
* @return The lengh in bytes of the record.
* @throws java.io.IOException
*/
public int getContentLength(int index) throws IOException {
int ret = -1;
if (this.lastIndex != index) {
this.readRecord(index);
}
ret = this.recLen;
return ret;
}
}