7#include "ImportPdsTable.h"
15#include <QScopedPointer>
18#include "EndianSwapper.h"
24#include "TableField.h"
25#include "TableRecord.h"
74 const QString &pdsTableFile,
75 const QString &pdsTableName) {
77 load(pdsLabFile, pdsTableFile, pdsTableName);
133 const QString &pdsTableFile,
134 const QString &pdsTableName) {
138 loadLabel(pdsLabFile, tempTblFile, pdsTableName);
139 if (!pdsTableFile.isEmpty()) tempTblFile = pdsTableFile;
145 int tableStartRecord =
toInt(tableFile.baseName());
146 tempTblFile = pdsLabFile;
152 if (!tableFile.fileExists()) {
154 FileName tableFileLowercase(tableFile.path() +
"/"
155 + tableFile.name().toLower());
156 if (!tableFileLowercase.fileExists()) {
157 IString msg =
"Unable to import PDS table. Neither of the following "
158 "possible table files were found: ["
159 + tableFile.expanded() +
"] or ["
160 + tableFileLowercase.expanded() +
"]";
163 tableFile = tableFileLowercase.expanded();
164 tempTblFile = tableFile.expanded();
212 const bool &formatted)
const {
213 if ((
int) index >=
columns() - 1) {
214 QString msg =
"Unable to import the binary PDS table [" +
m_tableName
215 +
"] into Isis. The requested column index ["
216 +
toString((
int) index) +
"] exceeds the last column index ["
244 for (
int i = 0 ; i <
columns() ; i++) {
247 colnames.push_back(
name);
296 const QString &dataType) {
301 return (column != 0);
321 Table table(isisTableName, record);
326 QString msg =
"Unable to import the PDS table [" +
m_tableName
351 const QString &isisTableName) {
352 return (
importTable(colnames.split(
","), isisTableName));
374 const QString &isisTableName) {
376 for (
int i = 0 ; i < colnames.size() ; i++) {
379 QString msg =
"Unable to import the PDS table [" +
m_tableName
380 +
"] into Isis. The requested column name ["
381 + colnames[i] +
"] does not "
385 ctypes.push_back(*descr);
390 Table table(isisTableName, record);
439 QString &pdsTableFile,
440 const QString &tblname) {
444 QString tableName = ( tblname.isEmpty() ) ?
m_tableName : tblname;
446 QString msg =
"The PDS file " + pdsLabFile +
447 " does not have the required TABLE object, ["
448 + tableName +
"]. The PDS label file is probably invalid";
454 if (tabObj.hasKeyword(
"RECORD_BYTES")) {
459 else if (tabObj.hasKeyword(
"ROW_BYTES") && tabObj.hasKeyword(
"ROW_SUFFIX_BYTES")) {
461 (int) tabObj.findKeyword(
"ROW_SUFFIX_BYTES");
469 QString trueTableName;
472 trueTableName = tableName;
474 + label[
"^" + tableName][0];
476 else if (tabObj.objects() == 1) {
478 tableDetails = &tabObj.object(0);
480 + tabObj[
"^" + trueTableName][0];
482 m_trows = (int) tableDetails->findKeyword(
"ROWS");
483 int ncols = (int) tableDetails->findKeyword(
"COLUMNS");
484 m_pdsTableType = QString(tableDetails->findKeyword(
"INTERCHANGE_FORMAT"));
486 QString msg =
"Unable to import the PDS table [" + tableName
487 +
"] from the PDS file ["
488 + pdsTableFile +
"] into Isis. "
490 +
"] is not supported. Valid values are ASCII or BINARY.";
493 m_rowBytes = tableDetails->findKeyword(
"ROW_BYTES");
498 while (colobj != tableDetails->endObject()) {
499 if (colobj->isNamed(
"COLUMN")) {
509 msg <<
"Number of columns in the COLUMNS label keyword (" << ncols
510 <<
") does not match number of COLUMN objects found ("
512 cout << msg.str() << endl;
538 QString tempTblFile(pdsTableFile);
543 while (tfile.GetLine(tline,
false)) {
574 cd.
m_name = colobj[
"NAME"][0];
581 cd.m_dataType = colobj[
"DATA_TYPE"][0].toUpper();
584 cd.m_startByte = ((int) colobj[
"START_BYTE"]) - 1;
585 cd.m_numBytes = (int) colobj[
"BYTES"];
588 cd.m_itemBytes = cd.m_numBytes;
589 if ( colobj.hasKeyword(
"ITEM_BYTES") ) {
590 cd.m_itemBytes = (int) colobj[
"ITEM_BYTES"];
594 if ( colobj.hasKeyword(
"ITEMS") ) {
595 cd.m_items = (int) colobj[
"ITEMS"];
617 if ( (nth >=
columns()) || ( nth < 0) ) {
618 QString mess =
"Index (" + QString::number(nth) +
619 ") into Columns invalid (max: " + QString::number(
columns()) +
")";
644 ColumnTypes::iterator col =
m_coldesc.begin();
647 if (c.toUpper() == cName.toUpper()) {
return (&(*col)); }
670 ColumnTypes::const_iterator col =
m_coldesc.begin();
673 if (c.toUpper() == cName.toUpper()) {
return (&(*col)); }
692 const QString &delimiter)
const {
693 return (tline.mid(cdesc.m_startByte, cdesc.m_numBytes));
714 const QString &delimiter)
const {
718 if ( 1 == cdesc.m_items)
return (
QStringList(value) );
722 if ( 0 == cdesc.m_itemBytes ) {
723 if ( delimiter.isEmpty() )
return (
QStringList(value));
725 return ( value.split(delimiter, Qt::SkipEmptyParts) );
731 for (
int i = 0 ; i < cdesc.m_items ; i++) {
732 fields.push_back(value.mid(pos, cdesc.m_itemBytes));
733 pos += cdesc.m_itemBytes + 1;
760 QString cname = QString(colname).replace(QRegExp(
"[(),]"),
" ").simplified();
762 bool uppercase =
true;
764 for (
int i = 0 ; i < cname.size() ; i++) {
766 oString.push_back(cname[i].toUpper());
769 else if ( (cname[i] ==
' ') || (cname[i] ==
'_') ) {
773 oString.push_back(cname[i].toLower());
799 return ttype.split(
"_").last();
821 QString dtype = cdesc.m_dataType;
824 if ( dtype ==
"INTEGER" ) {
827 else if ( ((dtype ==
"DOUBLE")
829 || (dtype ==
"FLOAT")) ) {
858 for (
int i = 0 ; i < ctypes.size() ; i++) {
885 int ith = cdesc.m_colnum;
888 if (tfield.isInteger()) {
889 data.
Trim(
" \t\r\n");
892 else if (tfield.isDouble()) {
893 data.
Trim(
" \t\r\n");
897 QString str(tfield.size(),
' ');
898 str.insert(0, data.
Trim(
" \t\r\n").
ToQt());
903 QString msg =
"Conversion failure of column " + cdesc.m_name;
928 for (
int i = 0 ; i < ctypes.size() ; i++) {
929 extract(cols, ctypes[i], record[i]);
954 for (
int i = 0 ; i <
m_rows.size() ; i++) {
959 QString msg =
"Failed to convert data in row [" +
toString((
int) i) +
"]";
967 ifstream pdsFileStream(tempTblFile.toLatin1().data(), ifstream::binary);
969 if (!pdsFileStream) {
970 IString msg =
"Unable to open file containing PDS table ["
971 + tempTblFile +
"].";
976 QScopedPointer<char, QScopedPointerArrayDeleter<char> > rowBuffer(
new char[
m_recordBytes]);
981 for (
int rowIndex = 0; rowIndex <
m_trows; rowIndex++) {
1033 for (
int colIndex = 0; colIndex <
columns(); colIndex++) {
1034 QString columnName =
m_coldesc[colIndex].m_name;
1035 for (
int fieldIndex = 0 ; fieldIndex < record.
Fields() ; fieldIndex++) {
1036 QString fieldName = record[fieldIndex].name();
1037 if (fieldName == columnName) {
1038 int startByte =
m_coldesc[colIndex].m_startByte;
1039 int numBytes =
m_coldesc[colIndex].m_numBytes;
1041 if (record[fieldIndex].isInteger()) {
1043 memmove(&columnValue, &rowBuffer[startByte], numBytes);
1045 int fieldValue = endianSwap.Int(&columnValue);
1046 record[fieldIndex] = fieldValue;
1049 else if (record[fieldIndex].isDouble()) {
1052 memmove(&columnValue, &rowBuffer[startByte], numBytes);
1053 double fieldValue = endianSwap.Double(&columnValue);
1054 record[fieldIndex] = fieldValue;
1057 else if (record[fieldIndex].isReal()) {
1060 memmove(&columnValue, &rowBuffer[startByte], numBytes);
1061 float fieldValue = endianSwap.Float(&columnValue);
1062 record[fieldIndex] = fieldValue;
1065 else if (record[fieldIndex].isText()) {
1066 QString fieldValue(numBytes,
'\0');
1067 for (
int byte = 0;
byte < numBytes;
byte++) {
1068 fieldValue[byte] = rowBuffer[startByte + byte];
1070 record[fieldIndex] = fieldValue;
1103 QString dataType = cdesc.m_dataType;
1105 QString
name = cdesc.m_name;
1106 if (dataType ==
"MSB_INTEGER" || dataType ==
"INTEGER"
1107 || dataType ==
"SUN_INTEGER" || dataType ==
"MAC_INTEGER") {
1108 if (cdesc.m_numBytes != 4) {
1109 QString msg =
"Only 4 byte integer values are supported in Isis. "
1110 "PDS Column [" + cdesc.m_name
1111 +
"] has an integer DATA_TYPE with [BYTES = "
1112 +
toString(cdesc.m_numBytes) +
"].";
1118 else if (dataType ==
"LSB_INTEGER" || dataType ==
"VAX_INTEGER"
1119 || dataType ==
"PC_INTEGER" ) {
1120 if (cdesc.m_numBytes != 4) {
1121 QString msg =
"Only 4 byte integer values are supported in Isis. "
1122 "PDS Column [" + cdesc.m_name
1123 +
"] has an integer DATA_TYPE with [BYTES = "
1124 +
toString(cdesc.m_numBytes) +
"].";
1130 else if (dataType ==
"FLOAT"
1131 || dataType ==
"REAL"
1132 || dataType ==
"SUN_REAL"
1133 || dataType ==
"MAC_REAL"
1134 || dataType ==
"IEEE_REAL" ) {
1136 if (cdesc.m_numBytes == 8) {
1139 else if (cdesc.m_numBytes == 4) {
1143 IString msg =
"Only 4 byte or 8 byte real values are supported in Isis. "
1144 "PDS Column [" + cdesc.m_name
1145 +
"] has a real DATA_TYPE with [BYTES = "
1146 +
toString(cdesc.m_numBytes) +
"].";
1150 else if (dataType ==
"PC_REAL") {
1152 if (cdesc.m_numBytes == 8) {
1155 else if (cdesc.m_numBytes == 4) {
1159 QString msg =
"Only 4 byte or 8 byte real values are supported in Isis. "
1160 "PDS Column [" + cdesc.m_name
1161 +
"] has a real DATA_TYPE with [BYTES = "
1162 +
toString(cdesc.m_numBytes) +
"].";
1166 else if (dataType.contains(
"CHARACTER")
1167 || dataType.contains(
"ASCII")
1168 || dataType ==
"DATE" || dataType ==
"TIME" ) {
1173 IString msg =
"PDS Column [" + cdesc.m_name
1174 +
"] has an unsupported DATA_TYPE ["
1193 QString msg =
"Unable to import the binary PDS table [" +
m_tableName
1194 +
"]. The column DATA_TYPE values indicate differing byte "
1214 for (
int i = 0 ; i <
columns() ; i++) {
File name manipulation and expansion.
QString path() const
Returns the path of the file name.
@ Unknown
A type of error that cannot be classified as any of the other error types.
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
@ Programmer
This error is for when a programmer made an API call that was illegal.
Adds specific functionality to C++ strings.
int ToInteger() const
Returns the object string as an integer.
IString Trim(const std::string &chars)
Removes characters from the beginning and end of the IString.
QString ToQt() const
Retuns the object string as a QString.
double ToDouble() const
Returns the floating point value the IString represents.
void init()
Initialize object variables.
ColumnDescr * findColumn(const QString &colName)
Searches internal column descriptors for a named column.
virtual bool processRow(const int &row, const QString &rowdata)
Process a freshly read PDS table line of data.
void setName(const QString &name="TABLE")
Set the name of the PDS table object.
QString name() const
Return the name of the PDS table.
QString getFormattedName(const QString &colname) const
Converts a column name to a camel-case after it has been cleansed.
int rows() const
Returns the number of rows in the table.
void loadLabel(const QString &labfile, QString &tblfile, const QString &tblname="")
Loads the contents of a PDS table label description.
const ColumnDescr & getColumnDescriptor(const int &nth) const
Retrieve a column description by index.
int m_pdsTableStart
The start byte of the PDS table data.
Table importTable(const QString &isisTableName)
Populate a Table object with the PDS table and return it.
QString m_pdsTableFile
The name of the file containing the table data.
QString getColumnValue(const QString &tline, const ColumnDescr &cdesc, const QString &delimiter="") const
Extracts a column from a QString based upon a description.
void load(const QString &pdsLabFile, const QString &pdsTabFile="", const QString &pdsTableName="TABLE")
Loads a PDS table label and (optional) data file.
void setPdsByteOrder(QString byteOrder)
Sets the byte order for BINARY PDS table files.
int m_rowBytes
The number of bytes for one PDS table row.
QString m_pdsTableType
The INTERCHANGE_FORMAT value for the table.
TableField & extract(const Columns &columns, const ColumnDescr &cdesc, TableField &field) const
Extract a TableField from a PDS column in the text row.
TableRecord makeRecord(const ColumnTypes &ctypes)
Creates a TableRecord for columns.
TableRecord extractBinary(char *rowBuffer, TableRecord &record) const
This method is used to set the field values for the given record.
int m_trows
Number rows in table according to label.
QString m_tableName
The name of the PDS table object.
int m_recordBytes
The number of bytes for one Isis table record.
ColumnTypes m_coldesc
Column descriptions.
void loadTable(const QString &tabfile)
Loads the contents of a PDS table data file.
TableField makeFieldFromBinaryTable(const ColumnDescr &cdesc)
Creates an empty TableField with the appropriate type from a binary PDS table column description.
QString m_byteOrder
The byte order of the PDS table file, if binary.
virtual ~ImportPdsTable()
Destructs the ImportPdsTable object.
bool setType(const QString &colName, const QString &dataType)
Change the datatype for a column.
QString getGenericType(const QString &ttype) const
Determine generic data type of a column.
ColumnDescr getColumnDescription(PvlObject &colobj, int nth) const
Extract a column description from a COLUMN object.
ImportPdsTable()
Default constructor.
QString getType(const QString &colName) const
Get the type associated with the specified column.
bool hasColumn(const QString &colName) const
This method determines whether the PDS table has a column with the given name.
void fillTable(Table &table, const ColumnTypes &columns, TableRecord &record) const
Fill the ISIS Table object with PDS table data.
QStringList getColumnNames(const bool &formatted=true) const
Return the names of all the columns.
QString getColumnName(const unsigned int &index=0, const bool &formatted=true) const
Returns the name of the specifed column.
TableField makeField(const ColumnDescr &cdesc)
Creates a TableField for the column type.
int columns() const
Returns the number of columns in the table.
QStringList getColumnFields(const QString &tline, const ColumnDescr &cdesc, const QString &delimiter="") const
Extracts column fields from a QString based upon a description.
QString name() const
Returns the container name.
Container for cube-like labels.
Contains Pvl Groups and Pvl Objects.
bool hasKeyword(const QString &kname, FindOptions opts) const
See if a keyword is in the current PvlObject, or deeper inside other PvlObjects and Pvlgroups within ...
bool hasObject(const QString &name) const
Returns a boolean value based on whether the object exists in the current PvlObject or not.
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
QList< PvlObject >::iterator PvlObjectIterator
The counter for objects.
PvlObject & object(const int index)
Return the object at the specified index.
PvlKeyword & findKeyword(const QString &kname, FindOptions opts)
Finds a keyword in the current PvlObject, or deeper inside other PvlObjects and Pvlgroups within this...
Class for storing an Isis::Table's field information.
@ Integer
The values in the field are 4 byte integers.
@ Real
The values in the field are 4 byte reals or floats.
@ Text
The values in the field are text strings with 1 byte per character.
@ Double
The values in the field are 8 byte doubles.
Class for storing Table blobs information.
int Fields() const
Returns the number of fields that are currently in the record.
Provides access to sequential ASCII stream I/O.
This is free and unencumbered software released into the public domain.
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
int toInt(const QString &string)
Global function to convert from a string to an integer.
Namespace for the standard library.
QString m_dataType
PDS table DATA_TYPE of column.
QString m_name
Name of column.