Isis 3 Programmer Reference
PvlTokenizer.cpp
Go to the documentation of this file.
1 
22 #include "PvlTokenizer.h"
23 
24 #include <sstream>
25 #include <fstream>
26 
27 #include <QDebug>
28 
29 #include "IException.h"
30 #include "IString.h"
31 #include "Message.h"
32 
33 using namespace std;
34 namespace Isis {
35 
37  PvlTokenizer::PvlTokenizer() {
38  Clear();
39  }
40 
42  PvlTokenizer::~PvlTokenizer() {
43  Clear();
44  }
45 
47  void PvlTokenizer::Clear() {
48  tokens.clear();
49  }
50 
63  void PvlTokenizer::Load(std::istream &stream, const QString &terminator) {
64  QString upTerminator(terminator.toUpper());
65  QString s;
66  int c;
67  bool newlineFound = false;
68 
69  while(true) {
70  newlineFound = SkipWhiteSpace(stream);
71  c = stream.peek();
72  ValidateCharacter(c);
73  if(c == EOF) return;
74 
75  if(c == '#') {
76  s = ReadComment(stream);
77  Isis::PvlToken t("_COMMENT_");
78  t.addValue(s);
79 
80  if(newlineFound || tokens.size() == 0 || tokens[tokens.size()-1].valueSize() == 0) {
81  // applies to next pvl item
82  tokens.push_back(t);
83  }
84  else {
85  // applies to previous pvl item
86  tokens.push_back(tokens[tokens.size()-1]);
87  tokens[tokens.size()-2] = t;
88  }
89 
90  continue;
91  }
92 
93  if(c == '/') {
94  c = stream.get();
95  c = stream.peek();
96  stream.unget();
97  ValidateCharacter(c);
98  if(c == '*') {
99  s = ReadComment(stream);
100  Isis::PvlToken t("_COMMENT_");
101  t.addValue(s);
102 
103  if(newlineFound || tokens.size() == 0 || tokens[tokens.size()-1].valueSize() == 0) {
104  // applies to next pvl item
105  tokens.push_back(t);
106  }
107  else {
108  // applies to previous pvl item
109  tokens.push_back(tokens[tokens.size()-1]);
110  tokens[tokens.size()-2] = t;
111  }
112 
113  continue;
114  }
115  }
116 
117  s = ReadToken(stream);
118  Isis::PvlToken t(s);
119 
120  if(t.keyUpper() == upTerminator) {
121  tokens.push_back(t);
122  return;
123  }
124 
125  SkipWhiteSpace(stream);
126  c = stream.peek();
127  ValidateCharacter(c);
128  if(c == EOF) {
129  tokens.push_back(t);
130  return;
131  }
132 
133  if(c != '=') {
134  tokens.push_back(t);
135  if(t.keyUpper() == upTerminator) return;
136  continue;
137  }
138 
139  stream.ignore();
140  SkipWhiteSpace(stream);
141 
142  c = stream.peek();
143  ValidateCharacter(c);
144  if(c == EOF) {
145  tokens.push_back(t);
146  return;
147  }
148 
149  if(c == '(') {
150  stream.ignore();
151  try {
152  s = ReadToParen(stream);
153  ParseCommaList(t, s);
154  }
155  catch(IException &e) {
156  QString message = Isis::Message::KeywordValueBad(t.key());
157  throw IException(e, IException::Unknown, message, _FILEINFO_);
158  }
159  tokens.push_back(t);
160  continue;
161  }
162 
163  if(c == '{') {
164  stream.ignore();
165  try {
166  s = ReadToBrace(stream);
167  ParseCommaList(t, s);
168  }
169  catch(IException &e) {
170  QString message = Isis::Message::KeywordValueBad(t.key());
171  throw IException(e, IException::Unknown, message, _FILEINFO_);
172  }
173  tokens.push_back(t);
174  continue;
175  }
176 
177  if(c == '"') {
178  stream.ignore();
179  try {
180  s = ReadToDoubleQuote(stream);
181  }
182  catch(IException &e) {
183  QString message = Isis::Message::KeywordValueBad(t.key());
184  throw IException(e, IException::Unknown, message, _FILEINFO_);
185  }
186  t.addValue(s);
187  tokens.push_back(t);
188  continue;
189  }
190 
191  if(c == '\'') {
192  stream.ignore();
193  try {
194  s = ReadToSingleQuote(stream);
195  }
196  catch(IException &e) {
197  QString message = Isis::Message::KeywordValueBad(t.key());
198  throw IException(IException::Unknown, message, _FILEINFO_);
199  }
200  t.addValue(s);
201  tokens.push_back(t);
202  continue;
203  }
204 
205 
206  s = ReadToken(stream);
207  t.addValue(s);
208  tokens.push_back(t);
209  continue;
210  }
211  }
212 
220  QString PvlTokenizer::ReadComment(std::istream &stream) {
221  QString s;
222  int c;
223 
224  c = stream.get();
225  while((c != '\r') && (c != '\n') && (c != '\0')) {
226  s += (char) c;
227  c = stream.peek();
228  ValidateCharacter(c);
229  if(c == EOF) return s;
230  c = stream.get();
231  }
232 
233  stream.unget();
234 
235  return s;
236  }
237 
248  QString PvlTokenizer::ReadToken(std::istream &stream) {
249  QString s;
250  int c;
251 
252  c = stream.get();
253  while((!isspace(c)) && (c != '\0') && (c != '=')) {
254  s += (char) c;
255  c = stream.peek();
256  ValidateCharacter(c);
257  if(c == EOF) return s;
258  c = stream.get();
259  }
260 
261  stream.unget();
262 
263  return s;
264  }
265 
272  bool PvlTokenizer::SkipWhiteSpace(std::istream &stream) {
273  bool foundNewline = false;
274  int c;
275 
276  c = stream.peek();
277  ValidateCharacter(c);
278  while((isspace(c)) || (c == '\0')) {
279  if(c == '\n') {
280  foundNewline = true;
281  }
282 
283  c = stream.get();
284  c = stream.peek();
285  ValidateCharacter(c);
286  }
287 
288  return foundNewline;
289  }
290 
291 
292  QString PvlTokenizer::ReadToDoubleQuote(std::istream &stream) {
293  QString s;
294  int c;
295 
296  do {
297  c = stream.get();
298  ValidateCharacter(c);
299  if(c == EOF) {
300  QString message = Isis::Message::MissingDelimiter('"', s);
301  throw IException(IException::Unknown, message, _FILEINFO_);
302  }
303  else if(c != '"') {
304  s += (char) c;
305  }
306  }
307  while(c != '"');
308 
309  int pos = s.indexOf(QRegExp("[\\n\\r]"));
310  while(pos != -1) {
311  QString first = s.mid(0, pos);
312  bool addspace = false;
313  if(first[pos-1] == ' ') addspace = true;
314  first = first.remove(QRegExp("[\\s]*$"));
315  QString second = s.mid(pos + 1);
316  if(second[0] == ' ') addspace = true;
317  if(second[0] == '\r') addspace = true;
318  if(second[0] == '\n') addspace = true;
319  second = second.remove(QRegExp("^[\\s]*"));
320  if(second[0] == ',') addspace = false;
321  s = first;
322  if(addspace) s += " ";
323  s += second;
324 
325  pos = s.indexOf(QRegExp("[\\n\\r]"));
326  }
327  return s;
328  }
329 
330  QString PvlTokenizer::ReadToSingleQuote(std::istream &stream) {
331  QString s;
332  int c;
333 
334  do {
335  c = stream.get();
336  ValidateCharacter(c);
337  if(c == EOF) {
338  QString message = Isis::Message::MissingDelimiter('\'', s);
339  throw IException(IException::Unknown, message, _FILEINFO_);
340  }
341  else if(c != '\'') {
342  s += (char) c;
343  }
344  }
345  while(c != '\'');
346 
347  int pos = s.indexOf(QRegExp("[\\n\\r]"));
348  while(pos != -1) {
349  QString first = s.mid(0, pos);
350  bool addspace = false;
351  if(first[pos-1] == ' ') addspace = true;
352  first = first.remove(QRegExp("[\\s]*$"));
353  QString second = s.mid(pos + 1);
354  if(second[0] == ' ') addspace = true;
355  if(second[0] == '\r') addspace = true;
356  if(second[0] == '\n') addspace = true;
357  second = second.remove(QRegExp("^[\\s]*"));
358  if(second[0] == ',') addspace = false;
359  s = first;
360  if(addspace) s += " ";
361  s += second;
362  pos = s.indexOf(QRegExp("[\\n\\r]"));
363  }
364 
365  return s;
366  }
367 
368  QString PvlTokenizer::ReadToParen(std::istream &stream) {
369  QString s;
370  int c;
371  int leftParenCount = 1;
372 
373  do {
374  c = stream.get();
375  ValidateCharacter(c);
376  if(c == EOF) {
377  QString message = Isis::Message::MissingDelimiter(')', s);
378  throw IException(IException::Unknown, message, _FILEINFO_);
379  }
380  else if(c == '"') {
381  try {
382  s += "\"" + ReadToDoubleQuote(stream) + "\"";
383  }
384  catch(IException &) {
385  QString message = Isis::Message::MissingDelimiter('"', s);
386  throw IException(IException::Unknown, message, _FILEINFO_);
387  }
388  }
389  else if(c == '\'') {
390  try {
391  s += "'" + ReadToSingleQuote(stream) + "'";
392  }
393  catch(IException &) {
394  QString message = Isis::Message::MissingDelimiter('\'', s);
395  throw IException(IException::Unknown, message, _FILEINFO_);
396  }
397  }
398  else if(c == ')') {
399  leftParenCount--;
400  if(leftParenCount > 0) s += (char) c;
401  }
402  else {
403  s += (char) c;
404  if(c == '(') leftParenCount++;
405  }
406  }
407  while(leftParenCount > 0);
408 
409  return s;
410  }
411 
412  QString PvlTokenizer::ReadToBrace(std::istream &stream) {
413  QString s;
414  int c;
415  int leftBraceCount = 1;
416 
417  do {
418  c = stream.get();
419  ValidateCharacter(c);
420  if(c == EOF) {
421  QString message = Isis::Message::MissingDelimiter('}', s);
422  throw IException(IException::Unknown, message, _FILEINFO_);
423  }
424  else if(c == '"') {
425  try {
426  s += "\"" + ReadToDoubleQuote(stream) + "\"";
427  }
428  catch(IException &e) {
429  QString message = Isis::Message::MissingDelimiter('"', s);
430  throw IException(IException::Unknown, message, _FILEINFO_);
431  }
432  }
433  else if(c == '\'') {
434  try {
435  s += "'" + ReadToSingleQuote(stream) + "'";
436  }
437  catch(IException &) {
438  QString message = Isis::Message::MissingDelimiter('\'', s);
439  throw IException(IException::Unknown, message, _FILEINFO_);
440  }
441  }
442  else if(c == '}') {
443  leftBraceCount--;
444  if(leftBraceCount > 0) s += (char) c;
445  }
446  else {
447  s += (char) c;
448  if(c == '{') leftBraceCount++;
449  }
450  }
451  while(leftBraceCount > 0);
452 
453  return s;
454  }
455 
464  void PvlTokenizer::ParseCommaList(Isis::PvlToken &t, const QString &cl) {
465  stringstream stream(cl.toLatin1().data());
466  int c;
467  QString s;
468 
469  do {
470  SkipWhiteSpace(stream);
471  c = stream.get();
472  if(c == '"') {
473  s += ReadToDoubleQuote(stream);
474  }
475  else if(c == '\'') {
476  s += ReadToSingleQuote(stream);
477  }
478  else if(c == '(') {
479  s += "(";
480  s += ReadToParen(stream);
481  s += ")";
482  }
483  else if(c == '{') {
484  s += "{";
485  s += ReadToBrace(stream);
486  s += "}";
487  }
488  else if(c == ',') {
489  t.addValue(s);
490  s.clear();
491  }
492  else if(c != EOF) {
493  s += (char) c;
494  }
495  }
496  while(c != EOF);
497 
498  t.addValue(s);
499  }
500 
501 
502  vector<Isis::PvlToken> & PvlTokenizer::GetTokenList() {
503  return tokens;
504  }
505 
511  void PvlTokenizer::ValidateCharacter(int c) {
512  if(c == EOF) return;
513  if(isprint(c)) return;
514  if(isspace(c)) return;
515  if(c == '\0') return;
516 
517  QString message = "ASCII data expected but found unprintable (binary) data";
518  throw IException(IException::Unknown, message, _FILEINFO_);
519  }
520 } // end namespace isis
QString KeywordValueBad(const QString &key)
This error should be used when a supplied keyword does not appear in the list (e.g., an Isis cube label).
Namespace for the standard library.
void addValue(const QString &v)
Adds a value to the value-vector.
Definition: PvlToken.cpp:97
QString key() const
Returns the token keyword.
Definition: PvlToken.cpp:64
Container for Keyword-value pair.
Definition: PvlToken.h:54
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
Isis exception class.
Definition: IException.h:107
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
QString keyUpper() const
Returns the token keyword in all uppercase characters.
Definition: PvlToken.cpp:73
QString MissingDelimiter(const char delimiter)
This error should be used when a delimiter is missing.