USGS

Isis 3.0 Object Programmers' Reference

Home

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.toAscii().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.toAscii().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.toAscii().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