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
24using namespace std;
25
26namespace Isis {
39 // initialize member variables
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
52 // delete pointers and set to null
53 delete m_isisTable;
54 m_isisTable = NULL;
55 }
56
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;
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
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
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
~ExportPdsTable()
Destructs for ExportPdsTable objects.
void Pack(TableRecord record, char *buffer, EndianSwapper *endianSwap)
Pack the buffer with data from the table record, swapping bytes if needed.
int m_numRows
The number of rows in the exported PDS table.
QString m_pdsByteOrder
A string indicating the byte order of the exported PDS file.
PvlObject fillMetaData()
Creates a PvlObject to be added to the PDS label with needed TABLE information.
PvlObject exportTable(char *pdsTableBuffer, int pdsFileRecordBytes, QString pdsByteOrder)
This methods fills the given buffer with the binary PDS table data and returns label information.
QString formatPdsTableName()
Format the PDS table object name using the ISIS table name.
int m_rowBytes
The number of bytes per row in the exported PDS table.
int m_outputRecordBytes
The number of bytes per record in the exported PDS file.
Table * m_isisTable
Input ISIS Table object to be exported.
ExportPdsTable(Table isisTable)
Construct an ExportPdsTable object and set default member variable values.
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
A single keyword-value pair.
Definition PvlKeyword.h:87
Contains Pvl Groups and Pvl Objects.
Definition PvlObject.h:61
Class for storing an Isis::Table's field information.
Definition TableField.h:47
@ Integer
The values in the field are 4 byte integers.
Definition TableField.h:53
@ Real
The values in the field are 4 byte reals or floats.
Definition TableField.h:57
@ Text
The values in the field are text strings with 1 byte per character.
Definition TableField.h:55
@ Double
The values in the field are 8 byte doubles.
Definition TableField.h:54
Class for storing Table blobs information.
Definition Table.h:61
int RecordSize() const
Returns the number of bytes per record.
Definition Table.cpp:333
int RecordFields() const
Returns the number of fields per record.
Definition Table.cpp:323
int Records() const
Returns the number of records.
Definition Table.cpp:313
QString Name() const
The Table's name.
Definition Table.cpp:247
int RecordSize() const
Returns the number of bytes per record.
int Fields() const
Returns the number of fields that are currently in the record.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
Namespace for the standard library.