// **********************************************************************
//
// <copyright>
//
// BBN Technologies
// 10 Moulton Street
// Cambridge, MA 02138
// (617) 873-8000
//
// Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/layer/rpf/RpfAttributes.java,v $
// $RCSfile: RpfAttributes.java,v $
// $Revision: 1.5 $
// $Date: 2008/07/21 03:41:17 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.layer.rpf;
import java.io.FileNotFoundException;
import java.io.IOException;
import com.bbn.openmap.io.BinaryBufferedFile;
import com.bbn.openmap.io.BinaryFile;
import com.bbn.openmap.io.FormatException;
import com.bbn.openmap.util.Debug;
/**
* This class knows how to read the attribute section of an RPF file.
* This section includes all the information about the image,
* including source and production information.
*/
public class RpfAttributes {
public String currencyDate;// [8];
public String productionDate; // [8];
public String significantDate; // [8];
public String chartSeriesCode; // [10];
public String mapDesignationCode; // [8];
public String oldHorDatum; // [4];
public String edition; // [7];
public String projectionCode; // [2];
public float projectionA;
public float projectionB;
public float projectionC;
public float projectionD;
public String vertDatumCode; // [4];
public String horDatumCode; // [4];
public long vertAbsAccuracy; //uint
public int vertAbsUnits; //ushort
public long horAbsAccuracy; //uint
public int horAbsUnits; // ushort
public long vertRelAccuracy; //uint
public int vertRelUnits; // ushort
public long horRelAccuracy; //uint
public int horRelUnits; // ushort
public String ellipsoidCode; // [3];
public String soundingDatumCode; // [4];
public int navSystemCode; // ushort
public String gridCode; // [2];
public float eMagChange;
public int eMagChangeUnits; // ushort
public float wMagChange;
public int wMagChangeUnits; // ushort
public float magAngle; //uint
public int magAngleUnits; // ushort
public float gridConver; //uint
public int gridConverUnits; // ushort
public double highElevation;
public int highElevationUnits; // ushort
public double highLat;
public double highLon;
public String legendFileName; // [12];
public String dataSource; // [12];
public long gsd; // uint
public int dataLevel; // ushort
public RpfAttributes() {}
/**
* Read the section in a file. The method will start reading from
* the offset provided.
*
* @param binFile the opened RPF file.
* @param attributeLocation the offset of the attribute section in
* the file.
*/
public boolean read(BinaryFile binFile, long attributeLocation) {
try {
long k;
long j = 0;
AttributeSubheader attributeSubheader = new AttributeSubheader();
// AttributeOffsetRecord attributeOffsetRecord = new
// AttributeOffsetRecord();
AttributeOffsetRecord attributeOffsetRecord;
binFile.seek(attributeLocation);
attributeSubheader.read(binFile);
if (Debug.debugging("rpfdetail")) {
System.out.println(attributeSubheader);
}
AttributeOffsetRecord[] attributeOffsetRecords = new AttributeOffsetRecord[attributeSubheader.numAttributes];
int i = attributeSubheader.numAttributes - 1;
// OK, I know what you are thinking - two sequential
// loops? It's an optimization for the binFile,
// especially if we're reading from a URL - turns this
// into a couple of sequential reads.
j = 0;
for (int attIndex = attributeSubheader.numAttributes; attIndex > 0; attIndex--) {
i = attIndex - 1;
k = attributeLocation
+ 10/* sizeof(attribute_subheader) */
+ attributeSubheader.tableOffset
+ ((attributeSubheader.numAttributes - attIndex) * 8/* sizeof(attributeOffsetRecord */);
binFile.seek(k);
attributeOffsetRecords[i] = new AttributeOffsetRecord();
attributeOffsetRecords[i].read(binFile);
if (Debug.debugging("rpfdetail")) {
Debug.output(" ##" + (++j) + " at " + k + " => attrib ID '"
+ attributeOffsetRecords[i].attributeId
+ "'|Param ID '"
+ attributeOffsetRecords[i].parameterId
+ "'|offset '" + attributeOffsetRecords[i].offset
+ "'");
}
}
for (i = attributeOffsetRecords.length - 1; i >= 0; i--) {
attributeOffsetRecord = attributeOffsetRecords[i];
binFile.seek(attributeLocation + 10
+ attributeOffsetRecord.offset);
switch (attributeOffsetRecord.attributeId) {
case 1:
currencyDate = binFile.readFixedLengthString(8);// [8];
break;
case 2:
productionDate = binFile.readFixedLengthString(8); // [8];
break;
case 3:
significantDate = binFile.readFixedLengthString(8); // [8];
break;
case 4:
if ((int) attributeOffsetRecord.parameterId == 1)
chartSeriesCode = binFile.readFixedLengthString(10); // [10];
else if ((int) attributeOffsetRecord.parameterId == 2)
mapDesignationCode = binFile.readFixedLengthString(8); // [8];
else if ((int) attributeOffsetRecord.parameterId == 3)
oldHorDatum = binFile.readFixedLengthString(4); // [4];
else if ((int) attributeOffsetRecord.parameterId == 4)
edition = binFile.readFixedLengthString(7); // [7];
break;
case 5:
if ((int) attributeOffsetRecord.parameterId == 1)
projectionCode = binFile.readFixedLengthString(2); // [2];
else if ((int) attributeOffsetRecord.parameterId == 2)
projectionA = binFile.readFloat();
else if ((int) attributeOffsetRecord.parameterId == 3)
projectionB = binFile.readFloat();
else if ((int) attributeOffsetRecord.parameterId == 4)
projectionC = binFile.readFloat();
else if ((int) attributeOffsetRecord.parameterId == 5)
projectionD = binFile.readFloat();
break;
case 6:
vertDatumCode = binFile.readFixedLengthString(4); // [4];
break;
case 7:
horDatumCode = binFile.readFixedLengthString(4); // [4];
break;
case 8:
if ((int) attributeOffsetRecord.parameterId == 1)
vertAbsAccuracy = (long) binFile.readInteger();
else if ((int) attributeOffsetRecord.parameterId == 2)
vertAbsUnits = (int) binFile.readShort(); //ushort
break;
case 9:
if ((int) attributeOffsetRecord.parameterId == 1)
horAbsAccuracy = (long) binFile.readInteger();
else if ((int) attributeOffsetRecord.parameterId == 2)
horAbsUnits = (int) binFile.readShort(); // ushort
break;
case 10:
if ((int) attributeOffsetRecord.parameterId == 1)
vertRelAccuracy = (long) binFile.readInteger();
else if ((int) attributeOffsetRecord.parameterId == 2)
vertRelUnits = (int) binFile.readShort(); // ushort
break;
case 11:
if ((int) attributeOffsetRecord.parameterId == 1)
horRelAccuracy = (long) binFile.readInteger();
else if ((int) attributeOffsetRecord.parameterId == 2)
horRelUnits = (int) binFile.readShort(); // ushort
break;
case 12:
ellipsoidCode = binFile.readFixedLengthString(3); // [3];
break;
case 13:
soundingDatumCode = binFile.readFixedLengthString(4); // [4];
break;
case 14:
navSystemCode = (int) binFile.readShort(); // ushort
break;
case 15:
gridCode = binFile.readFixedLengthString(2); // [2];
break;
case 16:
if ((int) attributeOffsetRecord.parameterId == 1)
eMagChange = binFile.readFloat();
else if ((int) attributeOffsetRecord.parameterId == 2)
eMagChangeUnits = (int) binFile.readShort(); // ushort
break;
case 17:
if ((int) attributeOffsetRecord.parameterId == 1)
wMagChange = binFile.readFloat();
else if ((int) attributeOffsetRecord.parameterId == 2)
wMagChangeUnits = (int) binFile.readShort(); // ushort
break;
case 18:
if ((int) attributeOffsetRecord.parameterId == 1)
magAngle = binFile.readFloat();
else if ((int) attributeOffsetRecord.parameterId == 2)
magAngleUnits = (int) binFile.readShort(); // ushort
break;
case 19:
if ((int) attributeOffsetRecord.parameterId == 1)
gridConver = binFile.readFloat();
else if ((int) attributeOffsetRecord.parameterId == 2)
gridConverUnits = (int) binFile.readShort(); // ushort
break;
case 20:
if ((int) attributeOffsetRecord.parameterId == 1)
highElevation = binFile.readDouble();
else if ((int) attributeOffsetRecord.parameterId == 2)
highElevationUnits = (int) binFile.readShort(); // ushort
else if ((int) attributeOffsetRecord.parameterId == 3)
highLat = binFile.readDouble();
else if ((int) attributeOffsetRecord.parameterId == 4)
highLon = binFile.readDouble();
break;
case 21:
legendFileName = binFile.readFixedLengthString(12); // [12];
break;
case 22:
if ((int) attributeOffsetRecord.parameterId == 1)
dataSource = binFile.readFixedLengthString(12); // [12];
else if ((int) attributeOffsetRecord.parameterId == 2)
gsd = (long) binFile.readInteger(); // uint
break;
case 23:
dataLevel = (int) binFile.readShort(); // ushort
break;
}
}
} catch (IOException e) {
Debug.error("RpfAttributes: read(): File IO Error!\n" + e);
return false;
} catch (FormatException f) {
Debug.error("RpfAttributes: read(): File IO Format error!\n" + f);
return false;
}
return true;
}
public String toString() {
StringBuffer s = new StringBuffer();
s.append("Attribute Section:\n");
s.append(" currency date = ").append(currencyDate).append("\n");
s.append(" production date = ").append(productionDate).append("\n");
s.append(" significant date = ").append(significantDate).append("\n");
s.append(" chart series code = ").append(chartSeriesCode).append("\n");
s.append(" map designation code = ").append(mapDesignationCode).append("\n");
s.append(" old horizontal datum = ").append(oldHorDatum).append("\n");
s.append(" edition = ").append(edition).append("\n");
s.append(" projection code = ").append(projectionCode).append("\n");
s.append(" projection A = ").append(projectionA).append("\n");
s.append(" projection B = ").append(projectionB).append("\n");
s.append(" projection C = ").append(projectionC).append("\n");
s.append(" projection D = ").append(projectionD).append("\n");
s.append(" vertical datum code = ").append(vertDatumCode).append("\n");
s.append(" horizontal datum code = ").append(horDatumCode).append("\n");
s.append(" vertical absolute accuracy = ").append(vertAbsAccuracy).append("\n");
s.append(" vertical absolute units = ").append(vertAbsUnits).append("\n");
s.append(" horizontal absolute accuracy = ").append(horAbsAccuracy).append("\n");
s.append(" horizontal absolute units = ").append(horAbsUnits).append("\n");
s.append(" vertical relative accuracy = ").append(vertRelAccuracy).append("\n");
s.append(" vertical relative units = ").append(vertRelUnits).append("\n");
s.append(" horizontal relative accuracy = ").append(horRelAccuracy).append("\n");
s.append(" horizontal relative units = ").append(horRelUnits).append("\n");
s.append(" ellipsoid code = ").append(ellipsoidCode).append("\n");
s.append(" sounding datum code = ").append(soundingDatumCode).append("\n");
s.append(" nav system code = ").append(navSystemCode).append("\n");
s.append(" grid code = ").append(gridCode).append("\n");
s.append(" east mag change = ").append(eMagChange).append("\n");
s.append(" east mag change units = ").append(eMagChangeUnits).append("\n");
s.append(" west mag change = ").append(wMagChange).append("\n");
s.append(" west mag units = ").append(wMagChangeUnits).append("\n");
s.append(" magnetic angle = ").append(magAngle).append("\n");
s.append(" magnetic angle units = ").append(magAngleUnits).append("\n");
s.append(" grid conversion = ").append(gridConver).append("\n");
s.append(" grid conversion units = ").append(gridConverUnits).append("\n");
s.append(" high elevation = ").append(highElevation).append("\n");
s.append(" high elevation units = ").append(highElevationUnits).append("\n");
s.append(" high latitude = ").append(highLat).append("\n");
s.append(" high longitude = ").append(highLon).append("\n");
s.append(" legend file name = ").append(legendFileName).append("\n");
s.append(" data source = ").append(dataSource).append("\n");
s.append(" gsd = ").append(gsd).append("\n");
s.append(" data level = ").append(dataLevel).append("\n");
return s.toString();
}
/**
* Get the attributes from within a RPF Frame file. Returns null
* if something goes wrong. You do need to make sure that the
* Debug class is initialized before calling this class. For
* OpenMap, it usually is.
*
* @param filename the file path for the RPF frame file.
* @return a RpfAttributes object.
*/
public static RpfAttributes getAttributes(String filename)
throws IOException, FileNotFoundException {
BinaryFile binFile = new BinaryBufferedFile(filename);
RpfHeader head = new RpfHeader();
head.read(binFile);
RpfAttributes att = getAttributes(binFile);
binFile.close();
head = null;
return att;
}
/**
* Get the attributes from within a RPF Frame file, after the
* header has been read. Returns null if something goes wrong. You
* do need to make sure that the Debug class is initialized before
* calling this class. For OpenMap, it usually is.
*
* @param binFile BinaryFile.
* @return a RpfAttributes object.
*/
public static RpfAttributes getAttributes(BinaryFile binFile)
throws IOException, FileNotFoundException {
RpfFileSections rfs = new RpfFileSections(binFile);
RpfAttributes att = rfs.parseAttributes(binFile);
return att;
}
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("Usage: java RpfAttributes <path to RPF frame>");
return;
}
Debug.init(System.getProperties());
try {
RpfAttributes att = RpfAttributes.getAttributes(args[0]);
Debug.output(att.toString());
} catch (FileNotFoundException e) {
Debug.error("RpfAttributes: file " + args[0] + " not found");
} catch (IOException ioe) {
Debug.error("RpfAttributes: File IO Error while handling attributes: \n"
+ ioe);
}
}
static public class AttributeSubheader {
int numAttributes; //ushort
int numArealRecords; // ushort
long tableOffset; // ulong
int offsetRecordLength; // ushort
public void read(BinaryFile binFile) {
try {
numAttributes = (int) binFile.readShort();
numArealRecords = (int) binFile.readShort();
tableOffset = (long) binFile.readInteger();
offsetRecordLength = (int) binFile.readShort();
} catch (IOException e) {
Debug.error("AttributeSubheader: read(): File IO Error!\n" + e);
} catch (FormatException f) {
Debug.error("AttributeSubheader: read(): File IO Format error!\n"
+ f);
}
}
public String toString() {
StringBuffer s = new StringBuffer();
s.append("## RPF ATTRIBUTE INFORMATION\n");
s.append("Number of Attributes - ").append(numAttributes).append("\n");
s.append("Number of Areal Records - ").append(numArealRecords).append("\n");
s.append("Size of offset - ").append(tableOffset).append("\n");
s.append("Record Length - ").append(offsetRecordLength).append("\n");
return s.toString();
}
}
static public class AttributeOffsetRecord {
int attributeId; // ushort
int parameterId; //char
int sequenceNum; //char
long offset; //ulong
public void read(BinaryFile binFile) {
try {
attributeId = (int) binFile.readShort();
parameterId = binFile.read();
sequenceNum = binFile.read();
offset = (long) binFile.readInteger();
} catch (IOException e) {
Debug.error("AttributeOffsetRecord: read(): File IO Error!\n"
+ e);
} catch (FormatException f) {
Debug.error("AttributeOffsetRecord: read(): File IO Format error!\n"
+ f);
}
}
}
}