USGS

Isis 3.0 Object Programmers' Reference

Home

PvlFormat.cpp

Go to the documentation of this file.
00001 
00023 #include "IException.h"
00024 #include "IString.h"
00025 #include "Message.h"
00026 #include "FileName.h"
00027 #include "PvlKeyword.h"
00028 #include "TextFile.h"
00029 #include "Pvl.h"
00030 #include "PvlFormat.h"
00031 
00032 using namespace std;
00033 
00034 namespace Isis {
00035 
00036   /*
00037   * Constructs an empty PvlFormat
00038   */
00039   PvlFormat::PvlFormat() {
00040     Init();
00041   }
00042 
00043 
00044   /*
00045   * Constructs a PvlFormat using the file name to ingest as the keyword to type
00046   * mapping. This is provided as a convience for child objects. The map is not
00047   * used for output of PvlKeywords in Normal Isis format.
00048   *
00049   * @param file A file name with keyword=type. Where KEYWORD is the name of a
00050   * keyword in this PvlKeyword and TYPE is one of [QString | integer | float ]
00051   */
00052   PvlFormat::PvlFormat(const QString &file) {
00053     Init();
00054     Add(file);
00055   }
00056 
00057 
00058   /*
00059   * Constructs a PvlFormat using the specified pre populated Pvl map of keyword
00060   * name (QString) vs keyword type (KeywordType).
00061   *
00062   * @param keywordType A Pvl with keyword=type. Where keyword is the name of a
00063   * keyword in a PvlKeyword and type is one of [QString | integer | float ]
00064   */
00065   PvlFormat::PvlFormat(Pvl &keywordType) {
00066     Init();
00067     Add(keywordType);
00068   }
00069 
00070 
00072   void PvlFormat::Init() {
00073     p_keywordMap.Clear();
00074     p_keywordMapFile.clear();
00075     p_charLimit = 80;
00076   }
00077 
00078 
00079   /*
00080   * Add the contents of a file to the keyword type mapping. The file should
00081   * contain KEYWORD=TYPE (one per line), where TYPE is one of the QStrings
00082   * KeywordType can convert.
00083   */
00084   void PvlFormat::Add(const QString &file) {
00085     p_keywordMapFile = file;
00086 
00087     // Open the file and internalize it into the Pvl map
00088     try {
00089       Pvl pvl(file);
00090       Add(pvl);
00091     }
00092     catch(IException &e) {
00093       QString msg;
00094       msg += "Unable to open or read keyword to type mapping file [";
00095       msg += file + "]";
00096       throw IException(e, IException::Programmer, msg, _FILEINFO_);
00097     }
00098   }
00099 
00100 
00101   /*
00102   * Add the contents of a Pvl to the keyword type mapping. The pvl should
00103   * contain KEYWORD=TYPE, where TYPE is one of the QStrings KeywordType can
00104   * convert.
00105   */
00106   void PvlFormat::Add(Pvl &pvl) {
00107     for(int i = 0; i < pvl.Keywords(); ++i) {
00108       PvlKeyword &key = pvl[i];
00109       QString name = key.Name().toUpper();
00110       QString type = key[0].toUpper();
00111       PvlKeyword newKey(name, type);
00112       for(int j = 1; j < key.Size(); ++j) newKey.AddValue(key[j]);
00113       // Make sure we don't duplicate Keys
00114       if (p_keywordMap.HasKeyword(name)) {
00115         p_keywordMap.DeleteKeyword(name);
00116       }
00117       p_keywordMap.AddKeyword(newKey);
00118     }
00119   }
00120 
00121 
00122   /*
00123   * Returns the type of the keyword from the supplied map if any
00124   *
00125   * @param keyword The PvlKeyword to have its type returned
00126   */
00127   KeywordType PvlFormat::Type(const PvlKeyword &keyword) {
00128     QString name = keyword.Name().toUpper();
00129     if(p_keywordMap.HasKeyword(name)) {
00130       PvlKeyword &key = p_keywordMap.FindKeyword(name);
00131       return ToKeywordType(key[0]);
00132     }
00133     return NoTypeKeyword;
00134   }
00135 
00136 
00137   /*
00138   * Returns the number of digits of accuracy (right of decimal place) this
00139   * keyword should be output with
00140   *
00141   * @param keyword The PvlKeyword the accuracy is need for
00142   * @return The number of decimal places to be output. If this number is not
00143   *         available in keyword map return -1.
00144   */
00145   int PvlFormat::Accuracy(const PvlKeyword &keyword) {
00146     QString name = keyword.Name().toUpper();
00147     if(p_keywordMap.HasKeyword(name)) {
00148       PvlKeyword &key = p_keywordMap.FindKeyword(name);
00149       if(key.Size() > 1) {
00150         return toInt(key[1]);
00151       }
00152     }
00153     return -1;
00154   }
00155 
00156 
00157   /*
00158   * Returns the keyword name and value(s) formatted in "Normal" Isis format
00159   *
00160   * @param keyword The PvlKeyword to be formatted
00161   * @param num Use the ith value of the keyword
00162   */
00163   QString PvlFormat::FormatValue(const PvlKeyword &keyword, int num) {
00164 
00165     QString val;
00166     val.clear();
00167 
00168     // Find out if the units are the same for all values
00169     bool singleUnit = IsSingleUnit(keyword);
00170 
00171     // Create a Null value if the value index is greater than the number of values
00172     if(num >= keyword.Size()) {
00173       return "Null";
00174     }
00175 
00176     // Create a Null value if the requested index is an empty QString
00177     if(keyword[num].size() == 0) {
00178       val += "Null";
00179     }
00180     else {
00181       val += keyword[num];
00182     }
00183 
00184     val = AddQuotes(val);
00185 
00186     // If it is an array start it off with a paren
00187     if((keyword.Size() > 1) && (num == 0)) {
00188       val = "(" + val;
00189     }
00190 
00191     // Add the units to this value
00192     if((!singleUnit) && (keyword.Unit(num).size() > 0)) {
00193       val += " <" + keyword.Unit(num) + ">";
00194     }
00195 
00196     // Add a comma for arrays
00197     if(num != keyword.Size() - 1) {
00198       val += ", ";
00199     }
00200     // If it is an array close it off
00201     else if(keyword.Size() > 1) {
00202       val += ")";
00203     }
00204 
00205     // Add the units to the end if all values have the same units
00206     if((singleUnit) && (num == keyword.Size() - 1) &&
00207         (keyword.Unit(num).size() > 0)) {
00208       val += " <" + keyword.Unit(num) + ">";
00209     }
00210 
00211     return val;
00212   }
00213 
00214 
00215   /*
00216   * Format the name of the container
00217   *
00218   * @param keyword The PvlContainer being closed.
00219   */
00220   QString PvlFormat::FormatName(const PvlKeyword &keyword) {
00221     return keyword.Name();
00222   }
00223 
00224 
00225   /*
00226   * Format the end of a container
00227   *
00228   * @param name The text used to signify the end of a container
00229   * @param keyword The PvlContainer being closed.
00230   */
00231   QString PvlFormat::FormatEnd(const QString name,
00232                                    const PvlKeyword &keyword) {
00233     return "End_" + FormatName(keyword);
00234   };
00235 
00236 
00237   /*
00238   * Add single or double quotes around a value if necessary. The Isis definition
00239   * of when quotes are necessary is used.
00240   *
00241   * @param value The PvlKeyword value to be quoted if necessary.
00242   */
00243   QString PvlFormat::AddQuotes(const QString value) {
00244     QString val = value;
00245 
00246     bool needQuotes = false;
00247 
00248     // find out if we need quotes and what kind of quotes might already exist
00249     char existingQuoteType = '\0';
00250     for(int pos = 0; !needQuotes && pos < val.size(); pos++) {
00251       // check for values indicating we need quotes, if we have a sequence
00252       //   it should already be properly quoted...
00253       if(pos == 0) {
00254         if(val[pos] == '(' && val[val.size() - 1] == ')') break;
00255         if(val[pos] == '{' && val[val.size() - 1] == '}') break;
00256       }
00257 
00258       if(val[pos] == ' ' || val[pos] == '(' ||
00259           val[pos] == '(' || val[pos] == ')' ||
00260           val[pos] == '{' || val[pos] == '}' ||
00261           val[pos] == ',') {
00262         needQuotes = true;
00263       }
00264 
00265       if(pos == val.size() - 1 && val[pos] == '-')
00266         needQuotes = true;
00267 
00268       // remember if we are a quote, what quote type we are
00269       if(existingQuoteType == '\0') {
00270         if(val[pos] == '"') {
00271           existingQuoteType = '"';
00272         }
00273         else if(val[pos] == '\'') {
00274           existingQuoteType = '\'';
00275         }
00276       }
00277       else {
00278         // make sure we dont have mixing of our outside quote type
00279         if(val[pos] == '"' || val[pos] == '\'') {
00280           val[pos] = existingQuoteType;
00281         }
00282       }
00283     }
00284 
00285     // figure out what kind of quotes we want to add
00286     char quoteValue = '"';
00287 
00288     if(existingQuoteType == '"') {
00289       quoteValue = '\'';
00290     }
00291 
00292     if(needQuotes) {
00293       val = quoteValue + val + quoteValue;
00294     }
00295 
00296     return val;
00297   }
00298 
00299 
00306   bool PvlFormat::IsSingleUnit(const PvlKeyword &keyword) {
00307 
00308     // See if the units are all the same
00309     bool singleUnit = true;
00310     for(int i = 0; i < keyword.Size(); i ++) {
00311       if(!keyword.StringEqual(keyword.Unit(i), keyword.Unit(0))) {
00312         singleUnit = false;
00313       }
00314     }
00315 
00316     return singleUnit;
00317   }
00318 }
00319