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