vil_nitf2_typed_field_formatter.cxx
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 #include <algorithm>
6 #include <iomanip>
7 #include <iostream>
8 #include <utility>
9 #include <cerrno>
11 
12 
13 //==============================================================================
14 // Class vil_nitf2_date_time_formatter
15 
17  : vil_nitf2_typed_field_formatter<vil_nitf2_date_time>(vil_nitf2::type_date_time, field_width)
18 {}
19 
21 {
23 }
24 
25 bool vil_nitf2_date_time_formatter::read_vcl_stream(std::istream& input, vil_nitf2_date_time& out_value, bool& out_blank)
26 {
27  return out_value.read(input, field_width, out_blank);
28 }
29 
31 {
32  return value.write(output, field_width);
33 }
34 
35 //==============================================================================
36 // Class vil_nitf2_location_formatter
37 
39  : vil_nitf2_typed_field_formatter<vil_nitf2_location*>(vil_nitf2::type_location, field_width)
40 {}
41 
43 {
45 }
46 
48  vil_nitf2_location*& out_value,
49  bool& out_blank)
50 {
51  std::streampos tag_start_pos = input.tellg();
53  if (location->read(input, field_width, out_blank)) {
54  out_value = location;
55  return true;
56  } else {
57  delete location;
58  input.seekg(tag_start_pos);
60  if (location->read(input, field_width, out_blank)) {
61  out_value = location;
62  return true;
63  } else {
64  delete location;
65  out_value = nullptr;
66  return false;
67  }
68  }
69 }
70 
72 {
73  return value->write(output, field_width);
74 }
75 
76 //==============================================================================
77 // Class vil_nitf2_integer_formatter
78 
80  : vil_nitf2_typed_field_formatter<int>(vil_nitf2::type_int, field_width),
81  show_sign(show_sign)
82 {
83  //Assuming that int is 32 bits, then it can't represent a value higher than
84  // (10^32)/2 ... that is 2147483648.
85  //assert( field_width < 10 );
86 }
87 
89 {
91 }
92 
93 bool
95  int& out_value, bool& out_blank)
96 {
97  char* cstr;
98  if (!read_c_str(input, field_width, cstr, out_blank)) {
99  delete[] cstr;
100  return false;
101  }
102  char* endp;
103  errno = 0;
104  out_value = (int)strtol(cstr, &endp, 10);
105  bool sign_ok = check_sign(cstr, show_sign);
106  bool retVal = (endp-cstr)==field_width // processed all chars
107  && errno==0 // with no errors
108  && sign_ok; // sign shown as expected
109  delete[] cstr;
110  return retVal;
111 }
112 
113 bool vil_nitf2_integer_formatter::write_vcl_stream(std::ostream& output, const int& value)
114 {
115  output << std::setw(field_width) << std::right << std::setfill('0');
116  if (show_sign) {
117  output << std::showpos;
118  } else {
119  output << std::noshowpos;
120  }
121  output << value;
122  return !output.fail();
123 }
124 
125 //==============================================================================
126 // Class vil_nitf2_long_long_formatter
127 
129 vil_nitf2_long_long_formatter(int field_width, bool show_sign)
130  : vil_nitf2_typed_field_formatter<vil_nitf2_long>(vil_nitf2::type_long_long, field_width),
131  show_sign(show_sign)
132 {}
133 
135 {
137 }
138 
140 read_vcl_stream(std::istream& input, vil_nitf2_long& out_value, bool& out_blank)
141 {
142  char* cstr;
143  if (!read_c_str(input, field_width, cstr, out_blank)) {
144  delete[] cstr;
145  return false;
146  }
147  bool conversion_ok;
148  char* endp;
149  errno = 0;
150 
151 #if VXL_HAS_INT_64
152 
153 #if defined _MSC_VER
154  out_value = _strtoi64(cstr, &endp, 10);
155  conversion_ok = (endp-cstr)==field_width; // processed all chars
156 #else
157  out_value = ::strtoll(cstr, &endp, 10); // in Standard C Library
158  conversion_ok = (endp-cstr)==field_width; // processed all chars
159 #endif
160 
161 #else //VXL_HAS_INT_64
162  out_value = strtol(cstr, &endp, 10);
163  conversion_ok = (endp-cstr)==field_width; // processed all chars
164 #endif //VXL_HAS_INT_64
165 
166  bool sign_ok = check_sign(cstr, show_sign);
167  delete[] cstr;
168  return conversion_ok
169  && errno==0 // with no errors
170  && sign_ok; // sign shown as expected
171 }
172 
173 bool vil_nitf2_long_long_formatter::write_vcl_stream(std::ostream& output, const vil_nitf2_long& value)
174 {
175  output << std::setw(field_width) << std::right << std::setfill('0');
176  if (show_sign) {
177  output << std::showpos;
178  } else {
179  output << std::noshowpos;
180  }
181  output << value;
182  return !output.fail();
183 }
184 
185 //==============================================================================
186 // Class vil_nitf2_double_formatter
187 
189 vil_nitf2_double_formatter(int field_width, int precision, bool show_sign)
190  : vil_nitf2_typed_field_formatter<double>(vil_nitf2::type_double, field_width),
191  precision(precision),
192  show_sign(show_sign)
193 {}
194 
196 {
198 }
199 
201  double& out_value, bool& out_blank)
202 {
203  char* cstr;
204  if (!read_c_str(input, field_width, cstr, out_blank)) {
205  delete[] cstr;
206  return false;
207  }
208  char* endp;
209  errno=0;
210  out_value = strtod(cstr, &endp);
211  bool sign_ok = check_sign(cstr, show_sign);
212  bool decimal_ok = cstr[(field_width-precision)-1]=='.';
213  bool retVal =
214  (endp-cstr)==field_width // processed all chars
215  && errno==0 // with no errors
216  && decimal_ok // decimal point in right place
217  && sign_ok; // sign shown as expected
218  delete[] cstr;
219  return retVal;
220 }
221 
222 bool vil_nitf2_double_formatter::write_vcl_stream(std::ostream& output, const double& value)
223 {
224  output << std::setw(field_width) << std::fixed;
225  if (show_sign) {
226  output << std::showpos;
227  } else {
228  output << std::noshowpos;
229  }
230  output << std::internal << std::setfill('0') << std::setprecision(precision)
231  << value;
232  return !output.fail();
233 }
234 
235 //==============================================================================
236 // Class vil_nitf2_exponential_formatter
237 
239 vil_nitf2_exponential_formatter(int mantissa_width, int exponent_width)
240  : vil_nitf2_typed_field_formatter<double>(vil_nitf2::type_double,
241  mantissa_width + exponent_width + 5),
242  mantissa_width(mantissa_width),
243  exponent_width(exponent_width)
244 {}
245 
247 {
249 }
250 
252  double& out_value, bool& out_blank)
253 {
254  char* cstr;
255  if (!read_c_str(input, field_width, cstr, out_blank)) {
256  delete[] cstr;
257  return false;
258  }
259  char* endp;
260  errno=0;
261  out_value = strtod(cstr, &endp);
262  // Check locations of non-digits in format: +d.dddddE+dd
263  const char base_sign = cstr[0];
264  const bool base_sign_ok = base_sign=='+' || base_sign=='-';
265  const bool decimal_ok = cstr[2]=='.';
266  const char e_ok = cstr[3+mantissa_width]=='E';
267  const char exp_sign = cstr[4+mantissa_width];
268  const bool exp_sign_ok = exp_sign=='+' || exp_sign=='-';
269  bool retVal =
270  (endp-cstr)==field_width // processed all chars
271  && errno==0 // read a number with no errors
272  && base_sign_ok // base sign in right place
273  && decimal_ok // decimal point in right place
274  && e_ok // 'E' in right place
275  && exp_sign_ok; // exponent sign in right place
276  delete[] cstr;
277  return retVal;
278 }
279 
281  const double& value)
282 {
283  // Can't control the width of exponent (it's 3) so write it to a buffer first
284  std::ostringstream buffer;
285  buffer << std::setw(field_width) << std::scientific
286  << std::showpos << std::uppercase
287  << std::internal << std::setfill('0') << std::setprecision(mantissa_width)
288  << value;
289  std::string buffer_string = buffer.str();
290  auto length = (unsigned int)(buffer_string.length());
291  // Write everything up to the exponent sign
292  output << buffer_string.substr(0,length-3);
293  // Write exponent digits, padding or unpadding them to desired width
294  output << std::setw(exponent_width) << std::setfill('0')
295  << buffer_string.substr(length-std::min(3,exponent_width), std::min(3,exponent_width));
296  return !output.fail();
297 }
298 
299 //==============================================================================
300 // Class vil_nitf2_binary_formatter
301 
303  : vil_nitf2_typed_field_formatter<void*>(vil_nitf2::type_binary, width_bytes)
304 {}
305 
307 {
309 }
310 
311 bool vil_nitf2_binary_formatter::read(vil_stream& input, void*& out_value,
312  bool& out_blank)
313 {
314  out_value = (void*)(new char[field_width]);
315  out_blank = false; //no such thing as 'blank' binary data
316  return input.read( out_value, field_width ) == field_width;
317 }
318 
319 bool vil_nitf2_binary_formatter::write(vil_nitf2_ostream& output, void*const& value)
320 {
321  return output.write( value, field_width ) == field_width;
322 }
323 
324 //==============================================================================
325 // Class vil_nitf2_char_formatter
326 
328  : vil_nitf2_typed_field_formatter<char>(vil_nitf2::type_char, 1)
329 {}
330 
332 {
333  return new vil_nitf2_char_formatter();
334 }
335 
336 bool vil_nitf2_char_formatter::read_vcl_stream(std::istream& input, char& out_value, bool& out_blank)
337 {
338  input.get(out_value);
339  //int numRead = input.read(&out_value, 1);
340  out_blank = (out_value == ' ');
341  return !input.fail();
342  //return numRead == 1;
343 }
344 
345 bool vil_nitf2_char_formatter::write_vcl_stream(std::ostream& output, const char& value)
346 {
347  output << value;
348  return !output.fail();
349 }
350 
351 //==============================================================================
352 // Class vil_nitf2_string_formatter
353 
355 vil_nitf2_string_formatter(int field_width, enum_char_set char_set)
356  : vil_nitf2_typed_field_formatter<std::string>(vil_nitf2::type_string, field_width),
357  char_set(char_set)
358 {}
359 
361 {
363 }
364 
366  std::string& out_value,
367  bool& out_blank)
368 {
369  char* cstr;
370  if (!read_c_str(input, field_width, cstr, out_blank)) {
371  delete[] cstr;
372  return false;
373  }
374  std::string str = std::string(cstr);
375  delete[] cstr;
376  std::string::size_type end_pos = str.find_last_not_of(' ')+1;
377  if (end_pos == std::string::npos) {
378  out_value = str;
379  } else {
380  out_value = str.substr(0, end_pos);
381  }
382  return is_valid(out_value);
383 }
384 
385 bool vil_nitf2_string_formatter::write_vcl_stream(std::ostream& output, const std::string& value)
386 {
387  output << std::setw(field_width) << std::left << std::setfill(' ') << value;
388  return !output.fail();
389 }
390 
391 bool vil_nitf2_string_formatter::is_valid(std::string /*value*/) const
392 {
393  // to do: check char set
394  return true;
395 }
396 
397 //==============================================================================
398 // Class vil_nitf2_enum_string_formatter
399 
402  : vil_nitf2_string_formatter(field_width), value_map(std::move(value_map))
403 {
404  //field_type = Nitf::Enum;
406 }
407 
409 {
411 }
412 
414 {
415  for (auto & entry : value_map)
416  {
417  std::string token = entry.first;
418 #if 0 // disable the err message
419  if (int(token.length()) > field_width) {
420  //std::cerr << "vil_nitf2_enum_values: WARNING: Ignoring token "
421  // << token << "; length exceeds declared field width.\n";
422  // Should probably remove it so that is_valid() doesn't match it.
423  // On the other hand, this class will never read a token of this
424  // length, so don't worry about it.
425  }
426 #endif
427  }
428 }
429 
430 bool vil_nitf2_enum_string_formatter::is_valid_value(const std::string& token) const
431 {
432  return value_map.find(token) != value_map.end();
433 }
434 
435 //==============================================================================
436 // Class vil_nitf2_enum_values
437 
438 vil_nitf2_enum_values& vil_nitf2_enum_values::value(std::string token, std::string pretty_name)
439 {
440  if (!insert(std::make_pair(token, pretty_name)).second) {
441  std::cerr << "vil_nitf2_enum_values: WARNING: Ignoring definition "
442  << token << "; token already defined for this enumeration.\n";
443  }
444  return *this;
445 }
446 
447 //==============================================================================
448 // Class vil_nitf2_tre_sequence_formatter
449 
450 #include "vil_nitf2_tagged_record.h"
451 
454  vil_nitf2::type_tagged_record_sequence, 1 /* ignored */)
455 {}
456 
459 {
461 }
462 
465  vil_nitf2_tagged_record_sequence& out_value, bool& out_blank )
466 {
467  if (field_width <= 0) return false;
468  vil_streampos current = input.tell();
469  vil_streampos end = current + field_width;
470  bool error_reading_tre = false;
471  out_value.clear();
472  while (input.tell() < end && !error_reading_tre) {
474  if (record) {
475  out_value.push_back(record); // out_value assumes ownership of record
476  }
477  error_reading_tre &= !record;
478  }
479  if (input.tell() != end) { // TO DO: what does end equal at EOF?
480  VIL_NITF2_LOG(log_info) << "\nSeeking to end of TRE sequence field.\n";
481  input.seek(end);
482  if (input.tell() != end) {
483  std::cerr << "\nSeek to end of TRE sequence field failed.\n";
484  error_reading_tre = true;
485  }
486  }
487  out_blank = false;
488  return !error_reading_tre;
489 }
490 
493 {
494  return false;
495 }
vil_nitf2_field_formatter * copy() const override
vxl_int_32 vil_nitf2_long
Definition: vil_nitf2.h:26
vil_nitf2_integer_formatter(int field_width, bool show_sign=false)
bool write(vil_nitf2_ostream &output, void *const &value) override
Overload to write() instead of write_vcl_stream() to write binary data.
virtual vil_streampos tell() const =0
Return file pointer.
vil_nitf2_field_formatter * copy() const override
vil_nitf2_field_formatter * copy() const override
bool write_vcl_stream(std::ostream &output, const vil_nitf2_date_time &value) override
bool read(vil_nitf2_istream &input, vil_nitf2_tagged_record_sequence &out_value, bool &out_blank) override
bool read_vcl_stream(std::istream &input, vil_nitf2_long &out_value, bool &out_blank) override
vil_nitf2_field_formatter * copy() const override
vil_nitf2_exponential_formatter(int mantissa_width, int exponent_width)
vil_nitf2_string_formatter(int field_width, enum_char_set char_set=ECS)
bool write_vcl_stream(std::ostream &output, const double &value) override
vil_nitf2_field_formatter * copy() const override
virtual vil_streampos write(void const *buf, vil_streampos n)=0
Write n bytes from buf. Returns number of bytes written.
bool write(std::ostream &output, int field_width) const
bool read_vcl_stream(std::istream &input, vil_nitf2_date_time &out_value, bool &out_blank) override
bool write_vcl_stream(std::ostream &output, const int &value) override
bool read(std::istream &input, int field_width, bool &out_blank)
virtual bool is_valid(std::string value) const
vil_nitf2_double_formatter(int field_width, int precision, bool show_sign)
bool read_vcl_stream(std::istream &input, int &out_value, bool &out_blank) override
virtual void seek(vil_streampos position)=0
Goto file pointer.
#define VIL_NITF2_LOG(LEVEL)
Definition: vil_nitf2.h:63
virtual vil_streampos read(void *buf, vil_streampos n)=0
Read n bytes into buf. Returns number of bytes read.
bool read(vil_nitf2_istream &input, void *&out_value, bool &out_blank) override
vil_nitf2_enum_string_formatter(int field_width, vil_nitf2_enum_values)
static bool check_sign(const char *cstr, bool show_sign)
vil_nitf2_field_formatter * copy() const override
Stream interface for VIL image loaders.
Definition: vil_stream.h:21
bool write_vcl_stream(std::ostream &output, const std::string &value) override
vil_nitf2_field_formatter * copy() const override
bool write_vcl_stream(std::ostream &output, const vil_nitf2_long &value) override
virtual bool write(std::ostream &output, int field_width)=0
virtual bool read(std::istream &input, int field_width, bool &out_blank)=0
bool write_vcl_stream(std::ostream &output, const char &value) override
vil_nitf2_field_formatter * copy() const override
vil_nitf2_field_formatter * copy() const override
bool write(vil_nitf2_ostream &output, const vil_nitf2_tagged_record_sequence &value) override
Overload to write() instead of write_vcl_stream() to write binary data.
bool read_vcl_stream(std::istream &input, char &out_value, bool &out_blank) override
static bool read_c_str(std::istream &input, int length, char *&out_cstr, bool &all_blank)
bool write_vcl_stream(std::ostream &output, const double &value) override
bool write_vcl_stream(std::ostream &output, vil_nitf2_location *const &value) override
vxl_int_32 vil_streampos
Definition: vil_stream.h:16
bool read_vcl_stream(std::istream &input, vil_nitf2_location *&out_value, bool &out_blank) override
vil_nitf2_field_formatter * copy() const override
bool is_valid_value(const std::string &value) const
bool read_vcl_stream(std::istream &input, double &out_value, bool &out_blank) override
bool read_vcl_stream(std::istream &input, std::string &out_value, bool &out_blank) override
bool read_vcl_stream(std::istream &input, double &out_value, bool &out_blank) override
static vil_nitf2_tagged_record * create(vil_nitf2_istream &input)
vil_nitf2_field_formatter * copy() const override
vil_nitf2_long_long_formatter(int field_width, bool show_sign=false)
vil_nitf2_enum_values & value(std::string token, std::string pretty_name="")