vil_nitf2_tagged_record.h
Go to the documentation of this file.
1 // vil_nitf2: Written by Harry Voorhees (hlv@) and Rob Radtke (rob@) of
2 // Stellar Science Ltd. Co. (stellarscience.com) for
3 // Air Force Research Laboratory, 2005.
4 
5 #ifndef VIL_NITF2_TAGGED_RECORD_H
6 #define VIL_NITF2_TAGGED_RECORD_H
7 
8 #include <list>
9 #include <vector>
10 #include <set>
11 #include <iostream>
12 #include <string>
13 #include <ostream>
14 // not used? #include <map>
15 // not used? #include <vcl_compiler.h>
16 // not used? #include <sstream>
17 // not used? #include <istream>
18 
20 #include "vil_nitf2_field.h"
21 
22 // Forward declarations
30 
31 // Overview of NITF tagged record code
32 //
33 // This code is used to define and read National Imagery Transmission
34 // Format (NITF) tagged record extensions (TREs), also known as
35 // controlled extensions. It is intended to eventually support
36 // writing and verifying TREs also.
37 //
38 // A TRE is stored as a sequence of ASCII fields, each of a std::fixed length,
39 // that are appended together without any tag names or delimiters. Some
40 // fields' existence depends on the values of previous fields; other
41 // fields are repeated by a value of a previous field. The TRE definition
42 // code allows the programmer to specify such conditions, and the NITF
43 // file reader evaluates such conditions as it parses the file.
44 //
45 // The classes that represent TRE definitions were designed so that a
46 // programmer can succinctly define a TRE in a format similar to the
47 // tables that appear in the NITF documentation. This was felt to be
48 // important goal to help reduce errors, since NITF TREs can contain
49 // hundred of fields, and many users will need to define their own TRE's
50 // depending on their application and environment.
51 //
52 // Here an example that implements part of the definition of TRE "MTIRPB"
53 // from NIMA STDI-0002 version 2.1:
54 //
55 // vil_nitf2_tagged_record_definition::define("MTIRPB", fields()
56 //
57 // .field("MTI_DP", "Destination Point", NITF_INT(2))
58 // .field("DATIME", "Scan Date & Time", NITF_DAT(14))
59 // .field("ACFT_LOC", "Aircraft Position", NITF_LOC(21))
60 // .field("SQUINT_ANGLE", "Squint Angle", NITF_DBL(6, 2, true), true)
61 // .field("NO_VALID_TARGETS", "Number of Targets", NITF_INT(3))
62 //
63 // .repeat("NO_VALID_TARGETS", fields()
64 //
65 // .field("TGT_n_SPEED", "Target Ground Speed", NITF_INT(4), true)
66 // .field("TGT_n_CAT", "Target Classification Category",
67 // NITF_ENUM(1, vil_nitf2_enum_values()
68 // .value("H", "Helicopter")
69 // .value("T", "Tracked")
70 // .value("U", "Unknown")
71 // .value("W", "Wheeled")),
72 // true))
73 //
74 // .field("TEST_POS_COND", "Test True Condition", NITF_STR_BCSA(14), false,
75 // NitfGreaterThan<int>("MTI_DP", 1))
76 // .end();
77 //
78 // A TaggedRecordDefintion consists of the TRE's name (here, "MTIRPB")
79 // and an ordered list of FieldDefinitions. Each field definition is
80 // specified by these arguments to method "field" above: tag,
81 // pretty_name, format; followed by optional arguments: value_optional,
82 // repeat_count, condition, units, description.
83 //
84 // In this example the first field is a two-digit integer; the second a
85 // is a date-time structure, specified to 14 "digits" precision
86 // (YYYYMMDDHHMMSS); the next field is a location specified as 21
87 // characters, stored either as a latitude-longitude pair of decimal
88 // degrees or deg/min/sec/hemisphere (depending on the TRE, various
89 // formats are allowed, sometimes with variable precision). The next
90 // field, SQUINT_ANGLE, is a std::fixed-point decimal number stored using 6
91 // characters, including 2 decimal places and a sign. The "true"
92 // following the empty "units" argument indicates that field
93 // SQUINT_ANGLE's value is optional, i.e., the field may be blank. Unless
94 // a value is defined as optional, the parser will issue a warning in
95 // such cases (although it will continue parsing the rest of the TRE if
96 // possible).
97 //
98 // The next field, NO_VALID_TARGETS, is an integer field. This is followed
99 // by a repeating integer field, TGT_n_SPEED; the last argument of its
100 // definition indicates that TGT_n_SPEED is repeated by the value of field
101 // NO_VALID_TARGETS. The code here represents TGT_n_SPEED as a single field
102 // whose value is a std::vector of integer pointers. The reason for using
103 // pointers is in case some of the field values are blank; for such entries,
104 // the corresponding std::vector element is null.
105 //
106 // The next field, TGT_n_CAT, is a repeating enumerated string field, whose
107 // valid values are "H", "T", "U", "W", and blank.
108 //
109 // The final field, TEST_POS_COND, is a conditional field. It exists if
110 // and only if its condition is satisfied; in this case, if the value of
111 // field MTI_DP is greater than 1. Conditional fields along with
112 // repeating fields therefore cause instances of a TRE to vary in length.
113 //
114 // That summarizes how TRE's are defined. Some possible extensions in the
115 // future include value range checks and the ability to specify which formats
116 // among a set of alternatives (such as geolocation) are allowed.
117 //
118 // When a TRE is defined, it is added to a dictionary of known TREs that
119 // is used to read (and eventually to write) NITF files. As a NITF file
120 // is read in, at the start of a TRE the tag and length of the TRE are read.
121 // If the tag is recognized, its data is parsed into field using tag
122 // definition, creating a TaggedRecord. If not, the tag's data is skipped
123 // over (according to its declared length) and the next tag is processed.
124 //
125 // Values of NITF fields are passed back to the application as built-in
126 // types and as NITF structure types. Built-in types include integer,
127 // double (used to represent all std::fixed-point decimal fields), string, and
128 // character. NITF structure types include date_time and Location.
129 //
130 // Here is an overview of the class hierarchy:
131 //
132 // vil_nitf2_tagged_record_definition: defines a TRE, consisting of a name and a
133 // list of vil_nitf2_field_definition.
134 //
135 // vil_nitf2_field_definition: defines a field; includes a vil_nitf2_field_formatter.
136 //
137 // vil_nitf2_field_formatter and its derived classes vil_nitf2_typed_field_formatter<T>:
138 // define the type and format of a field; used to read and write a field.
139 //
140 // vil_nitf2_tagged_record: an instance of a tagged record. Points to a
141 // TaggedRecordDefinition and owns a list of vil_nitf2_field.
142 //
143 // vil_nitf2_field: an instance of a field. Contains a pointer to a
144 // vil_nitf2_field_definition. See derived classes for its value.
145 //
146 // vil_nitf2_typed_scalar_field<T>: derived from vil_nitf2_field to represent a scalar
147 // value of type T (where T=integer, double, std::string, char,
148 // vil_nitf2_date_time, or vil_nitf2_location*)
149 //
150 // vil_nitf2_typed_array_field<T*>: derived from vil_nitf2_field to represent a
151 // repeating field of type T.
152 //
153 // vil_nitf2_field_functor<T>: A function object base class used to derive
154 // functions that compute values of tags from a TRE for the purpose
155 // of representing conditions and repeat counts.
156 
157 //-----------------------------------------------------------------------------
158 // vil_nitf2_tagged_record is an instance of a single NITF tagged record extension,
159 // consisting of a list of vil_nitf2_fields, as read from (or to be written to) a
160 // NITF file.
161 //
163 {
164  public:
165  // Return record identifier
166  std::string name() const;
167  std::string pretty_name() const;
168 
169  // Return record length in bytes
170  int length() const { return m_length; }
171 
172  //bool validate(vil_nitf2_ostream& = std::cerr);
173 
174  // Attempts to read a NITF tagged record from input stream
176 
177  // Attempts to write a NITF tagged record to the input stream
178  virtual bool write(vil_nitf2_ostream&);
179 
180  // Implements operator <<
181  std::ostream& output(std::ostream&) const;
182 
183  // Sets out_value to the value of the integer-value field specified by tag.
184  // Returns 0 if such a field is not found.
185  bool get_value(std::string tag, int& out_value) const;
186  bool get_value(std::string tag, double& out_value) const;
187  bool get_value(std::string tag, char& out_value) const;
188  bool get_value(std::string tag, void*& out_value) const;
189  bool get_value(std::string tag, std::string& out_value) const;
190  bool get_value(std::string tag, vil_nitf2_location*& out_value) const;
191  bool get_value(std::string tag, vil_nitf2_date_time& out_value) const;
192 #if VXL_HAS_INT_64
193  bool get_value(std::string tag, vil_nitf2_long& out_value) const;
194 #endif //VXL_HAS_INT_64
195 
196  //bool get_value(std::string tag, int i, int& out_value) const;
197  //bool get_value(std::string tag, int i, double& out_value) const;
198  //bool get_value(std::string tag, int i, char& out_value) const;
199  //bool get_value(std::string tag, int i, void*& out_value) const;
200  //bool get_value(std::string tag, int i, std::string& out_value) const;
201  //bool get_value(std::string tag, int i, vil_nitf2_location*& out_value) const;
202  //bool get_value(std::string tag, int i, vil_nitf2_date_time& out_value) const;
203 #if VXL_HAS_INT_64
204  //bool get_value(std::string tag, int i, vil_nitf2_long& out_value) const;
205 #endif //VXL_HAS_INT_64
206 
207  bool get_value(std::string tag, const vil_nitf2_index_vector& indexes, int& out_value) const;
208  bool get_value(std::string tag, const vil_nitf2_index_vector& indexes, double& out_value) const;
209  bool get_value(std::string tag, const vil_nitf2_index_vector& indexes, char& out_value) const;
210  bool get_value(std::string tag, const vil_nitf2_index_vector& indexes, void*& out_value) const;
211  bool get_value(std::string tag, const vil_nitf2_index_vector& indexes, std::string& out_value) const;
212  bool get_value(std::string tag, const vil_nitf2_index_vector& indexes, vil_nitf2_location*& out_value) const;
213  bool get_value(std::string tag, const vil_nitf2_index_vector& indexes, vil_nitf2_date_time& out_value) const;
214 #if VXL_HAS_INT_64
215  bool get_value(std::string tag, const vil_nitf2_index_vector& indexes, vil_nitf2_long& out_value) const;
216 #endif //VXL_HAS_INT_64
217 
218  // Sets out_value to a flattened list of the values of the array field element
219  // specified by tag and index. If index is the empty vector, then out_values
220  // hold all instances of the field. If index partially specifies value instances,
221  // the out_values hold all instances of the field selected by the partial index.
222  // Appends to, instead of clearing, out_values if clear_out_values is false.
223  // Returns 0 if such a field is not found or is of the wrong type.
224  bool get_values(std::string tag, const vil_nitf2_index_vector& indexes,
225  std::vector<int>& out_values, bool clear_out_values = true) const;
226  bool get_values(std::string tag, const vil_nitf2_index_vector& indexes,
227  std::vector<double>& out_values, bool clear_out_values = true) const;
228  bool get_values(std::string tag, const vil_nitf2_index_vector& indexes,
229  std::vector<char>& out_values, bool clear_out_values = true) const;
230  bool get_values(std::string tag, const vil_nitf2_index_vector& indexes,
231  std::vector<void*>& out_values, bool clear_out_values = true) const;
232  bool get_values(std::string tag, const vil_nitf2_index_vector& indexes,
233  std::vector<std::string>& out_values, bool clear_out_values = true) const;
234  bool get_values(std::string tag, const vil_nitf2_index_vector& indexes,
235  std::vector<vil_nitf2_location*>& out_values, bool clear_out_values = true) const;
236  bool get_values(std::string tag, const vil_nitf2_index_vector& indexes,
237  std::vector<vil_nitf2_date_time>& out_values, bool clear_out_values = true) const;
238 #if VXL_HAS_INT_64
239  bool get_values(std::string tag, const vil_nitf2_index_vector& indexes,
240  std::vector<vil_nitf2_long>& out_values, bool clear_out_values = true) const;
241 #endif
242 
243  // Convenience overload of preceding methods, that set out_values to all
244  // instances of array field element.
245  bool get_values(std::string tag, std::vector<int>& out_values) const;
246  bool get_values(std::string tag, std::vector<double>& out_values) const;
247  bool get_values(std::string tag, std::vector<char>& out_values) const;
248  bool get_values(std::string tag, std::vector<void*>& out_values) const;
249  bool get_values(std::string tag, std::vector<std::string>& out_values) const;
250  bool get_values(std::string tag, std::vector<vil_nitf2_location*>& out_values) const;
251  bool get_values(std::string tag, std::vector<vil_nitf2_date_time>& out_values) const;
252 #if VXL_HAS_INT_64
253  bool get_values(std::string tag, std::vector<vil_nitf2_long>& out_values) const;
254 #endif
255 
256  virtual vil_nitf2_field::field_tree* get_tree() const;
257 
258  // Sets the value of the integer-valued field specified by tag to value.
259  // Not yet implemented.
260  //bool set_value(std::string tag, int value) {
261  // return m_field_sequence->set_value(tag, value); }
262 
263  // Returns a field with specified tag, or 0 if not found.
264  vil_nitf2_field* get_field(std::string tag) const {
265  return m_field_sequence->get_field(tag); }
266 
267  // Removes a field with specified tag, returning whether successful.
268  // Use this method to "undefine" an existing field.
269  // Not yet implemented.
270  //bool remove_field(std::string tag) {
271  // return m_field_sequence->remove_field(tag); }
272 
273  // Test method. Prints results. Returns true if no errors.
274  static bool test();
275 
276  // Destructor
277  virtual ~vil_nitf2_tagged_record();
278 
279  private:
280  // Default constructor
282 
283  // Reads tagged record members from input stream
284  bool read(vil_nitf2_istream& input);
285 
286  // Static variables
291 
292  // Member variables
295  int m_length;
298 };
299 
300 std::ostream& operator << (std::ostream& os, const vil_nitf2_tagged_record& record);
301 
302 //-----------------------------------------------------------------------------
303 // A sequence of tagged records, as read from a NITF file header or image
304 // subheader extended data field.
305 
306 class vil_nitf2_tagged_record_sequence : public std::list<vil_nitf2_tagged_record*>
307 {
308  public:
309  // Constructor
311 
312  // Destructor
313  virtual ~vil_nitf2_tagged_record_sequence() = default;
314 };
315 
316 std::ostream& operator << (std::ostream& os, const vil_nitf2_tagged_record_sequence& seq);
317 
318 #endif // VIL_NITF2_TAGGED_RECORD_H
vxl_int_32 vil_nitf2_long
Definition: vil_nitf2.h:26
std::ostream & operator<<(std::ostream &os, const vil_nitf2_tagged_record &record)
virtual ~vil_nitf2_tagged_record_sequence()=default
std::ostream & output(std::ostream &) const
vil_nitf2_field * get_field(std::string tag) const
static vil_nitf2_field_definition & s_length_definition()
vil_nitf2_tagged_record_definition * m_definition
Stream interface for VIL image loaders.
Definition: vil_stream.h:21
static vil_nitf2_field_definition & s_tag_definition()
vil_nitf2_scalar_field * m_tag_field
vil_nitf2_field_sequence * m_field_sequence
static vil_nitf2_integer_formatter & s_length_formatter()
bool get_value(std::string tag, int &out_value) const
vil_nitf2_scalar_field * m_length_field
bool read(vil_nitf2_istream &input)
vil_nitf2_field * get_field(const std::string &tag) const
vil_nitf2_tagged_record_definition defines a particular tagged record extension (TRE).
virtual vil_nitf2_field::field_tree * get_tree() const
Functors used by NITF classes.
bool get_values(std::string tag, const vil_nitf2_index_vector &indexes, std::vector< int > &out_values, bool clear_out_values=true) const
virtual bool write(vil_nitf2_ostream &)
static vil_nitf2_string_formatter & s_tag_formatter()
static vil_nitf2_tagged_record * create(vil_nitf2_istream &input)