NitfUtilities.h

Go to the documentation of this file.
00001 /*
00002  * The information in this file is
00003  * Copyright(c) 2007 Ball Aerospace & Technologies Corporation
00004  * and is subject to the terms and conditions of the
00005  * GNU Lesser General Public License Version 2.1
00006  * The license text is available from   
00007  * http://www.gnu.org/licenses/lgpl.html
00008  */
00009 
00010 #ifndef NITFUTILITIES_H
00011 #define NITFUTILITIES_H
00012 
00013 class Classification;
00014 class DateTime;
00015 #include "DataVariant.h"
00016 #include "DynamicObject.h"
00017 #include "Endian.h"
00018 #include "NitfConstants.h"
00019 #include "NitfTreParser.h"
00020 #include "TypesFile.h"
00021 #include "StringUtilities.h"
00022 
00023 #include <iomanip>
00024 #include <iostream>
00025 #include <limits>
00026 #include <set>
00027 #include <string>
00028 #include <vector>
00029 
00030 #include <boost/lexical_cast.hpp>
00031 
00032 namespace Nitf
00033 {
00034    /**
00035     * Returns the string representation of the given RPC coefficient.
00036     *
00037     * @param prefix
00038     *        The prefix for the coefficient name.
00039     * @param num
00040     *        The coefficient number to get [1, 20].
00041     * @return string representation of the coefficient.
00042     */
00043    std::string getRpcCoefficient(const std::string& prefix, const unsigned int& num);
00044 
00045    /**
00046     * Determine the least trusted state of the provided TreStates.
00047     *
00048     * @param stateA
00049     *        The first state to compare
00050     * @param stateB
00051     *        The second state to compare
00052     *
00053     * @return The least trusted of the provided states.
00054     */
00055    TreState MaxState(TreState stateA, TreState stateB);
00056 
00057    /**
00058     * Represents getting the first instance of a tag.
00059     */
00060    struct FindFirst
00061    {
00062       bool operator()(const DynamicObject& instance)
00063       {
00064          return true;
00065       }
00066    };
00067 
00068    /**
00069     * Gets a handle to a TRE out of the NITF Metadata.
00070     *
00071     * You can provide a functor to filter out which TRE to fetch (ie. find the first
00072     * ICHIPB with an OP_COL_11 field that is valid). Example:
00073     * @code
00074     * // Get the first instance of the RPC00B TRE; assumes nitfMetadata is the NITF metadata DynamicObject
00075     * DynamicObject* pDynObj = getTagHandle(nitfMetadata, "RPC00B", FindFirst());
00076     * @endcode
00077     *
00078     * @param  nitfMetadata
00079     *         The cube's NITF metadata object.
00080     * @param  treName
00081     *         The name of the TRE.
00082     * @param  cond
00083     *         A functor that determines if the DynamicObject passed in should be fetched.
00084     *         argument is provided, gets the first instance of the tag.
00085     * @return A pointer to the tag handle of the given TRE and instance. NULL, if the
00086     *         TRE does not exist.
00087     */
00088    template<class Condition>
00089    const DynamicObject* getTagHandle(const DynamicObject& nitfMetadata,
00090       std::string treName, Condition cond = Condition())
00091    {
00092       std::string actualType;
00093 
00094       const DynamicObject* pTre = nitfMetadata.getAttribute(Nitf::TRE_METADATA).getPointerToValue<DynamicObject>();
00095       if (pTre == NULL)
00096       {
00097          return NULL;
00098       }
00099 
00100       // now get the TRE DynamicObject
00101       pTre = pTre->getAttribute(treName).getPointerToValue<DynamicObject>();
00102       if (pTre == NULL)
00103       {
00104          return NULL;
00105       }
00106 
00107       const DynamicObject* pFound = NULL;
00108       std::vector<std::string> instances;
00109       pTre->getAttributeNames(instances);
00110       for (std::vector<std::string>::const_iterator it = instances.begin(); it != instances.end(); ++it)
00111       {
00112          const DynamicObject* pObj = pTre->getAttribute(*it).getPointerToValue<DynamicObject>();
00113          if (pObj != NULL && cond(*pObj))
00114          {
00115             pFound = pObj;
00116             break;
00117          }
00118       }
00119       return pFound;
00120    }
00121 
00122    /**
00123     * Gets the sentinel value for a given field.
00124     * @return The sentinel value.
00125     */
00126    template<typename T>
00127    inline T getSentinel()
00128    {
00129       return std::numeric_limits<T>::max();
00130    }
00131 
00132    /**
00133     * Test a tag against a range
00134     *
00135     * @param reporter
00136     *        ostream to report failures to
00137     * @param testValue
00138     *        The value to test
00139     * @param minValue
00140     *        The minimum value of the range
00141     * @param maxValue
00142     *        The maximum value of the range
00143     *
00144     * @return SUSPECT if outside the range, VALID otherwise.
00145     */
00146    template<typename T>
00147    TreState testTagValueRange(std::ostream& reporter, const T& testValue, const T& minValue, const T& maxValue)
00148    {
00149       if (testValue < minValue || testValue > maxValue)
00150       {
00151          reporter << "SUSPECT field: " << testValue << " should have been between "
00152             << minValue << " and " << maxValue << ", ";
00153          return SUSPECT;
00154       }
00155 
00156       return VALID;
00157    }
00158 
00159    /**
00160     * Test a tag within a DynamicObject against a range.
00161     *
00162     * @param tre
00163     *        The DynamicObject from which to get the value.
00164     * @param reporter
00165     *        ostream To report failures.
00166     * @param pNumFields
00167     *        Number of fields currently read in by the calling parser.
00168     *        If not \c NULL, this value is incremented if the field has been read.
00169     * @param name
00170     *        The name of the tag within the DynamicObject.
00171     * @param minValue
00172     *        The minimum value of the range.
00173     * @param maxValue
00174     *        The maximum value of the range.
00175     * @param optional
00176     *        \c True if the field is considered to be optional (all spaces allowed).
00177     * @return INVALID if the tag is not found, SUSPECT if outside the range, VALID otherwise.
00178     */
00179    template<typename T>
00180    TreState testTagValueRange(const DynamicObject& tre, std::ostream& reporter, unsigned int* pNumFields,
00181       const std::string& name, const T& minValue, const T& maxValue, bool optional = false)
00182    {
00183       try
00184       {
00185          const T& testValue = dv_cast<T>(tre.getAttribute(name));
00186          TreState state = VALID;
00187          if (optional == false || getSentinel<T>() != testValue)
00188          {
00189             state = testTagValueRange(reporter, testValue, minValue, maxValue);
00190          }
00191 
00192          if (state != VALID)
00193          {
00194             reporter << ": field = " << name << ".\n";
00195          }
00196 
00197          if (pNumFields != NULL)
00198          {
00199             (*pNumFields)++;
00200          }
00201 
00202          return state;
00203       }
00204       catch (const std::bad_cast&)
00205       {
00206          reporter << "Field " << name << " not found in Dynamic Object from testTagValueRange().\n";
00207       }
00208       return INVALID;
00209    }
00210 
00211    /**
00212     * Test a tag within a DynamicObject for equivalence
00213     *
00214     * @param tre
00215     *        The DynamicObject to get the value from
00216     * @param reporter
00217     *        ostream to report failures to
00218     * @param name
00219     *        The name of the tag within the DynamicObject
00220     * @param eqValue
00221     *        The value to test equivalence against
00222     *        
00223     * @return INVALID if the tag is not found, SUSPECT if not equal, VALID otherwise.
00224     */
00225    template<typename T>
00226    TreState testTagValueEq(const DynamicObject& tre, std::ostream& reporter, const std::string& name, const T& eqValue)
00227    {
00228       try
00229       {
00230          const T& testValue = dv_cast<T>(tre.getAttribute(name));
00231          if (testValue == eqValue)
00232          {
00233             return VALID;
00234          }
00235          reporter << "Field " << name << " = " << testValue << " should have been equal to " << eqValue << ".\n";
00236          return SUSPECT;
00237       }
00238       catch (std::bad_cast e)
00239       {
00240          reporter << "Field " << name << " not found in Dynamic Object from testTagValueEq().\n";
00241          return INVALID;
00242       }
00243 
00244       return UNTESTED;
00245    }
00246 
00247    /**
00248     * Test a tag within a DynamicObject for non-equivalence
00249     *
00250     * @param tre
00251     *        The DynamicObject to get the value from
00252     * @param reporter
00253     *        ostream to report failures to
00254     * @param name
00255     *        The name of the tag within the DynamicObject
00256     * @param notEqValue
00257     *        The value to test non-equivalence against
00258     *        
00259     * @return INVALID if the tag is not found, SUSPECT if equal, VALID otherwise.
00260     */
00261    template<typename T>
00262    inline TreState testTagValueNotEq(const DynamicObject& tre, std::ostream& reporter,
00263       const std::string& name, const T& notEqValue)
00264    {
00265       try
00266       {
00267          const T& testValue = dv_cast<T>(tre.getAttribute(name));
00268          if (testValue != notEqValue)
00269          {
00270             return VALID;
00271          }
00272          reporter << "Field " << name << " = " << testValue <<
00273             " should have been not equal to " << notEqValue << ".\n";
00274          return SUSPECT;
00275       }
00276       catch (std::bad_cast e)
00277       {
00278          reporter << "Field " << name << " not found in Dynamic Object from testTagValueEq().\n";
00279          return INVALID;
00280       }
00281 
00282       return UNTESTED;
00283    }
00284 
00285    /**
00286     * Combination typecast and endian swap.
00287     *
00288     * @param pBuffer
00289     *        Buffer containing non-swapped data
00290     * @param sourceEndian
00291     *        The endianness of the data in the buffer
00292     *
00293     * @return The contents of the buffer, appropriately typed and swapped.
00294     */
00295    template<typename T>
00296    T convertBinary(const void* pBuffer, EndianType sourceEndian)
00297    {
00298       T data;
00299       Endian endian(sourceEndian);
00300       memcpy(&data, pBuffer, sizeof(T));
00301       endian.swapValue(data);
00302       return data;
00303    }
00304 
00305    /**
00306     * Test the specified bit.
00307     *
00308     * @param bitMask
00309     *        Mask to tests
00310     * @param bit
00311     *        Bit of the mask to test
00312     *
00313     * @return True if the given bit is true, false otherwise.
00314     */
00315    bool bitTest(unsigned int bitMask, unsigned int bit);
00316 
00317    /**
00318     * Parse a date-time string of the form HHMM (hour minute).
00319     *
00320     * @param fDTG
00321     *        The string to parse
00322     * @param hour
00323     *        Upon successful return, this contains the hours from the string.
00324     * @param min
00325     *        Upon successful return, this contains the minutes from the string.
00326     *
00327     * @return True if the parse succeeded, false otherwise.
00328     */
00329    bool DtgParseHHMM(const std::string& fDTG, unsigned short& hour, unsigned short& min);
00330 
00331    /**
00332     * Parse a date-time string of the form CCYYMMDDhhmm.
00333     *
00334     * @param fDTG
00335     *        The string to parse
00336     * @param year
00337     *        Upon successful return, this contains the year (including century) from the string.
00338     * @param month
00339     *        Upon successful return, this contains the month from the string.
00340     * @param day
00341     *        Upon successful return, this contains the day from the string.
00342     * @param hour
00343     *        Upon successful return, this contains the hours from the string.
00344     * @param min
00345     *        Upon successful return, this contains the minutes from the string.
00346     *
00347     * @return True if the parse succeeded, false otherwise.
00348     */
00349    bool DtgParseCCYYMMDDhhmm(const std::string& fDTG, unsigned short& year, unsigned short& month,
00350       unsigned short& day, unsigned short& hour, unsigned short& min);
00351 
00352    /**
00353     * Parse a date-time string of the form CCYYMMDDhhmm.
00354     *
00355     * @param fDTG
00356     *        The string to parse
00357     * @param pDateTime
00358     *        Upon successful return, this contains the date and time from the string.
00359     *
00360     * @return True if the parse succeeded, false otherwise.
00361     */
00362    bool DtgParseCCYYMMDDhhmm(const std::string& fDTG, DateTime* pDateTime);
00363 
00364    /**
00365     * Parse a date-time from two strings of the form CCYYMMDD and ssss.sss.
00366     *
00367     * @param date
00368     *        The date string to parse
00369     * @param time
00370     *        The time string to parse, this may have a variable number of digits but must be
00371     *        seconds of the day
00372     * @param pDateTime
00373     *        Upon successful return, this contains the date and time from the string.
00374     * @param secondsInDay
00375     *        Return the seconds in the day as a float. \em pDateTime only contains 1 second resolution
00376     *        so this is required to obtain fractional seconds. This is the value in time as a \c float.
00377     *
00378     * @return \c True if the parse succeeded, \c false otherwise.
00379     */
00380    bool DtgParseCCYYMMDDssss(const std::string& date, const std::string& time,
00381                              DateTime* pDateTime, float& secondsInDay);
00382 
00383    /**
00384     * Parse a date-time string of the form CCYYMMDDhhmmss.
00385     *
00386     * @param fDTG
00387     *        The string to parse
00388     * @param year
00389     *        Upon successful return, this contains the year (including century) from the string.
00390     * @param month
00391     *        Upon successful return, this contains the month from the string.
00392     * @param day
00393     *        Upon successful return, this contains the day from the string.
00394     * @param hour
00395     *        Upon successful return, this contains the hours from the string.
00396     * @param min
00397     *        Upon successful return, this contains the minutes from the string.
00398     * @param sec
00399     *        Upon successful return, this contains the seconds from the string.
00400     * @param pDateValid
00401     *        If non-NULL, the value pointed at will contain true if the date portion
00402     *        of the date-time string parsed successfully.
00403     * @param pTimeValid
00404     *        If non-NULL, the value pointed at will contain true if the time portion
00405     *        of the date-time string parsed successfully.
00406     *
00407     * @return True if the parse completely succeeded, false otherwise. Note
00408     *         that even if this returns false, pDateValid and pTimeValid will
00409     *         be set appropriately.
00410     */
00411    bool DtgParseCCYYMMDDhhmmss(const std::string& fDTG, unsigned short& year, unsigned short& month,
00412       unsigned short& day, unsigned short& hour, unsigned short& min, unsigned short& sec, bool* pDateValid = NULL,
00413       bool* pTimeValid = NULL);
00414 
00415    /**
00416     * Parse a date-time string of the form CCYYMMDDhhmmss.
00417     *
00418     * @param fDTG
00419     *        The string to parse
00420     * @param pDateTime
00421     *        Upon successful return, this contains the date and time from the string.
00422     *
00423     * @return True if the parse succeeded, false otherwise.
00424     *         Note that even if this returns false, pDateTime may contain partially valid data.
00425     */
00426    bool DtgParseCCYYMMDDhhmmss(const std::string& fDTG, DateTime* pDateTime);
00427 
00428    /**
00429     * Parse a date-time string of the form CCYYMMDD.
00430     *
00431     * @param fDTG
00432     *        The string to parse
00433     * @param year
00434     *        Upon successful return, this contains the year (including century) from the string.
00435     * @param month
00436     *        Upon successful return, this contains the month from the string.
00437     * @param day
00438     *        Upon successful return, this contains the day from the string.
00439     *
00440     * @return True if the parse succeeded, false otherwise.
00441     */
00442    bool DtgParseCCYYMMDD(const std::string& fDTG, unsigned short& year, unsigned short& month, unsigned short& day);
00443 
00444    /**
00445     * Parse a date-time string of the form CCYYMMDD.
00446     *
00447     * @param fDTG
00448     *        The string to parse
00449     * @param pDateTime
00450     *        Upon successful return, this contains the date and time from the string.
00451     *
00452     * @return True if the parse succeeded, false otherwise.
00453     */
00454    bool DtgParseCCYYMMDD(const std::string& fDTG, DateTime* pDateTime);
00455 
00456    /**
00457     * Parse a date-time string of the form DDMMMYY, where MMM is a three-letter
00458     * abbreviation for the month.
00459     *
00460     * @param fDTG
00461     *        The string to parse
00462     * @param year
00463     *        Upon successful return, this contains the year (including century) from the string.
00464     *        The century assumes that any two-digit year less than 48 refers to 2000 + YY, and any
00465     *        two-digit year greater than or equal to 48 refers to 1900 + YY.
00466     * @param month
00467     *        Upon successful return, this contains the 1-based month from the string.
00468     * @param day
00469     *        Upon successful return, this contains the day from the string.
00470     *
00471     * @return True if the parse succeeded, false otherwise.
00472     */
00473    bool DtgParseDDMMMYY(const std::string& fDTG, unsigned short& year, unsigned short& month, unsigned short& day);
00474 
00475    /**
00476     * Parse a date-time string of the form DDMMMYY, where MMM is a three-letter
00477     * abbreviation for the month.
00478     *
00479     * @param fDTG
00480     *        The string to parse
00481     * @param pDateTime
00482     *        Upon successful return, this contains the date and time from the string.
00483     *        The century assumes that any two-digit year less than 48 refers to 2000 + YY, and any
00484     *        two-digit year greater than or equal to 48 refers to 1900 + YY.
00485     *
00486     * @return True if the parse succeeded, false otherwise.
00487     */
00488    bool DtgParseDDMMMYY(const std::string& fDTG, DateTime* pDateTime);
00489 
00490    /**
00491     * Parse a date-time string of the form CCYYMMDDhhmmss.
00492     *
00493     * @param fDTG
00494     *        The string to parse
00495     * @param year
00496     *        Upon successful return, this contains the year (including century) from the string.
00497     * @param month
00498     *        Upon successful return, this contains the month from the string.
00499     * @param day
00500     *        Upon successful return, this contains the day from the string.
00501     * @param hour
00502     *        Upon successful return, this contains the hours from the string.
00503     * @param min
00504     *        Upon successful return, this contains the minutes from the string.
00505     * @param sec
00506     *        Upon successful return, this contains the seconds from the string.
00507     *
00508     * @return True if the parse succeeded, false otherwise.
00509     */
00510    bool DtgParseCCYYMMMDDhhmmss(const std::string& fDTG, unsigned short& year, unsigned short& month,
00511       unsigned short& day, unsigned short& hour, unsigned short& min, unsigned short& sec);
00512 
00513    /**
00514     * Parse a date-time string of the form CCYYMMDDhhmmss.
00515     *
00516     * @param fDTG
00517     *        The string to parse
00518     * @param pDateTime
00519     *        Upon successful return, this contains the date and time from the string.
00520     *
00521     * @return True if the parse succeeded, false otherwise.
00522     */
00523    bool DtgParseCCYYMMMDDhhmmss(const std::string& fDTG, DateTime* pDateTime);
00524 
00525    /**
00526     * Parse a date-time string of the form DDHHMMSSZMONYY, where MMM is a three-letter
00527     * abbreviation for the month.
00528     *
00529     * @param fDTG
00530     *        The string to parse
00531     * @param year
00532     *        Upon successful return, this contains the year (including century) from the string.
00533     *        The century assumes that any two-digit year less than 48 refers to 2000 + YY, and any
00534     *        two-digit year greater than or equal to 48 refers to 1900 + YY.
00535     * @param month
00536     *        Upon successful return, this contains the month from the string.
00537     * @param day
00538     *        Upon successful return, this contains the day from the string.
00539     * @param hour
00540     *        Upon successful return, this contains the hours from the string.
00541     * @param min
00542     *        Upon successful return, this contains the minutes from the string.
00543     * @param sec
00544     *        Upon successful return, this contains the seconds from the string.
00545     *
00546     * @return True if the parse succeeded, false otherwise.
00547     */
00548    bool DtgParseDDHHMMSSZMONYY(const std::string& fDTG, unsigned short& year, unsigned short& month,
00549       unsigned short& day, unsigned short& hour, unsigned short& min, unsigned short& sec);
00550 
00551    /**
00552     * Parse a date-time string of the form CCYYMMDDhhmmss, where MMM is a three-letter
00553     * abbreviation for the month.
00554     *
00555     * @param fDTG
00556     *        The string to parse
00557     * @param pDateTime
00558     *        Upon successful return, this contains the date and time from the string.
00559     *        The century assumes that any two-digit year less than 48 refers to 2000 + YY, and any
00560     *        two-digit year greater than or equal to 48 refers to 1900 + YY.
00561     *
00562     * @return True if the parse succeeded, false otherwise.
00563     */
00564    bool DtgParseDDHHMMSSZMONYY(const std::string& fDTG, DateTime* pDateTime);
00565 
00566    /**
00567     * Parse a date-time string of the form YYMMDD.
00568     *
00569     * @param fDTG
00570     *        The string to parse.
00571     * @param year
00572     *        Upon successful return, this contains the year (including century) from the string.
00573     *        The century assumes that any two-digit year less than 48 refers to 2000 + YY, and any
00574     *        two-digit year greater than or equal to 48 refers to 1900 + YY.
00575     * @param month
00576     *        Upon successful return, this contains the month from the string.
00577     * @param day
00578     *        Upon successful return, this contains the day from the string.
00579     *
00580     * @return True if the parse succeeded, false otherwise.
00581     */
00582    bool DtgParseYYMMDD(const std::string& fDTG, unsigned short& year, unsigned short& month, unsigned short& day);
00583 
00584    /**
00585     * Parse a date-time string of the form YYMMDD.
00586     *
00587     * @param fDTG
00588     *        The string to parse.
00589     * @param pDateTime
00590     *        Upon successful return, this contains the date from the string.
00591     *        The century assumes that any two-digit year less than 48 refers to 2000 + YY, and any
00592     *        two-digit year greater than or equal to 48 refers to 1900 + YY.
00593     *
00594     * @return True if the parse succeeded, false otherwise.
00595     */
00596     bool DtgParseYYMMDD(const std::string& fDTG, DateTime* pDateTime);
00597 
00598    /**
00599     * Test a tag to ensure valid BCS-A strings from within a set.
00600     *
00601     * @param testValue
00602     *        String to test.
00603     * @param reporter
00604     *        ostream to report errors to.
00605     * @param testSet
00606     *        Set of always allowed strings.
00607     * @param allBlankOk
00608     *        If true, it is valid to have an all blank (whitespace) string in testValue.
00609     * @param notInSetOk
00610     *        If true, it is valid to have testValue not occur in testSet.
00611     * @param emitMsgNotInSet
00612     *        If true, emit a message to reporter when testValue does not occur in testSet.
00613     *
00614     * @return This method follows these rules, in this order:
00615     *           -# If testValue occurs in testSet, returns TreState::VALID.
00616     *           -# If true is false, and testString is all blank,
00617     *                 emits a message and returns TreState::INVALID.
00618     *           -# If emitMsgNotInSet, emit a message
00619     *           -# If notInSetOk is false, returns TreState::SUSPECT.
00620     *           -# If testValue contains characters outside of BCS-A,
00621     *                 emits a message and returns TreState::INVALID.
00622     */
00623    TreState testTagValidBcsASet(const std::string& testValue, std::ostream& reporter, std::set<std::string> testSet,
00624       bool allBlankOk = false, bool notInSetOk = true, bool emitMsgNotInSet = false);
00625 
00626    /**
00627     * Test a tag to ensure valid BCS-A strings from within a set.
00628     *
00629     * @param tre
00630     *        DynamicObject to get the test value from
00631     * @param reporter
00632     *        ostream to report errors to.
00633     * @param pNumFields
00634     *        Number of fields currently read in by the calling parser.
00635     *        If not NULL, this value is incremented if the field has been read.
00636     * @param name
00637     *        The name of the test value within the DynamicObject.
00638     * @param testSet
00639     *        Set of always allowed strings.
00640     * @param allBlankOk
00641     *        If true, it is valid to have an all blank (whitespace) string in the test value.
00642     * @param notInSetOk
00643     *        If true, it is valid to have the test value not occur in testSet.
00644     * @param emitMsgNotInSet
00645     *        If true, emit a message to reporter when the test value does not occur in testSet.
00646     *
00647     * @return This method follows these rules, in this order:
00648     *           -# If testValue occurs in testSet, returns TreState::VALID.
00649     *           -# If true is false, and testString is all blank,
00650     *                 emits a message and returns TreState::INVALID.
00651     *           -# If emitMsgNotInSet, emit a message
00652     *           -# If notInSetOk is false, returns TreState::SUSPECT.
00653     *           -# If testValue contains characters outside of BCS-A,
00654     *                 emits a message and returns TreState::INVALID.
00655     */
00656    TreState testTagValidBcsASet(const DynamicObject& tre, std::ostream& reporter, unsigned int* pNumFields,
00657       const std::string& name, const std::set<std::string>& testSet, bool allBlankOk = false,
00658       bool notInSetOk = true, bool emitMsgNotInSet = false);
00659 
00660    /**
00661     * Reads a number of characters from a stream and places it in a vector of chars.
00662     *
00663     * @param  strm
00664     *         The source stream.
00665     * @param  buf
00666     *         The destination vector for the data.
00667     * @param  count
00668     *         The number of bytes to read from the stream.
00669     * @param  bStr
00670     *         TRUE if the value read will need to be a NULL-terminated string. FALSE if the data will be
00671     *         treated as binary data.
00672     * @return TRUE if the operation succeeds and the stream is good, FALSE otherwise.
00673     */
00674    bool readFromStream(std::istream& strm, std::vector<char>& buf, std::streamsize count, bool bStr = true);
00675 
00676    /**
00677     * Cleans up a string for NITF export.  It guarantees the string is characters long.
00678     * Left or right justified, as specified, if the string needs to be lengthened.
00679     *
00680     * @param  str
00681     *         The string to be cleaned up for NITF export
00682     * @param  size
00683     *         The required length of the output string.
00684     * @param  fillChar
00685     *         The character to fill with if the string needs to be lenghtened. Default is blank (' ').
00686     * @param  rightJustify
00687     *         If true then the string is right justified, left justified otherwise.
00688     * @return The output string. Guaranteed to be size characters long.
00689     */
00690    std::string sizeString(const std::string& str, unsigned int size, char fillChar = ' ', bool rightJustify = false);
00691 
00692    /**
00693     * Converts a numeric to a string.  It only works with numeric intrinsics
00694     * Guaranteed to be num characters long with a leading '-' if negative or 
00695     * a leading '+' if positive and posSign == true
00696     *
00697     * @param  num
00698     *         The numeric to be converted to a string.
00699     * @param  size
00700     *         The required length of the output string.
00701     * @param  precision
00702     *         For floating point the number of digits after the decimal point. 
00703     *         Default == -1 which means to fit in the maximum within the allocated size.
00704     * @param  fillChar
00705     *         The numeric fill character. Default == '0'.
00706     * @param  posSign
00707     *         If true then output a leading "+" if the num is positive.
00708     * @param  sciNotation
00709     *         If true then force scientific notation in the form: "+0.123456E+001"
00710     * @param  expSize
00711     *         The number of digits in the exponent (where 1 <= expSize <= 3).
00712     * @param optional
00713     *        \c True if field can be exported as optional (with placeholders) if not present initially.
00714     * @param optionalChar
00715     *        The \c char to use when filling the field with a placeholder.
00716     * @return The numeric value converted to a string. Guaranteed to be num characters 
00717     *         long with a leading '-' if negative or a leading '+' if positive and posSign == true
00718     */
00719    template<typename T>
00720    std::string toString(T num, unsigned int size, int precision = -1, char fillChar = '0', bool posSign = false,
00721       bool sciNotation = false, int expSize = 3, bool optional = false, char optionalChar = ' ')
00722    {
00723       std::stringstream   outp;
00724       std::string         outStr;
00725 
00726       if (optional == true && getSentinel<T>() == num)
00727       {
00728          outStr.resize(size, optionalChar);
00729          return outStr;
00730       }
00731 
00732       if (precision < 0)
00733       {
00734          precision = size;
00735       }
00736 
00737       if (posSign) 
00738       {
00739          outp << std::showpos;
00740       }
00741 
00742       if (fillChar == '0')
00743       {
00744          outp << std::internal;
00745       }
00746 
00747       outp << std::setfill(fillChar) << std::noboolalpha << std::setw(size);
00748 
00749       if (typeid(num) == typeid(float) || typeid(num) == typeid(double))
00750       {
00751          if (sciNotation)
00752          {
00753             // The I/O routines give us a 3 digit exponent but some TAGs require less.
00754             // The minimum size is 7, +0.0E+0. Addition digits are added to either the
00755             // precision of the mantissia or exponent. +0.0000E+000
00756             if (size < 7)
00757             {
00758                sciNotation = false;
00759             }
00760             else 
00761             {
00762                if (expSize < 1 || expSize > 3)
00763                {
00764                   // We need the abs(num) but the overloaded abs() function is ambiguous 
00765                   // in this template so use "?" operator on a known type
00766                   double ans = static_cast<double>(num);
00767                   ans = (ans >= 0 ? ans : -ans);
00768 
00769                   expSize = 3;
00770                   if (ans < 1.0E+10)
00771                   {
00772                      expSize = 1;
00773                   }
00774                   else if (ans > 1.0E-99 && ans < 1.0E+100)
00775                   {
00776                      expSize = 2;
00777                   }
00778 
00779                }
00780                int prec = size - 5 - expSize;
00781                if (prec == -1)
00782                {
00783                   prec = 1;
00784                   expSize = 1;
00785                }
00786                else if (prec == 0)
00787                {
00788                   prec = 1;
00789                   expSize = 2;
00790                }
00791 
00792                outp.setf(std::ios::uppercase);
00793                outp << std::scientific << std::setprecision(prec) << num;
00794             }
00795          }
00796 
00797          if (!sciNotation)
00798          {
00799             outp << std::fixed << std::setprecision(precision) << num;
00800          }
00801       }
00802 
00803       // char types print out as the ASCII value instead of the numeric
00804       // so cast it to an int.
00805       else if (typeid(num) == typeid(char) ||
00806          typeid(num) == typeid(unsigned char) || typeid(num) == typeid(signed char))
00807       {
00808          outp << static_cast<int>(num);
00809       }
00810 
00811       // "unsigned" vars do not print the "+" even with "showpos" 
00812       // so cast it to a signed int to force the "+" 
00813       // then use a int64 for the extra room to force it positive even 
00814       // if the sign bit was set.
00815       else if (!std::numeric_limits<T>::is_signed)
00816       {
00817          outp << static_cast<long long>(num);
00818       }
00819       else
00820       {
00821          outp << num;
00822       }
00823 
00824       // use ".str()" method instead of ">>" because ">>" left justifies 
00825       // blank filled strings whereas ".str()" works in every case
00826       outStr = outp.str();
00827 
00828       if (sciNotation)
00829       {
00830          // Find the first digit in the exponent
00831          const unsigned int eLocation = outStr.rfind("E");
00832          VERIFYRV(eLocation != std::string::npos && eLocation < outStr.length() - 2, std::string());
00833          const unsigned int exponentLocation = eLocation + 2;
00834 
00835          // If there are not enough digits, add them
00836          while (outStr.length() - exponentLocation < static_cast<unsigned int>(expSize))
00837          {
00838             outStr.insert(exponentLocation, "0");
00839          }
00840 
00841          // If there are too many digits, delete them
00842          while (outStr.length() - exponentLocation > static_cast<unsigned int>(expSize))
00843          {
00844             outStr.erase(exponentLocation, 1);
00845          }
00846       }
00847 
00848       // clamp the string length to the required size because << might have
00849       // made it too long. This will truncate the least significant digits.
00850       if (outStr.size() != size)
00851       {
00852          outStr.resize(size);
00853       }
00854 
00855       return outStr;
00856    }
00857 
00858 
00859    // General template for dealing with most types
00860    template<typename T>
00861    inline T fromBuffer(std::vector<char>& buf, bool& ok, bool allBlankOk, bool allDashesOk)
00862    {
00863       std::string trimmedString = StringUtilities::stripWhitespace(std::string(&buf.front()));
00864 
00865       // This special check must be made for signed types because boost::lexical_cast accepts
00866       // strings starting with a minus sign for unsigned types and converts them to two's complement.
00867       // See http://www.boost.org/doc/libs/1_47_0/libs/conversion/lexical_cast.htm#faq for more details.
00868       if (!std::numeric_limits<T>::is_signed)
00869       {
00870          if (trimmedString.empty() == false && trimmedString[0] == '-')
00871          {
00872             // This could be all dashes or a negative number.
00873             std::string allDashes(trimmedString.size(), '-');
00874             if (allDashesOk == false || trimmedString != allDashes)
00875             {
00876                ok = false;
00877             }
00878 
00879             return getSentinel<T>();
00880          }
00881       }
00882 
00883       try
00884       {
00885          if (trimmedString.empty() == true)
00886          {
00887             ok = allBlankOk;
00888          }
00889          else
00890          {
00891             if (allDashesOk)
00892             {
00893                std::string allDashes(trimmedString.size(), '-');
00894                if (trimmedString == allDashes)
00895                {
00896                   return getSentinel<T>();
00897                }
00898             }
00899 
00900             return boost::lexical_cast<T>(trimmedString);
00901          }
00902       }
00903       catch (boost::bad_lexical_cast e)
00904       {
00905          ok = false;
00906       }
00907 
00908       return getSentinel<T>();
00909    }
00910 
00911    // Specialization for the unusual ones
00912    template <>
00913    inline std::string fromBuffer<std::string>(std::vector<char>& buf, bool& ok, bool allBlankOk, bool allDashesOk)
00914    {
00915       std::string trimmedString = StringUtilities::stripWhitespace(std::string(&buf.front()));
00916       if (trimmedString.empty() == true)
00917       {
00918          ok = allBlankOk;
00919       }
00920 
00921       return trimmedString;
00922    }
00923 
00924    // create the error message
00925    inline bool readFieldErrMsg(std::string& msg, const std::string& name, const std::vector<char>& buf, int len)
00926    {
00927       std::string value;
00928       value.resize(len);
00929       strcpy(&value[0], &buf[0]);
00930 
00931       msg += "NITF Parse TAG Error: " + name + " = " + value + "\n";
00932       return true;
00933    }
00934 
00935    //
00936    inline bool numReadErrMsg(int64_t numRead, int64_t numBytes, std::string& errorMessage)
00937    {
00938       std::string numB;
00939       std::string numR;
00940 
00941       try
00942       {
00943          numR = boost::lexical_cast<std::string>(numRead);
00944          numB = boost::lexical_cast<std::string>(numBytes);
00945       }
00946       catch (boost::bad_lexical_cast e)
00947       {
00948       }
00949 
00950       if (numRead < 0)
00951       {
00952          errorMessage += "Read past end of data. Should have read " + numB + " bytes.\n";
00953       }
00954       else
00955       {
00956          errorMessage += "Read " + numR + " bytes. Should have read " + numB + " bytes.\n";
00957       }
00958 
00959       return true;
00960    }
00961 
00962    template<typename T>
00963    inline bool readField(std::istream& input, DynamicObject& output, bool& success,
00964       const std::string& name, int len, std::string& msg, std::vector<char>& buf,
00965       bool allBlankOk = false, bool allDashesOk = false)
00966    {
00967       bool ok(true);
00968       if (input.good() == false)
00969       {
00970          success = false;
00971       }
00972       else if (readFromStream(input, buf, len) == false)
00973       {
00974          success = false;
00975       }
00976       else
00977       {
00978          T value = fromBuffer<T>(buf, ok, allBlankOk, allDashesOk);
00979          if (ok == false || output.setAttribute(name, value) == false)
00980          {
00981             success = false;
00982             readFieldErrMsg(msg, name, buf, len);
00983          }
00984       }
00985 
00986       return success;
00987    }
00988 
00989    template<typename T>
00990    inline bool readAndConvertFromStream(std::istream& input, T& output, bool& success,
00991       const std::string& name, int len, std::string& msg, std::vector<char>& buf,
00992       bool allBlankOk = false, bool allDashesOk = false)
00993    {
00994       bool ok(true);
00995       if (!input.good())
00996       {
00997          success = false;
00998       }
00999       else if (!readFromStream(input, buf, len))
01000       {
01001          success = false;
01002       }
01003       else
01004       {
01005          output = fromBuffer<T>(buf, ok, allBlankOk, allDashesOk);
01006          if (!ok)
01007          {
01008             success = false;
01009             readFieldErrMsg(msg, name, buf, len);
01010          }
01011       }
01012 
01013       return success;
01014    }
01015 
01016    /**
01017     * Determines whether a Classification object is valid for export to a NITF 2.1 file.
01018     *
01019     * @param  classification
01020     *         The Classification object to validate.
01021     *
01022     * @param  errorMessage
01023     *         An error message indicating the nature of the problem.
01024     *
01025     * @return True if the given object is valid for NITF 2.1 export, false otherwise.
01026     */
01027    bool isClassificationValidForExport(const Classification& classification, std::string& errorMessage);
01028 
01029    /**
01030     * Determines whether a classification field is valid for export to a NITF 2.1 file.
01031     *
01032     * @param  classification
01033     *         The Classification object to validate.
01034     *
01035     * @param  fieldName
01036     *         The name of the field to validate.
01037     *
01038     * @return True if the given field is valid for NITF 2.1 export, false otherwise.
01039     */
01040    bool isClassificationFieldValidForExport(const Classification& classification, const std::string& fieldName);
01041 
01042    /**
01043     * Updates band information in the special metadata, computing start,
01044     * center, and end wavelengths from the given data if possible.
01045     *
01046     * @param  pMetadata
01047     *         The metadata to update.
01048     *
01049     * @param  centerWavelengths
01050     *         The center wavelengths to write or an empty vector if center wavelengths are unknown.
01051     *
01052     * @param  startWavelengths
01053     *         The start wavelengths to write or an empty vector if start wavelengths are unknown.
01054     *
01055     * @param  endWavelengths
01056     *         The end wavelengths to write or an empty vector if end wavelengths are unknown.
01057     *
01058     * @param  fwhms
01059     *         The FWHM for each band or an empty vector if FWHMs are unknown.
01060     *
01061     * @param  convertFromInverseCentimeters
01062     *         \c True if all data is in inverse centimeters, \c false if all data is in microns.
01063     *
01064     * @return \c True on success, \c false otherwise.
01065     */
01066    bool updateSpecialMetadata(DynamicObject* pMetadata, std::vector<double>& centerWavelengths,
01067       std::vector<double>& startWavelengths, std::vector<double>& endWavelengths,
01068       const std::vector<double>& fwhms, bool convertFromInverseCentimeters = false);
01069 }
01070 
01071 #endif

Software Development Kit - Opticks 4.9.0 Build 16218