USGS

Isis 3.0 Object Programmers' Reference

Home

ExportPdsTable.cpp
Go to the documentation of this file.
1 
22 #include "ExportPdsTable.h"
23 
24 #include <cmath>
25 #include <iostream>
26 
27 #include "Endian.h"
28 #include "EndianSwapper.h"
29 #include "IString.h"
30 #include "IException.h"
31 #include "Pvl.h"
32 #include "PvlKeyword.h"
33 #include "PvlObject.h"
34 #include "Table.h"
35 #include "TableField.h"
36 #include "TableRecord.h"
37 
38 
39 using namespace std;
40 
41 namespace Isis {
53  ExportPdsTable::ExportPdsTable(Table isisTable) {
54  // initialize member variables
55  m_outputRecordBytes = 0;
56  m_pdsByteOrder = "LSB";
57  m_isisTable = new Table(isisTable);
58  m_numRows = isisTable.Records(); //one row in pdsTable per record in isisTable
59  m_rowBytes = m_isisTable->RecordSize(); //this should be the same value
60  //for all pds rows and isis records
61  }
62 
66  ExportPdsTable::~ExportPdsTable() {
67  // delete pointers and set to null
68  delete m_isisTable;
69  m_isisTable = NULL;
70  }
71 
82  PvlObject ExportPdsTable::exportTable(char *pdsTableBuffer,
83  int outputFileRecordBytes,
84  QString pdsTableByteOrder) {
85  // Currently, we will not allow our table rows to be wrapped. So we must
86  // check that the rowbytes of the output table are no larger than the total
87  // record bytes allowed in the output pds file
88  m_outputRecordBytes = outputFileRecordBytes;
89  if (m_rowBytes > m_outputRecordBytes) {
90  throw IException(IException::Unknown,
91  "Unable to export Isis::Table object to PDS. The "
92  "Isis::Table record size [" + toString(m_rowBytes)
93  + "] is larger than the record bytes allowed in the "
94  "PDS file [" + toString(m_outputRecordBytes) + "].",
95  _FILEINFO_);
96  }
97 
98  // update variables
99  m_pdsByteOrder = pdsTableByteOrder.toUpper();
100 
101  if (m_pdsByteOrder != "MSB" && m_pdsByteOrder != "LSB") {
102  QString msg = "Unable to export the Isis Table [" + m_isisTable->Name()
103  + "] to a PDS table using the requested byte order ["
104  + m_pdsByteOrder + "]. Valid values are MSB or LSB.";
105  throw IException(IException::Unknown, msg, _FILEINFO_);
106  }
107 
108  // create an array of nulls to pad
109  // from the end of each row to the end of the record
110  int numRowNulls = outputFileRecordBytes - m_rowBytes;
111  char endRowPadding[numRowNulls];
112  for (int i = 0; i < numRowNulls; i++) {
113  endRowPadding[i] = '\0';
114  }
115 
116  // loop through records in the input Isis::Table object
117  // fill rowBuffer with packed record values, then fill with padding
118  EndianSwapper *endianSwap = new EndianSwapper(m_pdsByteOrder);
119 
120  int buffsize = 0;
121  for(int recIndex = 0; recIndex < m_isisTable->Records(); recIndex++) {
122  TableRecord record = (*m_isisTable)[recIndex];
123  char rowBuffer[record.RecordSize()];
124  Pack(record, rowBuffer, endianSwap);
125  int i = recIndex*m_outputRecordBytes;
126  memmove(pdsTableBuffer + i, &rowBuffer, record.RecordSize());
127  memmove(pdsTableBuffer + i + m_rowBytes, &endRowPadding, numRowNulls);
128  buffsize+=record.RecordSize();
129  buffsize+=numRowNulls;
130  }
131  return fillMetaData();
132  }
133 
140  PvlObject ExportPdsTable::fillMetaData() {
141  QString pdsTableName = formatPdsTableName();
142  PvlObject pdsTableLabelInfo(pdsTableName);
143  // Data Object Descriptions
144  // NOTE: this class is currently only exporting BINARY format PDS tables.
145  // implementation may be added later to export ASCII PDS tables.
146  pdsTableLabelInfo.addKeyword(PvlKeyword("INTERCHANGE_FORMAT", "BINARY"));
147  pdsTableLabelInfo.addKeyword(PvlKeyword("ROWS", toString(m_isisTable->Records())));
148  pdsTableLabelInfo.addKeyword(PvlKeyword("COLUMNS", toString(m_isisTable->RecordFields())));
149  pdsTableLabelInfo.addKeyword(PvlKeyword("ROW_BYTES", toString(m_rowBytes)));
150  pdsTableLabelInfo.addKeyword(PvlKeyword("ROW_SUFFIX_BYTES", toString(m_outputRecordBytes - m_rowBytes)));
151  int startByte = 1; // PDS begins indexing at 1
152  for(int fieldIndex = 0; fieldIndex < m_isisTable->RecordFields(); fieldIndex++) {
153  int columnBytes = 0;
154  TableField field = (*m_isisTable)[0][fieldIndex];
155  PvlObject columnObj("COLUMN");
156  columnObj.addKeyword(PvlKeyword("COLUMN_NUMBER", toString(fieldIndex + 1)));
157  columnObj.addKeyword(PvlKeyword("NAME", field.name()));
158 
159 
160  if (field.type() == TableField::Text) {
161  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "CHARACTER"));
162  QString val = field;
163  for(int i = 0; i < field.size(); i++) {
164  columnBytes++;
165  }
166  }
167  else if (field.type() == TableField::Integer) {
168  if (m_pdsByteOrder == "MSB") {
169  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "MSB_INTEGER"));
170  columnBytes = sizeof(int);
171  }
172  else { // if (m_pdsByteOrder == "LSB") {
173  // no need to check this. already validated in exportPdsTable()
174  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "LSB_INTEGER"));
175  columnBytes = sizeof(int);
176  }
177  }
178  else if (field.type() == TableField::Double) {
179  if (m_pdsByteOrder == "MSB") {
180  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "IEEE_REAL"));
181  columnBytes = sizeof(double);
182  }
183  else { // if (m_pdsByteOrder == "LSB") {
184  // no need to check this. already validated in exportPdsTable()
185  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "PC_REAL"));
186  columnBytes = sizeof(double);
187  }
188  }
189  else if (field.type() == TableField::Real) {
190  if (m_pdsByteOrder == "MSB") {
191  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "IEEE_REAL"));
192  columnBytes = sizeof(float);
193  }
194  else { // if (m_pdsByteOrder == "LSB") {
195  // no need to check this. already validated in exportPdsTable()
196  columnObj.addKeyword(PvlKeyword("DATA_TYPE", "PC_REAL"));
197  columnBytes = sizeof(float);
198  }
199  }
200  else { // This error is not covered in the unitTest since currently, there
201  // are no other valid values for TableField types. It is meant to
202  // catch other values if they are added to Table Field.
203  QString msg = "Unable to export Isis::Table object to PDS. Invalid "
204  "field type found for [" + field.name() + "].";
205  throw IException(IException::Programmer, msg, _FILEINFO_);
206  }
207  columnObj.addKeyword(PvlKeyword("START_BYTE", toString(startByte)));
208  startByte += columnBytes;
209  columnObj.addKeyword(PvlKeyword("BYTES", toString(columnBytes)));
210  pdsTableLabelInfo.addObject(columnObj);
211  }
212  return pdsTableLabelInfo;
213  }
214 
220  QString ExportPdsTable::formatPdsTableName() {
221  return ExportPdsTable::formatPdsTableName(m_isisTable->Name());
222  }
223 
234  QString ExportPdsTable::formatPdsTableName(QString isisTableName) {
235  QString tableName = isisTableName.simplified();
236  QString pdsTableName;
237  pdsTableName.push_back(tableName[0]);
238  for (int i = 1 ; i < tableName.size() ; i++) {
239  if (tableName[i] >= 65 && tableName[i] <= 90) {
240  pdsTableName.push_back('_');
241  pdsTableName.push_back(tableName[i]);
242  }
243  else {
244  pdsTableName.push_back(tableName[i]);
245  }
246  }
247  pdsTableName = pdsTableName.toUpper();
248  if (pdsTableName.indexOf("_TABLE") != pdsTableName.length() - 6) {
249  pdsTableName += "_TABLE";
250  }
251  return pdsTableName;
252  }
253 
264  void ExportPdsTable::Pack(TableRecord record, char *buffer,
265  EndianSwapper *endianSwap) {
266  // for each field, keep track of the start byte
267  int startByte = 0;
268  for(int fieldIndex = 0; fieldIndex < record.Fields(); fieldIndex++) {
269  // check the data type of the field,
270  // swap the appropriate number of bytes
271  // fill the buffer at the appropriate address
272  // find the start byte of the next field
273  TableField &field = record[fieldIndex];
274  if(field.isDouble()) {
275  vector<double> fieldValues = field;
276  for(unsigned int i = 0; i < fieldValues.size(); i++) {
277  double value = endianSwap->Double(&fieldValues[i]);
278  memmove(buffer + startByte, &value, 8);
279  startByte += sizeof(double);
280  }
281  }
282  else if(field.isInteger()) {
283  vector<int> fieldValues = field;
284  for(unsigned int i = 0; i < fieldValues.size(); i++) {
285  int value = endianSwap->Int(&fieldValues[i]);
286  memmove(buffer + startByte, &value, 4);
287  startByte += sizeof(int);
288  }
289  }
290  else if(field.isText()) {
291  QString val = field;
292  // copy each character and count each byte individually
293  for(int i = 0; i < field.size(); i++) {
294  if(i < (int)val.length()) {
295  buffer[startByte] = val[i].toAscii();
296  }
297  else {
298  // this line is not covered by unitTest since this is a case that
299  // should not happen. When a Text TableField is created, the
300  // string value length is resized to fit the field size.
301  buffer[startByte] = 0;
302  }
303  startByte++;
304  }
305  }
306  else if(field.isReal()) {
307  vector<float> fieldValues = field;
308  for(unsigned int i = 0; i < fieldValues.size(); i++) {
309  float value = endianSwap->Float(&fieldValues[i]);
310  memmove(buffer + startByte, &value, 4);
311  startByte += sizeof(float);
312  }
313  }
314  else { // This error is not covered in the unitTest since currently, there
315  // are no other valid values for TableField types. It is meant to
316  // catch other values if they are added to Table Field.
317  QString msg = "Unable to export Isis::Table object to PDS. Invalid "
318  "field type found for [" + field.name() + "].";
319  throw IException(IException::Programmer, msg, _FILEINFO_);
320  }
321  }
322  // after loopting through the fields, the value of the startByte variable
323  // should match the total number of row bytes for the table
324  if (startByte != m_rowBytes) { // thie error is not covered in the unitTest
325  // tested since it should not be possible
326  // unless the number of bytes reserved for
327  // each of the types changes
328  QString msg = "Unable to export Isis::Table object [" + m_isisTable->Name()
329  + "] to PDS. Record lengths are uneven.";
330  throw IException(IException::Unknown, msg, _FILEINFO_);
331  }
332  }
333 } // namespace Isis