Isis 3 Programmer Reference
Pvl.cpp
Go to the documentation of this file.
1 
22 #include "Pvl.h"
23 #include "PvlGroup.h"
24 #include "PvlKeyword.h"
25 
26 #include <locale>
27 #include <fstream>
28 
29 #include "FileName.h"
30 #include "IException.h"
31 #include "Message.h"
32 #include "PvlTokenizer.h"
33 #include "PvlFormat.h"
34 
35 using namespace std;
36 namespace Isis {
38  Pvl::Pvl() : Isis::PvlObject("Root") {
39  init();
40  }
41 
42 
48  Pvl::Pvl(const QString &file) : Isis::PvlObject("Root") {
49  init();
50  read(file);
51  }
52 
53 
55  Pvl::Pvl(const Pvl &other) : PvlObject::PvlObject(other) {
56  m_internalTemplate = false;
57  m_terminator = other.m_terminator;
58  }
59 
60 
62  void Pvl::init() {
63  m_filename = "";
64  m_terminator = "End";
65  m_internalTemplate = false;
66  }
67 
68 
76  void Pvl::read(const QString &file) {
77  // Expand the filename
78  Isis::FileName temp(file);
79  m_filename = temp.expanded();
80 
81  // Open the file
82  ifstream istm;
83  istm.open(m_filename.toLatin1().data(), std::ios::in);
84  if(!istm) {
85  QString message = Message::FileOpen(temp.expanded());
86  throw IException(IException::Io, message, _FILEINFO_);
87  }
88 
89  // Read it
90  try {
91  istm >> *this;
92  }
93  catch(IException &e) {
94  istm.close();
95  QString message = "Unable to read PVL file [" + temp.expanded() + "]";
96  throw IException(e, IException::Unknown, message, _FILEINFO_);
97  }
98  catch(...) {
99  istm.close();
100  QString message = "Unable to read PVL file [" + temp.expanded() + "]";
101  throw IException(IException::Unknown, message, _FILEINFO_);
102  }
103  istm.close();
104  }
105 
106 
116  void Pvl::write(const QString &file) {
117  // Expand the filename
118  Isis::FileName temp(file);
119 
120  // Set up a Formatter
121  bool removeFormatter = false;
122  if(format() == NULL) {
123  setFormat(new PvlFormat());
124  removeFormatter = true;
125  }
126 
127  // Open the file
128  ofstream ostm;
129  QString tempName(temp.expanded());
130  ostm.open(tempName.toLatin1().data(), std::ios::out);
131  ostm.seekp(0, std::ios::beg);
132  if(!ostm) {
133  QString message = Isis::Message::FileCreate(temp.expanded());
134  throw IException(IException::Io, message, _FILEINFO_);
135  }
136 
137  // Write the labels
138  try {
139  ostm << *this;
140  if(terminator() != "") ostm << format()->formatEOL();
141  }
142  catch(IException &e) {
143  ostm.close();
144  QString message = "Unable to write PVL to file [" + temp.expanded() + "]";
145  throw IException(e, IException::Io, message, _FILEINFO_);
146  }
147  catch(...) {
148  ostm.close();
149  QString message = "Unable to write PVL to file [" + temp.expanded() + "]";
150  throw IException(IException::Io, message, _FILEINFO_);
151  }
152 
153  if(removeFormatter) {
154  delete format();
155  setFormat(NULL);
156  }
157 
158  // Close the file
159  ostm.close();
160  }
161 
162 
170  void Pvl::append(const QString &file) {
171  // Set up for opening and writing
172  Isis::FileName temp(file);
173 
174  // Set up a Formatter
175  bool removeFormatter = false;
176  if(format() == NULL) {
177  setFormat(new PvlFormat());
178  removeFormatter = true;
179  }
180 
181  // Open the file
182  ofstream ostm;
183  QString tempName(temp.expanded());
184  ostm.open(tempName.toLatin1().data(), std::ios::app);
185  ostm.seekp(0, std::ios::end);
186  if(!ostm) {
187  QString message = Message::FileOpen(temp.expanded());
188  throw IException(IException::Io, message, _FILEINFO_);
189  }
190 
191  // Write the labels
192  try {
193  ostm << *this;
194  if(terminator() != "") ostm << format()->formatEOL();
195  }
196  catch(...) {
197  ostm.close();
198  QString message = "Unable to append PVL infomation to file [" +
199  temp.expanded() + "]";
200  throw IException(IException::Io, message, _FILEINFO_);
201  }
202 
203  if(removeFormatter) {
204  delete format();
205  setFormat(NULL);
206  }
207 
208  // Close the file
209  ostm.close();
210  }
211 
212 
213  void Pvl::setFormatTemplate(Isis::Pvl &temp) {
214  if(m_internalTemplate) delete m_formatTemplate;
215  m_internalTemplate = false;
216  Isis::PvlObject::setFormatTemplate(temp);
217  }
218 
219 
220  void Pvl::setFormatTemplate(const QString &file) {
221  if(m_internalTemplate) delete m_formatTemplate;
222  m_internalTemplate = true;
223  m_formatTemplate = new Isis::Pvl(file);
224  }
225 
226 
235  ostream &operator<<(std::ostream &os, Pvl &pvl) {
236  // Set up a Formatter
237  bool removeFormatter = false;
238  if(pvl.format() == NULL) {
239  pvl.setFormat(new PvlFormat());
240  removeFormatter = true;
241  }
242 
243  Isis::Pvl outTemplate;
244  if(pvl.hasFormatTemplate()) outTemplate = *(Isis::Pvl *)pvl.formatTemplate();
245 
246  // Look for and process all include files and remove duplicates from the
247  // format template. Include files take precedence over all other objects and
248  // groups
249  Isis::Pvl newTemp;
250  for(int i = 0; i < outTemplate.keywords(); i++) {
251  if(outTemplate[i].isNamed("Isis:PvlTemplate:File")) {
252  QString filename = outTemplate[i];
253  Isis::FileName file(filename);
254  if(!file.fileExists()) {
255  QString message = "Could not open the template file [" + filename + "]";
256  throw IException(IException::Io, message, _FILEINFO_);
257  }
258  Isis::Pvl include(file.expanded());
259 
260  for(int j = 0; j < include.keywords(); j++) {
261  if(!newTemp.hasKeyword(include[j].name()))
262  newTemp.addKeyword(include[j]);
263  }
264 
265  for(int j = 0; j < include.objects(); j++) {
266  if(!newTemp.hasObject(include.object(j).name()))
267  newTemp.addObject(include.object(j));
268  }
269 
270  for(int j = 0; j < include.groups(); j++) {
271  if(!newTemp.hasGroup(include.group(j).name()))
272  newTemp.addGroup(include.group(j));
273  }
274  }
275  // If it is not an include file add it in place
276  else if(!newTemp.hasKeyword(outTemplate[i].name()))
277  newTemp.addKeyword(outTemplate[i]);
278  }
279 
280  // copy over the objects
281  for(int i = 0; i < outTemplate.objects(); i++) {
282  if(!newTemp.hasObject(outTemplate.object(i).name()))
283  newTemp.addObject(outTemplate.object(i));
284  }
285 
286  // copy over the groups
287  for(int i = 0; i < outTemplate.groups(); i++) {
288  if(!newTemp.hasGroup(outTemplate.group(i).name()))
289  newTemp.addGroup(outTemplate.group(i));
290  }
291 
292  outTemplate = newTemp;
293 
294  // Output the pvl's comments
295  for(int i = 0; i < pvl.comments(); i++) {
296  os << pvl.comment(i) << pvl.format()->formatEOL();
297  if(i == (pvl.comments() - 1)) os << pvl.format()->formatEOL();
298  }
299 
300  // Output the keywords
301  if(pvl.keywords() > 0) {
302  os << (Isis::PvlContainer &) pvl << pvl.format()->formatEOL();
303  }
304 
305  // this number keeps track of the number of objects that have been written
306  int numObjects = 0;
307 
308  // Output the objects using the format template
309  for(int i = 0; i < outTemplate.objects(); i++) {
310  for(int j = 0; j < pvl.objects(); j++) {
311  if(outTemplate.object(i).name() != pvl.object(j).name()) continue;
312  if(numObjects == 0 && pvl.keywords() > 0) os << pvl.format()->formatEOL();
313  pvl.object(j).setIndent(pvl.indent());
314  pvl.object(j).setFormatTemplate(outTemplate.object(i));
315  pvl.object(j).setFormat(pvl.format());
316  os << pvl.object(j) << pvl.format()->formatEOL();
317  pvl.object(j).setFormat(NULL);
318  pvl.object(j).setIndent(0);
319  if(++numObjects < pvl.objects()) os << pvl.format()->formatEOL();
320  }
321  }
322 
323  // Output the objects that were not included in the format template pvl
324  for(int i = 0; i < pvl.objects(); i++) {
325  if(outTemplate.hasObject(pvl.object(i).name())) continue;
326  if(numObjects == 0 && pvl.keywords() > 0) os << pvl.format()->formatEOL();
327  pvl.object(i).setIndent(pvl.indent());
328  pvl.object(i).setFormat(pvl.format());
329  os << pvl.object(i) << pvl.format()->formatEOL();
330  pvl.object(i).setFormat(NULL);
331  pvl.object(i).setIndent(0);
332  if(++numObjects < pvl.objects()) os << pvl.format()->formatEOL();
333  }
334 
335  // this number keeps track of the number of groups that have been written
336  int numGroups = 0;
337 
338  // Output the groups using the format template
339  for(int i = 0; i < outTemplate.groups(); i++) {
340  for(int j = 0; j < pvl.groups(); j++) {
341  if(outTemplate.group(i).name() != pvl.group(j).name()) continue;
342  if((numGroups == 0) &&
343  (pvl.objects() > 0 || pvl.keywords() > 0)) os << pvl.format()->formatEOL();
344  pvl.group(j).setIndent(pvl.indent());
345  pvl.group(j).setFormatTemplate(outTemplate.group(i));
346  pvl.group(j).setFormat(pvl.format());
347  os << pvl.group(j) << pvl.format()->formatEOL();
348  pvl.group(j).setFormat(NULL);
349  pvl.group(j).setIndent(0);
350  if(++numGroups < pvl.groups()) os << pvl.format()->formatEOL();
351  }
352  }
353 
354  // Output the groups that were not in the format template
355  for(int i = 0; i < pvl.groups(); i++) {
356  if(outTemplate.hasGroup(pvl.group(i).name())) continue;
357  if((numGroups == 0) &&
358  (pvl.objects() > 0 || pvl.keywords() > 0)) os << pvl.format()->formatEOL();
359  pvl.group(i).setIndent(pvl.indent());
360  pvl.group(i).setFormat(pvl.format());
361  os << pvl.group(i) << pvl.format()->formatEOL();
362  pvl.group(i).setFormat(NULL);
363  pvl.group(i).setIndent(0);
364  if(++numGroups < pvl.groups()) os << pvl.format()->formatEOL();
365  }
366 
367  // Output the terminator
368  if(pvl.terminator() != "") {
369  os << pvl.terminator();
370  }
371 
372  if(removeFormatter) {
373  delete pvl.format();
374  pvl.setFormat(NULL);
375  }
376 
377  return os;
378  }
379 
380 
389  istream &operator>>(std::istream &is, Pvl &pvl) {
390  if(!is.good()) {
391  string msg = "Tried to read input stream with an error state into a Pvl";
393  }
394 
395  try {
396  PvlKeyword termination("End");
397 
398  PvlKeyword errorKeywords[] = {
399  PvlKeyword("EndGroup"),
400  PvlKeyword("EndObject")
401  };
402 
403  PvlKeyword readKeyword;
404  istream::pos_type beforeKeywordPos = is.tellg();
405 
406  is >> readKeyword;
407 
408  while(readKeyword != termination) {
409  for(unsigned int errorKey = 0;
410  errorKey < sizeof(errorKeywords) / sizeof(PvlKeyword);
411  errorKey++) {
412  if(readKeyword == errorKeywords[errorKey]) {
413  is.seekg(beforeKeywordPos, ios::beg);
414 
415  QString msg = "Unexpected [";
416  msg += readKeyword.name();
417  msg += "] in PVL Object [ROOT]";
419  }
420  }
421 
422  if(readKeyword == PvlKeyword("Group")) {
423  is.seekg(beforeKeywordPos);
424  PvlGroup newGroup;
425  is >> newGroup;
426  pvl.addGroup(newGroup);
427  }
428  else if(readKeyword == PvlKeyword("Object")) {
429  is.seekg(beforeKeywordPos);
430  PvlObject newObject;
431  is >> newObject;
432  pvl.addObject(newObject);
433  }
434  else {
435  pvl.addKeyword(readKeyword);
436  }
437 
438  readKeyword = PvlKeyword();
439  beforeKeywordPos = is.tellg();
440 
441  // non-whitespace non-ascii says we're done
442  if(is.good() && (is.peek() < 32 || is.peek() > 126)) {
443  // fake eof (binary data)
444  break;
445  }
446 
447  if(is.good()) {
448  is >> readKeyword;
449  }
450  else {
451  // eof
452  break;
453  }
454  }
455 
456  return is;
457  }
458  catch(IException &e) {
459  if(is.eof() && !is.bad()) {
460  is.clear();
461  is.unget();
462  }
463 
464  istream::pos_type errorPos = is.tellg();
465  if((int)errorPos == -1) throw;
466 
467  is.seekg(0, ios::beg);
468  long lineNumber = 1;
469 
470  if((int)is.tellg() == -1) throw;
471 
472  while(is.good() && is.tellg() < errorPos) {
473  char next = is.get();
474 
475  if(!isprint(next) && !isspace(next)) {
476  is.seekg(errorPos, ios::beg);
477  }
478  else if(next == '\n') {
479  lineNumber ++;
480  }
481  }
482 
483  string msg;
484  if(lineNumber > 0) {
485  msg = "Error in PVL file on line [";
486  msg += IString((Isis::BigInt)lineNumber);
487  msg += "]";
488  }
489 
490  throw IException(e, IException::Unknown, msg, _FILEINFO_);
491  }
492  }
493 
494 
496  const Pvl &Pvl::operator=(const Pvl &other) {
497  this->PvlObject::operator=(other);
498 
499  m_internalTemplate = other.m_internalTemplate;
500  m_terminator = other.m_terminator;
501 
502  return *this;
503  }
504 
505 
515  void Pvl::validatePvl(const Pvl & pPvl, Pvl & pPvlResults)
516  {
517  pPvlResults=Pvl(pPvl);
518 
519  // Validate Objects
520  int iTmplObjSize = objects();
521 
522  for(int i=0; i<iTmplObjSize; i++) {
523  PvlObject & pvlTmplObj = object(i);
524 
525  QString sObjName = pvlTmplObj.name();
526  bool bObjFound = false;
527 
528  // Pvl contains the Object Name
529  if(pPvl.hasObject(sObjName)) {
530  PvlObject & pvlObj = pPvlResults.findObject(sObjName);
531  pvlTmplObj.validateObject(pvlObj);
532  if(pvlObj.objects()==0 && pvlObj.groups()==0 && pvlObj.keywords()==0) {
533  pPvlResults.deleteObject(sObjName);
534  }
535  bObjFound = true;
536  }
537  else {
538  QString sOption = sObjName + "__Required";
539  bObjFound = true; // optional is the default
540  if(pvlTmplObj.hasKeyword(sOption)) {
541  PvlKeyword pvlKeyOption = pvlTmplObj.findKeyword(sOption);
542  if(pvlKeyOption[0] == "true") { // Required is true
543  bObjFound = false;
544  }
545  }
546  }
547  if (bObjFound == false) {
548  QString sErrMsg = "Object \"" + sObjName + "\" Not Found in the Template File\n";
549  throw IException(IException::User, sErrMsg, _FILEINFO_);
550  }
551  }
552 
553  // Validate Groups
554  int iTmplGrpSize = groups();
555  for(int i=0; i<iTmplGrpSize; i++) {
556  PvlGroup & pvlTmplGrp = group(i);
557 
558  QString sGrpName = pvlTmplGrp.name();
559  bool bGrpFound = false;
560 
561  // Pvl contains the Object Name
562  if(pPvl.hasGroup(sGrpName)) {
563  PvlGroup & pvlGrp = pPvlResults.findGroup(sGrpName);
564  pvlTmplGrp.validateGroup(pvlGrp);
565  if(pvlGrp.keywords()==0) {
566  pPvlResults.deleteGroup(sGrpName);
567  }
568  bGrpFound = true;
569  }
570  else {
571  bGrpFound = true;
572  QString sOption = sGrpName + "__Required";
573  if(pvlTmplGrp.hasKeyword(sOption)) {
574  PvlKeyword pvlKeyOption = pvlTmplGrp.findKeyword(sOption);
575  if(pvlKeyOption[0] == "true") { // Required is true
576  bGrpFound = false;
577  }
578  }
579  }
580  if (bGrpFound == false) {
581  QString sErrMsg = "Group \"" + sGrpName + "\" Not Found in the Template File\n";
582  throw IException(IException::User, sErrMsg, _FILEINFO_);
583  }
584  }
585 
586  // Validate all the Keywords
587  validateAllKeywords((PvlContainer &)pPvlResults);
588  }
589 
590 } //end namespace isis
PvlObject & object(const int index)
Return the object at the specified index.
Definition: PvlObject.cpp:460
long long int BigInt
Big int.
Definition: Constants.h:65
int keywords() const
Returns the number of keywords contained in the PvlContainer.
Definition: PvlContainer.h:100
QString FileCreate(const QString &filename)
This error should be used when a file could not be created.
Definition: FileCreate.cpp:28
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
const PvlObject & operator=(const PvlObject &other)
This is an assignment operator.
Definition: PvlObject.cpp:792
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:141
Contains more than one keyword-value pair.
Definition: PvlContainer.h:63
File name manipulation and expansion.
Definition: FileName.h:116
void validateAllKeywords(PvlContainer &pPvlCont)
Validate All the Keywords in a Container comparing with the Template.
int objects() const
Returns the number of objects.
Definition: PvlObject.h:231
void init()
initializes the class
Definition: Pvl.cpp:62
Formats a Pvl name value pair to Isis standards.
Definition: PvlFormat.h:124
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
Definition: PvlObject.h:286
void addGroup(const Isis::PvlGroup &group)
Add a group to the object.
Definition: PvlObject.h:198
QString m_terminator
Terminator used to signify the end of the PVL informationDefaults to "END".
Definition: Pvl.h:183
Namespace for the standard library.
bool hasGroup(const QString &name) const
Returns a boolean value based on whether the object has the specified group or not.
Definition: PvlObject.h:222
void append(const QString &file)
Appends PVL information to a file and handles the end of line sequence.
Definition: Pvl.cpp:170
void addKeyword(const PvlKeyword &keyword, const InsertMode mode=Append)
Add a keyword to the container.
void validateObject(PvlObject &pPvlObj)
Validate Object.
Definition: PvlObject.cpp:812
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:162
A type of error that occurred when performing an actual I/O operation.
Definition: IException.h:171
void deleteGroup(const QString &name)
Remove a group from the current PvlObject.
Definition: PvlObject.cpp:379
void validateGroup(PvlGroup &pPvlGrp)
Validate a Group comparing with the Template Group.
Definition: PvlGroup.cpp:220
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 ...
Definition: PvlObject.cpp:207
QString m_filename
This contains the filename used to initialize the pvl object.
Definition: PvlContainer.h:297
bool hasObject(const QString &name) const
Returns a boolean value based on whether the object exists in the current PvlObject or not...
Definition: PvlObject.h:335
void addObject(const PvlObject &object)
Add a PvlObject.
Definition: PvlObject.h:319
QString name() const
Returns the container name.
Definition: PvlContainer.h:77
PvlKeyword & findKeyword(const QString &kname, FindOptions opts)
Finds a keyword in the current PvlObject, or deeper inside other PvlObjects and Pvlgroups within this...
Definition: PvlObject.cpp:148
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
std::istream & operator>>(std::istream &is, CSVReader &csv)
Input read operator for input stream sources.
Definition: CSVReader.cpp:463
A type of error that could only have occurred due to a mistake on the user&#39;s part (e...
Definition: IException.h:142
A single keyword-value pair.
Definition: PvlKeyword.h:98
A type of error that cannot be classified as any of the other error types.
Definition: IException.h:134
void validatePvl(const Pvl &pPvl, Pvl &pPvlResults)
Validate a Pvl with the Template Pvl.
Definition: Pvl.cpp:515
QString expanded() const
Returns a QString of the full file name including the file path, excluding the attributes.
Definition: FileName.cpp:212
Container for cube-like labels.
Definition: Pvl.h:135
Pvl()
Constructs an empty Pvl object.
Definition: Pvl.cpp:38
void deleteObject(const QString &name)
Remove an object from the current PvlObject.
Definition: PvlObject.cpp:337
PvlKeyword & findKeyword(const QString &name)
Find a keyword with a specified name.
const Pvl & operator=(const Pvl &other)
This is an assignment operator.
Definition: Pvl.cpp:496
PvlGroup & group(const int index)
Return the group at the specified index.
Definition: PvlObject.cpp:423
QString name() const
Returns the keyword name.
Definition: PvlKeyword.h:114
Isis exception class.
Definition: IException.h:107
Adds specific functionality to C++ strings.
Definition: IString.h:181
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
QString FileOpen(const QString &filename)
This error should be used when a file could not be opened.
Definition: FileOpen.cpp:28
int groups() const
Returns the number of groups contained.
Definition: PvlObject.h:87
void write(const QString &file)
Opens and writes PVL information to a file and handles the end of line sequence.
Definition: Pvl.cpp:116
QDebug operator<<(QDebug debug, const Hillshade &hillshade)
Print this class out to a QDebug object.
Definition: Hillshade.cpp:308
Contains Pvl Groups and Pvl Objects.
Definition: PvlObject.h:74
void read(const QString &file)
Loads PVL information from a stream.
Definition: Pvl.cpp:76
bool fileExists() const
Returns true if the file exists; false otherwise.
Definition: FileName.cpp:465
QString terminator() const
Returns the terminator used to signify the end of the PVL informationDefaults to "END".
Definition: Pvl.h:168