00001 // vil_nitf2: Written by Harry Voorhees (hlv@) and Rob Radtke (rob@) of 00002 // Stellar Science Ltd. Co. (stellarscience.com) for 00003 // Air Force Research Laboratory, 2005. 00004 00005 #ifndef VIL_NITF2_TAGGED_RECORD_H 00006 #define VIL_NITF2_TAGGED_RECORD_H 00007 00008 #include <vcl_list.h> 00009 #include <vcl_vector.h> 00010 // not used? #include <vcl_map.h> 00011 // not used? #include <vcl_set.h> 00012 #include <vcl_iostream.h> 00013 // not used? #include <vcl_sstream.h> 00014 #include <vcl_string.h> 00015 // not used? #include <vcl_istream.h> 00016 #include <vcl_ostream.h> 00017 00018 #include "vil_nitf2_field_functor.h" 00019 #include "vil_nitf2_field.h" 00020 00021 // Forward declarations 00022 class vil_nitf2_field_formatter; 00023 class vil_nitf2_tagged_record; 00024 class vil_nitf2_tagged_record_definition; 00025 class vil_nitf2_integer_formatter; 00026 class vil_nitf2_string_formatter; 00027 class vil_nitf2_index_vector; 00028 class vil_nitf2_scalar_field; 00029 00030 // Overview of NITF tagged record code 00031 // 00032 // This code is used to define and read National Imagery Transmission 00033 // Format (NITF) tagged record extensions (TREs), also known as 00034 // controlled extensions. It is intended to eventually support 00035 // writing and verifying TREs also. 00036 // 00037 // A TRE is stored as a sequence of ASCII fields, each of a vcl_fixed length, 00038 // that are appended together without any tag names or delimiters. Some 00039 // fields' existence depends on the values of previous fields; other 00040 // fields are repeated by a value of a previous field. The TRE definition 00041 // code allows the programmer to specify such conditions, and the NITF 00042 // file reader evaluates such conditions as it parses the file. 00043 // 00044 // The classes that represent TRE definitions were designed so that a 00045 // programmer can succinctly define a TRE in a format similar to the 00046 // tables that appear in the NITF documentation. This was felt to be 00047 // important goal to help reduce errors, since NITF TREs can contain 00048 // hundred of fields, and many users will need to define their own TRE's 00049 // depending on their application and environment. 00050 // 00051 // Here an example that implements part of the definition of TRE "MTIRPB" 00052 // from NIMA STDI-0002 version 2.1: 00053 // 00054 // vil_nitf2_tagged_record_definition::define("MTIRPB", fields() 00055 // 00056 // .field("MTI_DP", "Destination Point", NITF_INT(2)) 00057 // .field("DATIME", "Scan Date & Time", NITF_DAT(14)) 00058 // .field("ACFT_LOC", "Aircraft Position", NITF_LOC(21)) 00059 // .field("SQUINT_ANGLE", "Squint Angle", NITF_DBL(6, 2, true), true) 00060 // .field("NO_VALID_TARGETS", "Number of Targets", NITF_INT(3)) 00061 // 00062 // .repeat("NO_VALID_TARGETS", fields() 00063 // 00064 // .field("TGT_n_SPEED", "Target Ground Speed", NITF_INT(4), true) 00065 // .field("TGT_n_CAT", "Target Classification Category", 00066 // NITF_ENUM(1, vil_nitf2_enum_values() 00067 // .value("H", "Helicopter") 00068 // .value("T", "Tracked") 00069 // .value("U", "Unknown") 00070 // .value("W", "Wheeled")), 00071 // true)) 00072 // 00073 // .field("TEST_POS_COND", "Test True Condition", NITF_STR_BCSA(14), false, 00074 // NitfGreaterThan<int>("MTI_DP", 1)) 00075 // .end(); 00076 // 00077 // A TaggedRecordDefintion consists of the TRE's name (here, "MTIRPB") 00078 // and an ordered list of FieldDefinitions. Each field definition is 00079 // specified by these arguments to method "field" above: tag, 00080 // pretty_name, format; followed by optional arguments: value_optional, 00081 // repeat_count, condition, units, description. 00082 // 00083 // In this example the first field is a two-digit integer; the second a 00084 // is a date-time structure, specified to 14 "digits" precision 00085 // (YYYYMMDDHHMMSS); the next field is a location specified as 21 00086 // characters, stored either as a latitude-longitude pair of decimal 00087 // degrees or deg/min/sec/hemisphere (depending on the TRE, various 00088 // formats are allowed, sometimes with variable precision). The next 00089 // field, SQUINT_ANGLE, is a vcl_fixed-point decimal number stored using 6 00090 // characters, including 2 decimal places and a sign. The "true" 00091 // following the empty "units" argument indicates that field 00092 // SQUINT_ANGLE's value is optional, i.e., the field may be blank. Unless 00093 // a value is defined as optional, the parser will issue a warning in 00094 // such cases (although it will continue parsing the rest of the TRE if 00095 // possible). 00096 // 00097 // The next field, NO_VALID_TARGETS, is an integer field. This is followed 00098 // by a repeating integer field, TGT_n_SPEED; the last argument of its 00099 // definition indicates that TGT_n_SPEED is repeated by the value of field 00100 // NO_VALID_TARGETS. The code here represents TGT_n_SPEED as a single field 00101 // whose value is a vcl_vector of integer pointers. The reason for using 00102 // pointers is in case some of the field values are blank; for such entries, 00103 // the corresponding vcl_vector element is null. 00104 // 00105 // The next field, TGT_n_CAT, is a repeating enumerated string field, whose 00106 // valid values are "H", "T", "U", "W", and blank. 00107 // 00108 // The final field, TEST_POS_COND, is a conditional field. It exists if 00109 // and only if its condition is satisfied; in this case, if the value of 00110 // field MTI_DP is greater than 1. Conditional fields along with 00111 // repeating fields therefore cause instances of a TRE to vary in length. 00112 // 00113 // That summarizes how TRE's are defined. Some possible extensions in the 00114 // future include value range checks and the ability to specify which formats 00115 // among a set of alternatives (such as geolocation) are allowed. 00116 // 00117 // When a TRE is defined, it is added to a dictionary of known TREs that 00118 // is used to read (and eventually to write) NITF files. As a NITF file 00119 // is read in, at the start of a TRE the tag and length of the TRE are read. 00120 // If the tag is recognized, its data is parsed into field using tag 00121 // definition, creating a TaggedRecord. If not, the tag's data is skipped 00122 // over (according to its declared length) and the next tag is processed. 00123 // 00124 // Values of NITF fields are passed back to the application as built-in 00125 // types and as NITF structure types. Built-in types include integer, 00126 // double (used to represent all vcl_fixed-point decimal fields), string, and 00127 // character. NITF structure types include date_time and Location. 00128 // 00129 // Here is an overview of the class hierarchy: 00130 // 00131 // vil_nitf2_tagged_record_definition: defines a TRE, consisting of a name and a 00132 // list of vil_nitf2_field_definition. 00133 // 00134 // vil_nitf2_field_definition: defines a field; includes a vil_nitf2_field_formatter. 00135 // 00136 // vil_nitf2_field_formatter and its derived classes vil_nitf2_typed_field_formatter<T>: 00137 // define the type and format of a field; used to read and write a field. 00138 // 00139 // vil_nitf2_tagged_record: an instance of a tagged record. Points to a 00140 // TaggedRecordDefinition and owns a list of vil_nitf2_field. 00141 // 00142 // vil_nitf2_field: an instance of a field. Contains a pointer to a 00143 // vil_nitf2_field_definition. See derived classes for its value. 00144 // 00145 // vil_nitf2_typed_scalar_field<T>: derived from vil_nitf2_field to represent a scalar 00146 // value of type T (where T=integer, double, vcl_string, char, 00147 // vil_nitf2_date_time, or vil_nitf2_location*) 00148 // 00149 // vil_nitf2_typed_array_field<T*>: derived from vil_nitf2_field to represent a 00150 // repeating field of type T. 00151 // 00152 // vil_nitf2_field_functor<T>: A function object base class used to derive 00153 // functions that compute values of tags from a TRE for the purpose 00154 // of representing conditions and repeat counts. 00155 00156 //----------------------------------------------------------------------------- 00157 // vil_nitf2_tagged_record is an instance of a single NITF tagged record extension, 00158 // consisting of a list of vil_nitf2_fields, as read from (or to be written to) a 00159 // NITF file. 00160 // 00161 class vil_nitf2_tagged_record 00162 { 00163 public: 00164 // Return record identifier 00165 vcl_string name() const; 00166 vcl_string pretty_name() const; 00167 00168 // Return record length in bytes 00169 int length() const { return m_length; } 00170 00171 //bool validate(vil_nitf2_ostream& = vcl_cerr); 00172 00173 // Attempts to read a NITF tagged record from input stream 00174 static vil_nitf2_tagged_record* create(vil_nitf2_istream& input); 00175 00176 // Attempts to write a NITF tagged record to the input stream 00177 virtual bool write(vil_nitf2_ostream&); 00178 00179 // Implements operator << 00180 vcl_ostream& output(vcl_ostream&) const; 00181 00182 // Sets out_value to the value of the integer-value field specified by tag. 00183 // Returns 0 if such a field is not found. 00184 bool get_value(vcl_string tag, int& out_value) const; 00185 bool get_value(vcl_string tag, double& out_value) const; 00186 bool get_value(vcl_string tag, char& out_value) const; 00187 bool get_value(vcl_string tag, void*& out_value) const; 00188 bool get_value(vcl_string tag, vcl_string& out_value) const; 00189 bool get_value(vcl_string tag, vil_nitf2_location*& out_value) const; 00190 bool get_value(vcl_string tag, vil_nitf2_date_time& out_value) const; 00191 #if VXL_HAS_INT_64 00192 bool get_value(vcl_string tag, vil_nitf2_long& out_value) const; 00193 #endif //VXL_HAS_INT_64 00194 00195 //bool get_value(vcl_string tag, int i, int& out_value) const; 00196 //bool get_value(vcl_string tag, int i, double& out_value) const; 00197 //bool get_value(vcl_string tag, int i, char& out_value) const; 00198 //bool get_value(vcl_string tag, int i, void*& out_value) const; 00199 //bool get_value(vcl_string tag, int i, vcl_string& out_value) const; 00200 //bool get_value(vcl_string tag, int i, vil_nitf2_location*& out_value) const; 00201 //bool get_value(vcl_string tag, int i, vil_nitf2_date_time& out_value) const; 00202 #if VXL_HAS_INT_64 00203 //bool get_value(vcl_string tag, int i, vil_nitf2_long& out_value) const; 00204 #endif //VXL_HAS_INT_64 00205 00206 bool get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, int& out_value) const; 00207 bool get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, double& out_value) const; 00208 bool get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, char& out_value) const; 00209 bool get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, void*& out_value) const; 00210 bool get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, vcl_string& out_value) const; 00211 bool get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, vil_nitf2_location*& out_value) const; 00212 bool get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, vil_nitf2_date_time& out_value) const; 00213 #if VXL_HAS_INT_64 00214 bool get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, vil_nitf2_long& out_value) const; 00215 #endif //VXL_HAS_INT_64 00216 00217 // Sets out_value to a flattened list of the values of the array field element 00218 // specified by tag and index. If index is the empty vector, then out_values 00219 // hold all instances of the field. If index partially specifies value instances, 00220 // the out_values hold all instances of the field selected by the partial index. 00221 // Appends to, instead of clearing, out_values if clear_out_values is false. 00222 // Returns 0 if such a field is not found or is of the wrong type. 00223 bool get_values(vcl_string tag, const vil_nitf2_index_vector& indexes, 00224 vcl_vector<int>& out_values, bool clear_out_values = true) const; 00225 bool get_values(vcl_string tag, const vil_nitf2_index_vector& indexes, 00226 vcl_vector<double>& out_values, bool clear_out_values = true) const; 00227 bool get_values(vcl_string tag, const vil_nitf2_index_vector& indexes, 00228 vcl_vector<char>& out_values, bool clear_out_values = true) const; 00229 bool get_values(vcl_string tag, const vil_nitf2_index_vector& indexes, 00230 vcl_vector<void*>& out_values, bool clear_out_values = true) const; 00231 bool get_values(vcl_string tag, const vil_nitf2_index_vector& indexes, 00232 vcl_vector<vcl_string>& out_values, bool clear_out_values = true) const; 00233 bool get_values(vcl_string tag, const vil_nitf2_index_vector& indexes, 00234 vcl_vector<vil_nitf2_location*>& out_values, bool clear_out_values = true) const; 00235 bool get_values(vcl_string tag, const vil_nitf2_index_vector& indexes, 00236 vcl_vector<vil_nitf2_date_time>& out_values, bool clear_out_values = true) const; 00237 #if VXL_HAS_INT_64 00238 bool get_values(vcl_string tag, const vil_nitf2_index_vector& indexes, 00239 vcl_vector<vil_nitf2_long>& out_values, bool clear_out_values = true) const; 00240 #endif 00241 00242 // Convenience overload of preceding methods, that set out_values to all 00243 // instances of array field element. 00244 bool get_values(vcl_string tag, vcl_vector<int>& out_values) const; 00245 bool get_values(vcl_string tag, vcl_vector<double>& out_values) const; 00246 bool get_values(vcl_string tag, vcl_vector<char>& out_values) const; 00247 bool get_values(vcl_string tag, vcl_vector<void*>& out_values) const; 00248 bool get_values(vcl_string tag, vcl_vector<vcl_string>& out_values) const; 00249 bool get_values(vcl_string tag, vcl_vector<vil_nitf2_location*>& out_values) const; 00250 bool get_values(vcl_string tag, vcl_vector<vil_nitf2_date_time>& out_values) const; 00251 #if VXL_HAS_INT_64 00252 bool get_values(vcl_string tag, vcl_vector<vil_nitf2_long>& out_values) const; 00253 #endif 00254 00255 virtual vil_nitf2_field::field_tree* get_tree() const; 00256 00257 // Sets the value of the integer-valued field specified by tag to value. 00258 // Not yet implemented. 00259 //bool set_value(vcl_string tag, int value) { 00260 // return m_field_sequence->set_value(tag, value); } 00261 00262 // Returns a field with specified tag, or 0 if not found. 00263 vil_nitf2_field* get_field(vcl_string tag) const { 00264 return m_field_sequence->get_field(tag); } 00265 00266 // Removes a field with specified tag, returning whether successful. 00267 // Use this method to "undefine" an existing field. 00268 // Not yet implemented. 00269 //bool remove_field(vcl_string tag) { 00270 // return m_field_sequence->remove_field(tag); } 00271 00272 // Test method. Prints results. Returns true if no errors. 00273 static bool test(); 00274 00275 // Destructor 00276 virtual ~vil_nitf2_tagged_record(); 00277 00278 private: 00279 // Default constructor 00280 vil_nitf2_tagged_record(); 00281 00282 // Reads tagged record members from input stream 00283 bool read(vil_nitf2_istream& input); 00284 00285 // Static variables 00286 static vil_nitf2_field_definition & s_length_definition(); 00287 static vil_nitf2_field_definition & s_tag_definition(); 00288 static vil_nitf2_integer_formatter & s_length_formatter(); 00289 static vil_nitf2_string_formatter & s_tag_formatter(); 00290 00291 // Member variables 00292 vil_nitf2_scalar_field* m_length_field; 00293 vil_nitf2_scalar_field* m_tag_field; 00294 int m_length; 00295 vil_nitf2_tagged_record_definition* m_definition; 00296 vil_nitf2_field_sequence* m_field_sequence; 00297 }; 00298 00299 vcl_ostream& operator << (vcl_ostream& os, const vil_nitf2_tagged_record& record); 00300 00301 //----------------------------------------------------------------------------- 00302 // A sequence of tagged records, as read from a NITF file header or image 00303 // subheader extended data field. 00304 00305 class vil_nitf2_tagged_record_sequence : public vcl_list<vil_nitf2_tagged_record*> 00306 { 00307 public: 00308 // Constructor 00309 vil_nitf2_tagged_record_sequence() : vcl_list<vil_nitf2_tagged_record*>() {} 00310 00311 // Destructor 00312 virtual ~vil_nitf2_tagged_record_sequence() {} 00313 }; 00314 00315 vcl_ostream& operator << (vcl_ostream& os, const vil_nitf2_tagged_record_sequence& seq); 00316 00317 #endif // VIL_NITF2_TAGGED_RECORD_H