Isis 3 Programmer Reference
PvlFormat.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "IException.h"
8#include "IString.h"
9#include "Message.h"
10#include "FileName.h"
11#include "PvlKeyword.h"
12#include "TextFile.h"
13#include "Pvl.h"
14#include "PvlFormat.h"
15
16using namespace std;
17
18namespace Isis {
19
20 /*
21 * Constructs an empty PvlFormat
22 */
23 PvlFormat::PvlFormat() {
24 init();
25 }
26
27
28 /*
29 * Constructs a PvlFormat using the file name to ingest as the keyword to type
30 * mapping. This is provided as a convience for child objects. The map is not
31 * used for output of PvlKeywords in Normal Isis format.
32 *
33 * @param file A file name with keyword=type. Where KEYWORD is the name of a
34 * keyword in this PvlKeyword and TYPE is one of [QString | integer | float ]
35 */
36 PvlFormat::PvlFormat(const QString &file) {
37 init();
38 add(file);
39 }
40
41
42 /*
43 * Constructs a PvlFormat using the specified pre populated Pvl map of keyword
44 * name (QString) vs keyword type (KeywordType).
45 *
46 * @param keywordType A Pvl with keyword=type. Where keyword is the name of a
47 * keyword in a PvlKeyword and type is one of [QString | integer | float ]
48 */
49 PvlFormat::PvlFormat(Pvl &keywordType) {
50 init();
51 add(keywordType);
52 }
53
54
57 m_keywordMap.clear();
58 m_keywordMapFile.clear();
59 m_charLimit = 80;
60 }
61
62
63 /*
64 * Add the contents of a file to the keyword type mapping. The file should
65 * contain KEYWORD=TYPE (one per line), where TYPE is one of the QStrings
66 * KeywordType can convert.
67 */
68 void PvlFormat::add(const QString &file) {
69 m_keywordMapFile = file;
70
71 // Open the file and internalize it into the Pvl map
72 try {
73 Pvl pvl(file);
74 add(pvl);
75 }
76 catch(IException &e) {
77 QString msg;
78 msg += "Unable to open or read keyword to type mapping file [";
79 msg += file + "]";
80 throw IException(e, IException::Programmer, msg, _FILEINFO_);
81 }
82 }
83
84
85 /*
86 * Add the contents of a Pvl to the keyword type mapping. The pvl should
87 * contain KEYWORD=TYPE, where TYPE is one of the QStrings KeywordType can
88 * convert.
89 */
90 void PvlFormat::add(Pvl &pvl) {
91 for(int i = 0; i < pvl.keywords(); ++i) {
92 PvlKeyword &key = pvl[i];
93 QString name = key.name().toUpper();
94 QString type = key[0].toUpper();
95 PvlKeyword newKey(name, type);
96 for(int j = 1; j < key.size(); ++j) newKey.addValue(key[j]);
97 // Make sure we don't duplicate Keys
98 if (m_keywordMap.hasKeyword(name)) {
99 m_keywordMap.deleteKeyword(name);
100 }
101 m_keywordMap.addKeyword(newKey);
102 }
103 }
104
105
106 /*
107 * Returns the type of the keyword from the supplied map if any
108 *
109 * @param keyword The PvlKeyword to have its type returned
110 */
111 KeywordType PvlFormat::type(const PvlKeyword &keyword) {
112 QString name = keyword.name().toUpper();
113 if(m_keywordMap.hasKeyword(name)) {
114 PvlKeyword &key = m_keywordMap.findKeyword(name);
115 return toKeywordType(key[0]);
116 }
117 return NoTypeKeyword;
118 }
119
120
121 /*
122 * Returns the number of digits of accuracy (right of decimal place) this
123 * keyword should be output with
124 *
125 * @param keyword The PvlKeyword the accuracy is need for
126 * @return The number of decimal places to be output. If this number is not
127 * available in keyword map return -1.
128 */
129 int PvlFormat::accuracy(const PvlKeyword &keyword) {
130 QString name = keyword.name().toUpper();
131 if(m_keywordMap.hasKeyword(name)) {
132 PvlKeyword &key = m_keywordMap.findKeyword(name);
133 if(key.size() > 1) {
134 return toInt(key[1]);
135 }
136 }
137 return -1;
138 }
139
140
141 /*
142 * Returns the keyword name and value(s) formatted in "Normal" Isis format
143 *
144 * @param keyword The PvlKeyword to be formatted
145 * @param num Use the ith value of the keyword
146 */
147 QString PvlFormat::formatValue(const PvlKeyword &keyword, int num) {
148
149 QString val;
150 val.clear();
151
152 // Find out if the units are the same for all values
153 bool singleUnit = isSingleUnit(keyword);
154
155 // Create a Null value if the value index is greater than the number of values
156 if(num >= keyword.size()) {
157 return "Null";
158 }
159
160 // Create a Null value if the requested index is an empty QString
161 if(keyword[num].size() == 0) {
162 val += "Null";
163 }
164 else {
165 val += keyword[num];
166 }
167
168 val = addQuotes(val);
169
170 // If it is an array start it off with a paren
171 if((keyword.size() > 1) && (num == 0)) {
172 val = "(" + val;
173 }
174
175 // Add the units to this value
176 if((!singleUnit) && (keyword.unit(num).size() > 0)) {
177 val += " <" + keyword.unit(num) + ">";
178 }
179
180 // Add a comma for arrays
181 if(num != keyword.size() - 1) {
182 val += ", ";
183 }
184 // If it is an array close it off
185 else if(keyword.size() > 1) {
186 val += ")";
187 }
188
189 // Add the units to the end if all values have the same units
190 if((singleUnit) && (num == keyword.size() - 1) &&
191 (keyword.unit(num).size() > 0)) {
192 val += " <" + keyword.unit(num) + ">";
193 }
194
195 return val;
196 }
197
198
199 /*
200 * Format the name of the container
201 *
202 * @param keyword The PvlContainer being closed.
203 */
204 QString PvlFormat::formatName(const PvlKeyword &keyword) {
205 return keyword.name();
206 }
207
208
209 /*
210 * Format the end of a container
211 *
212 * @param name The text used to signify the end of a container
213 * @param keyword The PvlContainer being closed.
214 */
215 QString PvlFormat::formatEnd(const QString name,
216 const PvlKeyword &keyword) {
217 return "End_" + formatName(keyword);
218 }
219
220
221 /*
222 * Add single or double quotes around a value if necessary. The Isis definition
223 * of when quotes are necessary is used.
224 *
225 * @param value The PvlKeyword value to be quoted if necessary.
226 */
227 QString PvlFormat::addQuotes(const QString value) {
228 QString val = value;
229
230 bool needQuotes = false;
231
232 // find out if we need quotes and what kind of quotes might already exist
233 char existingQuoteType = '\0';
234 for (int pos = 0; !needQuotes && pos < val.size(); pos++) {
235 // check for values indicating we need quotes, if we have a sequence
236 // it should already be properly quoted...
237 if (pos == 0) {
238 if (val[pos] == '(' || val[pos] == '{') {
239 // Find closing
240 int closePos = -1;
241 if (val[pos] == '(') {
242 closePos = val.indexOf(')');
243 }
244 if (val[pos] == '{') {
245 closePos = val.indexOf('}');
246 }
247
248 // If no closing paren or brace or If closing paren/brace not at end of value
249 if (closePos == -1 || closePos != val.size() - 1) {
250 needQuotes = true;
251 }
252 else {
253 break;
254 }
255 }
256 }
257
258 if (val[pos] == ' ' || val[pos] == '(' ||
259 val[pos] == '(' || val[pos] == ')' ||
260 val[pos] == '{' || val[pos] == '}' ||
261 val[pos] == ',' || val[pos] == '=') {
262 needQuotes = true;
263 }
264
265 if (pos == val.size() - 1 && val[pos] == '-') {
266 needQuotes = true;
267 }
268
269 // remember if we are a quote, what quote type we are
270 if (existingQuoteType == '\0') {
271 if (val[pos] == '"') {
272 existingQuoteType = '"';
273 }
274 else if (val[pos] == '\'') {
275 existingQuoteType = '\'';
276 }
277 }
278 else {
279 // make sure we dont have mixing of our outside quote type
280 if (val[pos] == '"' || val[pos] == '\'') {
281 val[pos] = existingQuoteType;
282 }
283 }
284 }
285
286 // figure out what kind of quotes we want to add
287 char quoteValue = '"';
288
289 if(existingQuoteType == '"') {
290 quoteValue = '\'';
291 }
292
293 if(needQuotes) {
294 val = quoteValue + val + quoteValue;
295 }
296
297 return val;
298 }
299
300
307 bool PvlFormat::isSingleUnit(const PvlKeyword &keyword) {
308
309 // See if the units are all the same
310 bool singleUnit = true;
311 for(int i = 0; i < keyword.size(); i ++) {
312 if(!keyword.stringEqual(keyword.unit(i), keyword.unit(0))) {
313 singleUnit = false;
314 }
315 }
316
317 return singleUnit;
318 }
319}
320
@ 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.
void deleteKeyword(const QString &name)
Remove a specified keyword.
unsigned int m_charLimit
Maximum number of characters on a single line of a keyword value.
Definition PvlFormat.h:163
bool isSingleUnit(const PvlKeyword &keyword)
Returns true if the units are the same for all value in the keyword otherwise it returns false.
void init()
Clears all PvlFormat data.
Definition PvlFormat.cpp:56
Container for cube-like labels.
Definition Pvl.h:119
A single keyword-value pair.
Definition PvlKeyword.h:87
int size() const
Returns the number of values stored in this keyword.
Definition PvlKeyword.h:133
QString unit(const int index=0) const
Returns the units of measurement of the element of the array of values for the object at the specifie...
static bool stringEqual(const QString &string1, const QString &string2)
Checks to see if two QStrings are equal.
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 ...
void clear()
Remove everything from the current PvlObject.
Definition PvlObject.h:343
PvlKeyword & findKeyword(const QString &kname, FindOptions opts)
Finds a keyword in the current PvlObject, or deeper inside other PvlObjects and Pvlgroups within this...
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
KeywordType
The different types of keywords that can be formatted.
Definition PvlFormat.h:19
int toInt(const QString &string)
Global function to convert from a string to an integer.
Definition IString.cpp:93
KeywordType toKeywordType(const QString type)
Convert a string representing a type of keyword to the corresponding enumeration.
Definition PvlFormat.h:38
Namespace for the standard library.