File failed to load: https://isis.astrogeology.usgs.gov/9.0.0/Object/assets/jax/output/NativeMML/config.js
Isis 3 Programmer Reference
ExportPdsTable.cpp
1
5
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 for(int recIndex = 0; recIndex < m_isisTable->Records(); recIndex++) {
106 TableRecord record = (*m_isisTable)[recIndex];
107 char rowBuffer[record.RecordSize()];
108 Pack(record, rowBuffer, endianSwap);
109 int i = recIndex*m_outputRecordBytes;
110 memmove(pdsTableBuffer + i, &rowBuffer, record.RecordSize());
111 memmove(pdsTableBuffer + i + m_rowBytes, &endRowPadding, numRowNulls);
112 }
113 return fillMetaData();
114 }
115
123 QString pdsTableName = formatPdsTableName();
124 PvlObject pdsTableLabelInfo(pdsTableName);
125 // Data Object Descriptions
126 // NOTE: this class is currently only exporting BINARY format PDS tables.
127 // implementation may be added later to export ASCII PDS tables.
128 pdsTableLabelInfo.addKeyword(PvlKeyword("INTERCHANGE_FORMAT", "BINARY"));
129 pdsTableLabelInfo.addKeyword(PvlKeyword("ROWS", toString(m_isisTable->Records())));
130 pdsTableLabelInfo.addKeyword(PvlKeyword("COLUMNS", toString(m_isisTable->RecordFields())));
131 pdsTableLabelInfo.addKeyword(PvlKeyword("ROW_BYTES", toString(m_rowBytes)));
132 pdsTableLabelInfo.addKeyword(PvlKeyword("ROW_SUFFIX_BYTES", toString(m_outputRecordBytes - m_rowBytes)));
133 int startByte = 1; // PDS begins indexing at 1
134 for(int fieldIndex = 0; fieldIndex < m_isisTable->RecordFields(); fieldIndex++) {
135 int columnBytes = 0;
136 TableField field = (*m_isisTable)[0][fieldIndex];
137 PvlObject columnObj("COLUMN");
138 columnObj.addKeyword(PvlKeyword("COLUMN_NUMBER", toString(fieldIndex + 1)));
139 columnObj.addKeyword(PvlKeyword("NAME", field.name()));
140
141
142 if (field.type() == TableField::Text) {
143 columnObj.addKeyword(PvlKeyword("DATA_TYPE", "CHARACTER"));
144 QString val = field;
145 for(int i = 0; i < field.size(); i++) {
146 columnBytes++;
147 }
148 }
149 else if (field.type() == TableField::Integer) {
150 if (m_pdsByteOrder == "MSB") {
151 columnObj.addKeyword(PvlKeyword("DATA_TYPE", "MSB_INTEGER"));
152 columnBytes = sizeof(int);
153 }
154 else { // if (m_pdsByteOrder == "LSB") {
155 // no need to check this. already validated in exportPdsTable()
156 columnObj.addKeyword(PvlKeyword("DATA_TYPE", "LSB_INTEGER"));
157 columnBytes = sizeof(int);
158 }
159 }
160 else if (field.type() == TableField::Double) {
161 if (m_pdsByteOrder == "MSB") {
162 columnObj.addKeyword(PvlKeyword("DATA_TYPE", "IEEE_REAL"));
163 columnBytes = sizeof(double);
164 }
165 else { // if (m_pdsByteOrder == "LSB") {
166 // no need to check this. already validated in exportPdsTable()
167 columnObj.addKeyword(PvlKeyword("DATA_TYPE", "PC_REAL"));
168 columnBytes = sizeof(double);
169 }
170 }
171 else if (field.type() == TableField::Real) {
172 if (m_pdsByteOrder == "MSB") {
173 columnObj.addKeyword(PvlKeyword("DATA_TYPE", "IEEE_REAL"));
174 columnBytes = sizeof(float);
175 }
176 else { // if (m_pdsByteOrder == "LSB") {
177 // no need to check this. already validated in exportPdsTable()
178 columnObj.addKeyword(PvlKeyword("DATA_TYPE", "PC_REAL"));
179 columnBytes = sizeof(float);
180 }
181 }
182 else { // This error is not covered in the unitTest since currently, there
183 // are no other valid values for TableField types. It is meant to
184 // catch other values if they are added to Table Field.
185 QString msg = "Unable to export Isis::Table object to PDS. Invalid "
186 "field type found for [" + field.name() + "].";
187 throw IException(IException::Programmer, msg, _FILEINFO_);
188 }
189 columnObj.addKeyword(PvlKeyword("START_BYTE", toString(startByte)));
190 startByte += columnBytes;
191 columnObj.addKeyword(PvlKeyword("BYTES", toString(columnBytes)));
192 pdsTableLabelInfo.addObject(columnObj);
193 }
194 return pdsTableLabelInfo;
195 }
196
205
216 QString ExportPdsTable::formatPdsTableName(QString isisTableName) {
217 QString tableName = isisTableName.simplified();
218 QString pdsTableName;
219 pdsTableName.push_back(tableName[0]);
220 for (int i = 1 ; i < tableName.size() ; i++) {
221 if (tableName[i] >= 65 && tableName[i] <= 90) {
222 pdsTableName.push_back('_');
223 pdsTableName.push_back(tableName[i]);
224 }
225 else {
226 pdsTableName.push_back(tableName[i]);
227 }
228 }
229 pdsTableName = pdsTableName.toUpper();
230 if (pdsTableName.indexOf("_TABLE") != pdsTableName.length() - 6) {
231 pdsTableName += "_TABLE";
232 }
233 return pdsTableName;
234 }
235
246 void ExportPdsTable::Pack(TableRecord record, char *buffer,
247 EndianSwapper *endianSwap) {
248 // for each field, keep track of the start byte
249 int startByte = 0;
250 for(int fieldIndex = 0; fieldIndex < record.Fields(); fieldIndex++) {
251 // check the data type of the field,
252 // swap the appropriate number of bytes
253 // fill the buffer at the appropriate address
254 // find the start byte of the next field
255 TableField &field = record[fieldIndex];
256 if(field.isDouble()) {
257 vector<double> fieldValues = field;
258 for(unsigned int i = 0; i < fieldValues.size(); i++) {
259 double value = endianSwap->Double(&fieldValues[i]);
260 memmove(buffer + startByte, &value, 8);
261 startByte += sizeof(double);
262 }
263 }
264 else if(field.isInteger()) {
265 vector<int> fieldValues = field;
266 for(unsigned int i = 0; i < fieldValues.size(); i++) {
267 int value = endianSwap->Int(&fieldValues[i]);
268 memmove(buffer + startByte, &value, 4);
269 startByte += sizeof(int);
270 }
271 }
272 else if(field.isText()) {
273 QString val = field;
274 // copy each character and count each byte individually
275 for(int i = 0; i < field.size(); i++) {
276 if(i < (int)val.length()) {
277 buffer[startByte] = val[i].toLatin1();
278 }
279 else {
280 // this line is not covered by unitTest since this is a case that
281 // should not happen. When a Text TableField is created, the
282 // string value length is resized to fit the field size.
283 buffer[startByte] = 0;
284 }
285 startByte++;
286 }
287 }
288 else if(field.isReal()) {
289 vector<float> fieldValues = field;
290 for(unsigned int i = 0; i < fieldValues.size(); i++) {
291 float value = endianSwap->Float(&fieldValues[i]);
292 memmove(buffer + startByte, &value, 4);
293 startByte += sizeof(float);
294 }
295 }
296 else { // This error is not covered in the unitTest since currently, there
297 // are no other valid values for TableField types. It is meant to
298 // catch other values if they are added to Table Field.
299 QString msg = "Unable to export Isis::Table object to PDS. Invalid "
300 "field type found for [" + field.name() + "].";
301 throw IException(IException::Programmer, msg, _FILEINFO_);
302 }
303 }
304 // after loopting through the fields, the value of the startByte variable
305 // should match the total number of row bytes for the table
306 if (startByte != m_rowBytes) { // thie error is not covered in the unitTest
307 // tested since it should not be possible
308 // unless the number of bytes reserved for
309 // each of the types changes
310 QString msg = "Unable to export Isis::Table object [" + m_isisTable->Name()
311 + "] to PDS. Record lengths are uneven.";
312 throw IException(IException::Unknown, msg, _FILEINFO_);
313 }
314 }
315} // namespace Isis
float Float(void *buf)
Swaps a floating point value.
int Int(void *buf)
Swaps a 4 byte integer value.
double Double(void *buf)
Swaps a double precision value.
~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
void addKeyword(const PvlKeyword &keyword, const InsertMode mode=Append)
Add a keyword to the container.
A single keyword-value pair.
Definition PvlKeyword.h:87
Contains Pvl Groups and Pvl Objects.
Definition PvlObject.h:61
void addObject(const PvlObject &object)
Add a PvlObject.
Definition PvlObject.h:307
Class for storing an Isis::Table's field information.
Definition TableField.h:47
bool isInteger() const
Determines whether the field type is Integer.
bool isDouble() const
Determines whether the field type is Double.
bool isReal() const
Determines whether the field type is Text.
QString name() const
Returns the name of the TableField.
@ 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
int size() const
Returns the number of values stored for the field at each record.
bool isText() const
Determines whether the field type is Text.
Type type() const
Returns the enumerated value of the TableField value's type.
Class for storing Table blobs information.
Definition Table.h:61
int Records() const
Returns the number of records.
Definition Table.cpp:371
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.