File failed to load: https://isis.astrogeology.usgs.gov/6.0.0/Object/assets/jax/output/NativeMML/config.js
Isis 3 Programmer Reference
ExportPdsTable.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "ExportPdsTable.h"
8 
9 #include <cmath>
10 #include <iostream>
11 
12 #include "Endian.h"
13 #include "EndianSwapper.h"
14 #include "IString.h"
15 #include "IException.h"
16 #include "Pvl.h"
17 #include "PvlKeyword.h"
18 #include "PvlObject.h"
19 #include "Table.h"
20 #include "TableField.h"
21 #include "TableRecord.h"
22 
23 
24 using namespace std;
25 
26 namespace Isis {
38  ExportPdsTable::ExportPdsTable(Table isisTable) {
39  // initialize member variables
40  m_outputRecordBytes = 0;
41  m_pdsByteOrder = "LSB";
42  m_isisTable = new Table(isisTable);
43  m_numRows = isisTable.Records(); //one row in pdsTable per record in isisTable
44  m_rowBytes = m_isisTable->RecordSize(); //this should be the same value
45  //for all pds rows and isis records
46  }
47 
51  ExportPdsTable::~ExportPdsTable() {
52  // delete pointers and set to null
53  delete m_isisTable;
54  m_isisTable = NULL;
55  }
56 
67  PvlObject ExportPdsTable::exportTable(char *pdsTableBuffer,
68  int outputFileRecordBytes,
69  QString pdsTableByteOrder) {
70  // Currently, we will not allow our table rows to be wrapped. So we must
71  // check that the rowbytes of the output table are no larger than the total
72  // record bytes allowed in the output pds file
73  m_outputRecordBytes = outputFileRecordBytes;
74  if (m_rowBytes > m_outputRecordBytes) {
75  throw IException(IException::Unknown,
76  "Unable to export Isis::Table object to PDS. The "
77  "Isis::Table record size [" + toString(m_rowBytes)
78  + "] is larger than the record bytes allowed in the "
79  "PDS file [" + toString(m_outputRecordBytes) + "].",
80  _FILEINFO_);
81  }
82 
83  // update variables
84  m_pdsByteOrder = pdsTableByteOrder.toUpper();
85 
86  if (m_pdsByteOrder != "MSB" && m_pdsByteOrder != "LSB") {
87  QString msg = "Unable to export the Isis Table [" + m_isisTable->Name()
88  + "] to a PDS table using the requested byte order ["
89  + m_pdsByteOrder + "]. Valid values are MSB or LSB.";
90  throw IException(IException::Unknown, msg, _FILEINFO_);
91  }
92 
93  // create an array of nulls to pad
94  // from the end of each row to the end of the record
95  int numRowNulls = outputFileRecordBytes - m_rowBytes;
96  char endRowPadding[numRowNulls];
97  for (int i = 0; i < numRowNulls; i++) {
98  endRowPadding[i] = '\0';
99  }
100 
101  // loop through records in the input Isis::Table object
102  // fill rowBuffer with packed record values, then fill with padding
103  EndianSwapper *endianSwap = new EndianSwapper(m_pdsByteOrder);
104 
105  int buffsize = 0;
106  for(int recIndex = 0; recIndex < m_isisTable->Records(); recIndex++) {
107  TableRecord record = (*m_isisTable)[recIndex];
108  char rowBuffer[record.RecordSize()];
109  Pack(record, rowBuffer, endianSwap);
110  int i = recIndex*m_outputRecordBytes;
111  memmove(pdsTableBuffer + i, &rowBuffer, record.RecordSize());
112  memmove(pdsTableBuffer + i + m_rowBytes, &endRowPadding, numRowNulls);
113  buffsize+=record.RecordSize();
114  buffsize+=numRowNulls;
115  }
116  return fillMetaData();
117  }
118 
125  PvlObject ExportPdsTable::fillMetaData() {
126  QString pdsTableName = formatPdsTableName();
127  PvlObject pdsTableLabelInfo(pdsTableName);
128  // Data Object Descriptions
129  // NOTE: this class is currently only exporting BINARY format PDS tables.
130  // implementation may be added later to export ASCII PDS tables.
131  pdsTableLabelInfo.addKeyword(PvlKeyword("INTERCHANGE_FORMAT", "BINARY"));
132  pdsTableLabelInfo.addKeyword(PvlKeyword("ROWS", toString(m_isisTable->Records())));
133  pdsTableLabelInfo.addKeyword(PvlKeyword("COLUMNS", toString(m_isisTable->RecordFields())));
134  pdsTableLabelInfo.addKeyword(PvlKeyword("ROW_BYTES", toString(m_rowBytes)));
135  pdsTableLabelInfo.addKeyword(PvlKeyword("ROW_SUFFIX_BYTES", toString(m_outputRecordBytes - m_rowBytes)));
136  int startByte = 1; // PDS begins indexing at 1
137  for(int fieldIndex = 0; fieldIndex < m_isisTable->RecordFields(); fieldIndex++) {
138  int columnBytes = 0;
139  TableField field = (*m_isisTable)[0][fieldIndex];
140  PvlObject columnObj("COLUMN");
141  columnObj.addKeyword(PvlKeyword("COLUMN_NUMBER", toString(fieldIndex + 1)));
142  columnObj.addKeyword(PvlKeyword("NAME", field.name()));
143 
144 
145  if (field.type() == TableField::Text) {
146  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "CHARACTER"));
147  QString val = field;
148  for(int i = 0; i < field.size(); i++) {
149  columnBytes++;
150  }
151  }
152  else if (field.type() == TableField::Integer) {
153  if (m_pdsByteOrder == "MSB") {
154  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "MSB_INTEGER"));
155  columnBytes = sizeof(int);
156  }
157  else { // if (m_pdsByteOrder == "LSB") {
158  // no need to check this. already validated in exportPdsTable()
159  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "LSB_INTEGER"));
160  columnBytes = sizeof(int);
161  }
162  }
163  else if (field.type() == TableField::Double) {
164  if (m_pdsByteOrder == "MSB") {
165  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "IEEE_REAL"));
166  columnBytes = sizeof(double);
167  }
168  else { // if (m_pdsByteOrder == "LSB") {
169  // no need to check this. already validated in exportPdsTable()
170  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "PC_REAL"));
171  columnBytes = sizeof(double);
172  }
173  }
174  else if (field.type() == TableField::Real) {
175  if (m_pdsByteOrder == "MSB") {
176  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "IEEE_REAL"));
177  columnBytes = sizeof(float);
178  }
179  else { // if (m_pdsByteOrder == "LSB") {
180  // no need to check this. already validated in exportPdsTable()
181  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "PC_REAL"));
182  columnBytes = sizeof(float);
183  }
184  }
185  else { // This error is not covered in the unitTest since currently, there
186  // are no other valid values for TableField types. It is meant to
187  // catch other values if they are added to Table Field.
188  QString msg = "Unable to export Isis::Table object to PDS. Invalid "
189  "field type found for [" + field.name() + "].";
190  throw IException(IException::Programmer, msg, _FILEINFO_);
191  }
192  columnObj.addKeyword(PvlKeyword("START_BYTE", toString(startByte)));
193  startByte += columnBytes;
194  columnObj.addKeyword(PvlKeyword("BYTES", toString(columnBytes)));
195  pdsTableLabelInfo.addObject(columnObj);
196  }
197  return pdsTableLabelInfo;
198  }
199 
205  QString ExportPdsTable::formatPdsTableName() {
206  return ExportPdsTable::formatPdsTableName(m_isisTable->Name());
207  }
208 
219  QString ExportPdsTable::formatPdsTableName(QString isisTableName) {
220  QString tableName = isisTableName.simplified();
221  QString pdsTableName;
222  pdsTableName.push_back(tableName[0]);
223  for (int i = 1 ; i < tableName.size() ; i++) {
224  if (tableName[i] >= 65 && tableName[i] <= 90) {
225  pdsTableName.push_back('_');
226  pdsTableName.push_back(tableName[i]);
227  }
228  else {
229  pdsTableName.push_back(tableName[i]);
230  }
231  }
232  pdsTableName = pdsTableName.toUpper();
233  if (pdsTableName.indexOf("_TABLE") != pdsTableName.length() - 6) {
234  pdsTableName += "_TABLE";
235  }
236  return pdsTableName;
237  }
238 
249  void ExportPdsTable::Pack(TableRecord record, char *buffer,
250  EndianSwapper *endianSwap) {
251  // for each field, keep track of the start byte
252  int startByte = 0;
253  for(int fieldIndex = 0; fieldIndex < record.Fields(); fieldIndex++) {
254  // check the data type of the field,
255  // swap the appropriate number of bytes
256  // fill the buffer at the appropriate address
257  // find the start byte of the next field
258  TableField &field = record[fieldIndex];
259  if(field.isDouble()) {
260  vector<double> fieldValues = field;
261  for(unsigned int i = 0; i < fieldValues.size(); i++) {
262  double value = endianSwap->Double(&fieldValues[i]);
263  memmove(buffer + startByte, &value, 8);
264  startByte += sizeof(double);
265  }
266  }
267  else if(field.isInteger()) {
268  vector<int> fieldValues = field;
269  for(unsigned int i = 0; i < fieldValues.size(); i++) {
270  int value = endianSwap->Int(&fieldValues[i]);
271  memmove(buffer + startByte, &value, 4);
272  startByte += sizeof(int);
273  }
274  }
275  else if(field.isText()) {
276  QString val = field;
277  // copy each character and count each byte individually
278  for(int i = 0; i < field.size(); i++) {
279  if(i < (int)val.length()) {
280  buffer[startByte] = val[i].toLatin1();
281  }
282  else {
283  // this line is not covered by unitTest since this is a case that
284  // should not happen. When a Text TableField is created, the
285  // string value length is resized to fit the field size.
286  buffer[startByte] = 0;
287  }
288  startByte++;
289  }
290  }
291  else if(field.isReal()) {
292  vector<float> fieldValues = field;
293  for(unsigned int i = 0; i < fieldValues.size(); i++) {
294  float value = endianSwap->Float(&fieldValues[i]);
295  memmove(buffer + startByte, &value, 4);
296  startByte += sizeof(float);
297  }
298  }
299  else { // This error is not covered in the unitTest since currently, there
300  // are no other valid values for TableField types. It is meant to
301  // catch other values if they are added to Table Field.
302  QString msg = "Unable to export Isis::Table object to PDS. Invalid "
303  "field type found for [" + field.name() + "].";
304  throw IException(IException::Programmer, msg, _FILEINFO_);
305  }
306  }
307  // after loopting through the fields, the value of the startByte variable
308  // should match the total number of row bytes for the table
309  if (startByte != m_rowBytes) { // thie error is not covered in the unitTest
310  // tested since it should not be possible
311  // unless the number of bytes reserved for
312  // each of the types changes
313  QString msg = "Unable to export Isis::Table object [" + m_isisTable->Name()
314  + "] to PDS. Record lengths are uneven.";
315  throw IException(IException::Unknown, msg, _FILEINFO_);
316  }
317  }
318 } // namespace Isis
Isis::EndianSwapper::Float
float Float(void *buf)
Swaps a floating point value.
Definition: EndianSwapper.cpp:78
Isis::TableField::type
Type type() const
Returns the enumerated value of the TableField value's type.
Definition: TableField.cpp:112
Isis::PvlObject
Contains Pvl Groups and Pvl Objects.
Definition: PvlObject.h:61
Isis::PvlKeyword
A single keyword-value pair.
Definition: PvlKeyword.h:82
Isis::PvlContainer::addKeyword
void addKeyword(const PvlKeyword &keyword, const InsertMode mode=Append)
Add a keyword to the container.
Definition: PvlContainer.cpp:202
Isis::TableRecord::Fields
int Fields() const
Returns the number of fields that are currently in the record.
Definition: TableRecord.cpp:78
Isis::PvlObject::addObject
void addObject(const PvlObject &object)
Add a PvlObject.
Definition: PvlObject.h:307
Isis::TableRecord
Definition: TableRecord.h:38
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::TableField::isInteger
bool isInteger() const
Determines whether the field type is Integer.
Definition: TableField.cpp:122
Isis::TableRecord::RecordSize
int RecordSize() const
Returns the number of bytes per record.
Definition: TableRecord.cpp:87
Isis::TableField::isReal
bool isReal() const
Determines whether the field type is Text.
Definition: TableField.cpp:150
Isis::Table
Class for storing Table blobs information.
Definition: Table.h:61
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::TableField::isDouble
bool isDouble() const
Determines whether the field type is Double.
Definition: TableField.cpp:132
Isis::TableField::size
int size() const
Returns the number of values stored for the field at each record.
Definition: TableField.cpp:168
Isis::TableField::name
QString name() const
Returns the name of the TableField.
Definition: TableField.cpp:97
Isis::EndianSwapper::Int
int Int(void *buf)
Swaps a 4 byte integer value.
Definition: EndianSwapper.cpp:108
std
Namespace for the standard library.
Isis::EndianSwapper
Byte swapper.
Definition: EndianSwapper.h:38
Isis::TableField::isText
bool isText() const
Determines whether the field type is Text.
Definition: TableField.cpp:141
Isis::Table::Records
int Records() const
Returns the number of records.
Definition: Table.cpp:313
Isis::EndianSwapper::Double
double Double(void *buf)
Swaps a double precision value.
Definition: EndianSwapper.cpp:55
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::TableField
Class for storing an Isis::Table's field information.
Definition: TableField.h:47

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the USGS Astrogeology Discussion Board
To report a bug, or suggest a feature go to: ISIS Github
File Modified: 07/13/2023 15:16:26