/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2003-2008, Open Source Geospatial Foundation (OSGeo) * * 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; * version 2.1 of the License. * * 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. */ package org.geotools.data.vpf.io; import java.io.IOException; import java.io.RandomAccessFile; import java.util.LinkedList; import java.util.List; import org.geotools.data.vpf.ifc.DataTypesDefinition; import org.geotools.data.vpf.ifc.FileConstants; import org.geotools.data.vpf.ifc.VPFHeader; import org.geotools.data.vpf.ifc.VPFRow; import org.geotools.data.vpf.util.DataUtils; import org.geotools.geometry.DirectPosition2D; import org.geotools.geometry.GeneralDirectPosition; import org.opengis.geometry.DirectPosition; /** * VPFInputStream.java Created: Mon Feb 24 22:39:57 2003 * * @author <a href="mailto:kobit@users.sourceforge.net">Artur Hefczyc</a> * @author <a href="mailto:knuterik@onemap.org">Knut-Erik Johnsen</a>, Project OneMap * * * @source $URL$ * @version $Id$ */ public abstract class VPFInputStream implements FileConstants, DataTypesDefinition { /** * Describe variable <code>input</code> here. * */ protected RandomAccessFile input = null; /** * Describe variable <code>header</code> here. * */ protected VPFHeader header = null; /** * Describe variable <code>streamFile</code> here. * */ protected String streamFile = null; /** * Describe variable <code>rowsReadAhead</code> here. * */ private List rowsReadAhead = new LinkedList(); /** * Describe variable <code>variableIndex</code> here. * */ private VPFInputStream variableIndex = null; /** * Describe variable <code>byteOrder</code> here. * */ private char byteOrder = LITTLE_ENDIAN_ORDER; /** * Describe variable <code>accessMode</code> here. * */ private String accessMode = "r"; /** * Creates a new <code>VPFInputStream</code> instance. * * @param file a <code>String</code> value * @exception IOException if an error occurs */ public VPFInputStream(String file) throws IOException { this.streamFile = file; input = new RandomAccessFile(streamFile, accessMode); header = readHeader(); // condeb("("+streamFile+ // ") header.getRecordSize()="+header.getRecordSize()); if (header.getRecordSize() < 0) { variableIndex = new VariableIndexInputStream( getVariableIndexFileName(), getByteOrder()); } // end of if (header.getRecordSize() == -1) } /** * Creates a new <code>VPFInputStream</code> instance. * * @param file a <code>String</code> value * @param byteOrder a <code>char</code> value * @exception IOException if an error occurs */ public VPFInputStream(String file, char byteOrder) throws IOException { this.streamFile = file; this.byteOrder = byteOrder; input = new RandomAccessFile(streamFile, accessMode); header = readHeader(); } // VariableIndexInputStream constructor /** * Describe <code>readHeader</code> method here. * * @return a <code>VPFHeader</code> value * @exception IOException if an error occurs */ public abstract VPFHeader readHeader() throws IOException; /** * Describe <code>readRow</code> method here. * * @return a <code>VPFRow</code> value * @exception IOException if an error occurs */ public abstract VPFRow readRow() throws IOException; /** * Describe <code>tableSize</code> method here. * * @return an <code>int</code> value * @exception IOException if an error occurs */ public abstract int tableSize() throws IOException; /** * Describe <code>getVariableIndexFileName</code> method here. * * @return a <code>String</code> value */ public String getVariableIndexFileName() { if (streamFile.equals("fcs")) { return "fcz"; } else { return streamFile.substring(0, streamFile.length() - 1) + "x"; } } /** * Describe <code>getHeader</code> method here. * * @return a <code>VPFHeader</code> value */ public VPFHeader getHeader() { return header; } /** * Get the ByteOrder value. * * @return the ByteOrder value. */ public char getByteOrder() { return byteOrder; } /** * Set the ByteOrder value. * * @param newByteOrder The new ByteOrder value. */ public void setByteOrder(char newByteOrder) { this.byteOrder = newByteOrder; } /** * Describe <code>unread</code> method here. * * @param bytes a <code>long</code> value * @exception IOException if an error occurs */ protected void unread(long bytes) throws IOException { input.seek(input.getFilePointer() - bytes); } /** * Describe <code>seek</code> method here. * * @param pos a <code>long</code> value * @exception IOException if an error occurs */ protected void seek(long pos) throws IOException { input.seek(pos); } /** * DOCUMENT ME! * * @param pos DOCUMENT ME! * * @throws IOException DOCUMENT ME! */ public void setPosition(long pos) throws IOException { // condeb("setPosition: "+pos); // condeb("header.getRecordSize(): "+header.getRecordSize()); if (header.getRecordSize() < 0) { VariableIndexRow varRow = (VariableIndexRow) variableIndex.readRow( (int) pos); // condeb("Variable index info:\noffset="+varRow.getOffset()+ // "\nsize="+varRow.getSize()); seek(varRow.getOffset()); // condeb("seek: "+varRow.getOffset()); } else { seek(header.getLength() + ((pos - 1) * header.getRecordSize())); // condeb("seek: "+(header.getLength()+(pos-1)*header.getRecordSize())); } } /** * Method <code>readRow</code> is used to perform * * @param index an <code><code>int</code></code> value * * @return a <code><code>VPFRow</code></code> value * * @exception IOException if an error occurs */ public VPFRow readRow(int index) throws IOException { setPosition(index); return readRow(); } /** * Describe <code>readAllRows</code> method here. * * @return a <code>List</code> value * @exception IOException if an error occurs */ public List readAllRows() throws IOException { LinkedList list = new LinkedList(); try { setPosition(1); } catch (IOException exc) { // This indicates that there are no rows return list; } VPFRow row = readRow(); while (row != null) { list.add(row); row = readRow(); } return list; } /** * Method <code>readRows</code> is used to perform * * @param rows a <code><code>VPFRow[]</code></code> value * * @return an <code><code>int</code></code> value * * @exception IOException if an error occurs */ public int readRows(VPFRow[] rows) throws IOException { int counter = 0; VPFRow row = readRow(); while ((row != null) && (counter < rows.length)) { rows[counter++] = row; row = readRow(); } return counter; } /** * Describe <code>readRows</code> method here. * * @param rows a <code>VPFRow[]</code> value * @param fromIndex an <code>int</code> value * @return an <code>int</code> value * @exception IOException if an error occurs */ public int readRows(VPFRow[] rows, int fromIndex) throws IOException { setPosition(fromIndex); return readRows(rows); } /** * Describe <code>readChar</code> method here. * * @return a <code>char</code> value * @exception IOException if an error occurs */ protected char readChar() throws IOException { return (char) input.read(); } /** * Describe <code>readString</code> method here. * * @param terminators a <code>String</code> value * @return a <code>String</code> value * @exception IOException if an error occurs */ protected String readString(String terminators) throws IOException { StringBuffer text = new StringBuffer(); char ctrl = readChar(); if (terminators.indexOf(ctrl) != -1) { if (ctrl == VPF_FIELD_SEPARATOR) { unread(1); } return null; } while (terminators.indexOf(ctrl) == -1) { text.append(ctrl); ctrl = readChar(); } if (text.toString().equals(STRING_NULL_VALUE)) { return null; } else { return text.toString(); } } /** * Describe <code>readVariableSizeData</code> method here. * * @param dataType a <code>char</code> value * @return an <code>Object</code> value * @exception IOException if an error occurs */ protected Object readVariableSizeData(char dataType) throws IOException { int instances = readInteger(); return readFixedSizeData(dataType, instances); } /** * Describe <code>readFixedSizeData</code> method here. * * @param dataType a <code>char</code> value * @param instancesCount an <code>int</code> value * @return an <code>Object</code> value * @exception IOException if an error occurs */ protected Object readFixedSizeData(char dataType, int instancesCount) throws IOException { Object result = null; switch (dataType) { case DATA_TEXT: case DATA_LEVEL1_TEXT: case DATA_LEVEL2_TEXT: case DATA_LEVEL3_TEXT: byte[] dataBytes = new byte[instancesCount * DataUtils.getDataTypeSize( dataType)]; input.readFully(dataBytes); result = DataUtils.decodeData(dataBytes, dataType); break; case DATA_SHORT_FLOAT: result = new Float(readFloat()); break; case DATA_LONG_FLOAT: result = new Double(readDouble()); break; case DATA_SHORT_INTEGER: result = new Short(readShort()); break; case DATA_LONG_INTEGER: result = new Integer(readInteger()); break; case DATA_NULL_FIELD: result = "NULL"; break; case DATA_TRIPLET_ID: result = readTripletId(); break; case DATA_2_COORD_F: result = readCoord2DFloat(instancesCount); break; case DATA_2_COORD_R: result = readCoord2DDouble(instancesCount); break; case DATA_3_COORD_F: result = readCoord3DFloat(instancesCount); break; case DATA_3_COORD_R: result = readCoord3DDouble(instancesCount); break; default: break; } // end of switch (dataType) return result; } /** * Describe <code>readNumber</code> method here. * * @param cnt an <code>int</code> value * @return a <code>byte[]</code> value * @exception IOException if an error occurs */ protected byte[] readNumber(int cnt) throws IOException { byte[] dataBytes = new byte[cnt]; input.readFully(dataBytes); if (byteOrder == LITTLE_ENDIAN_ORDER) { dataBytes = DataUtils.toBigEndian(dataBytes); } return dataBytes; } /** * Describe <code>readShort</code> method here. * * @return a <code>short</code> value * @exception IOException if an error occurs */ protected short readShort() throws IOException { return DataUtils.decodeShort(readNumber(DATA_SHORT_INTEGER_LEN)); } /** * Describe <code>readInteger</code> method here. * * @return an <code>int</code> value * @exception IOException if an error occurs */ protected int readInteger() throws IOException { return DataUtils.decodeInt(readNumber(DATA_LONG_INTEGER_LEN)); } /** * Describe <code>readFloat</code> method here. * * @return a <code>float</code> value * @exception IOException if an error occurs */ protected float readFloat() throws IOException { return DataUtils.decodeFloat(readNumber(DATA_SHORT_FLOAT_LEN)); } /** * Describe <code>readDouble</code> method here. * * @return a <code>double</code> value * @exception IOException if an error occurs */ protected double readDouble() throws IOException { return DataUtils.decodeDouble(readNumber(DATA_LONG_FLOAT_LEN)); } protected TripletId readTripletId() throws IOException { byte tripletDef = (byte) input.read(); int dataSize = TripletId.calculateDataSize(tripletDef); byte[] tripletData = new byte[dataSize + 1]; tripletData[0] = tripletDef; if (dataSize > 0) { input.readFully(tripletData, 1, dataSize); } return new TripletId(tripletData); } protected DirectPosition[] readCoord3DFloat(int instancesCount) throws IOException { DirectPosition[] result = new DirectPosition[instancesCount]; for (int inx = 0; inx < instancesCount; inx++) { result[inx] = new GeneralDirectPosition(readFloat(), readFloat(), readFloat()); } return result; } protected DirectPosition[] readCoord2DFloat(int instancesCount) throws IOException { DirectPosition[] result = new DirectPosition[instancesCount]; for (int inx = 0; inx < instancesCount; inx++) { result[inx] = new DirectPosition2D(readFloat(), readFloat()); } return result; } protected DirectPosition[] readCoord2DDouble(int instancesCount) throws IOException { DirectPosition[] result = null; result = new DirectPosition[instancesCount]; for (int inx = 0; inx < instancesCount; inx++) { result[inx] = new DirectPosition2D(readDouble(), readDouble()); } return result; } protected DirectPosition[] readCoord3DDouble(int instancesCount) throws IOException { DirectPosition[] result = null; result = new DirectPosition[instancesCount]; for (int inx = 0; inx < instancesCount; inx++) { result[inx] = new GeneralDirectPosition(readDouble(), readDouble(), readDouble()); } return result; } /** * Describe <code>availableRows</code> method here. * * @return an <code>int</code> value */ public int availableRows() { return (rowsReadAhead != null) ? rowsReadAhead.size() : 0; } /** * Describe <code>close</code> method here. * * @exception IOException if an error occurs */ public void close() throws IOException { if (variableIndex != null) { variableIndex.close(); variableIndex = null; } input.close(); input = null; } /** * Describe <code>condeb</code> method here. * * @param msg a <code>String</code> value */ protected void condeb(String msg) { System.out.println(msg); } } // VPFInputStream