core/vil/file_formats/vil_nitf2_typed_array_field.h
Go to the documentation of this file.
00001 //:
00002 // \file
00003 // vil_nitf2: Written by Harry Voorhees (hlv@) and Rob Radtke (rob@) of
00004 // Stellar Science Ltd. Co. (stellarscience.com) for
00005 // Air Force Research Laboratory, 2005.
00006 
00007 #ifndef VIL_NITF2_TYPED_ARRAY_FIELD_H
00008 #define VIL_NITF2_TYPED_ARRAY_FIELD_H
00009 
00010 #include <vcl_map.h>
00011 #include <vcl_iosfwd.h>
00012 
00013 #include "vil_nitf2_array_field.h"
00014 #include "vil_nitf2.h"
00015 
00016 class vil_nitf2_index_vector;
00017 
00018 //: Typed concrete class for array fields.
00019 // Stores values and implements I/O of values.
00020 //
00021 template<class T>
00022 class vil_nitf2_typed_array_field : public vil_nitf2_array_field
00023 {
00024  public:
00025   // Constructor
00026   vil_nitf2_typed_array_field(int num_dimensions, vil_nitf2_field_definition* field_definition)
00027     : vil_nitf2_array_field(field_definition, num_dimensions) {}
00028 
00029   //:
00030   // Set out_value to the scalar value at the specified index vector,
00031   // and returns whether specified element was defined.
00032   // The length of the index vector must equal num_dimensions(),
00033   // and check_index(indexes) must return true to indicate that
00034   // the indexes are within bounds. Even so, this method may return
00035   // false if the value is undefined at the specified index.
00036   // (This is a partial override of overloaded method
00037   // vil_nitf2_array_field::value() for my specific type.)
00038   bool value(const vil_nitf2_index_vector& indexes, T& out_value) const;
00039 
00040   //: Reads from input stream the scalar value at specified index.
00041   // check_index(indexes) must be true, or this will emit an error.
00042   // Returns success.
00043   bool read_vector_element(vil_nitf2_istream& input,
00044                            const vil_nitf2_index_vector& indexes,
00045                            int variable_width);
00046 
00047   //: Writes to output stream the scalar value at specified index.
00048   // check_index(indexes) must be true, of this will emit an error.
00049   // Returns success. Arg variable_width, if non-negative, overrides
00050   // formatter's field_width.
00051   bool write_vector_element(vil_nitf2_ostream& output,
00052                             const vil_nitf2_index_vector& indexes,
00053                             int variable_width) const;
00054 
00055   //: Output in human-readable form.
00056   // Implementation provides an example of how to iterate over all elements.
00057   virtual vcl_ostream& output(vcl_ostream& os) const;
00058 
00059   //: Destructor (overridden below for instantiations where T is a pointer)
00060   ~vil_nitf2_typed_array_field() {}
00061 
00062  protected:
00063   // Helper method for output() method above. Iterates over one
00064   // dimension of vector field, recursively printing all defined elements
00065   // to output stream.
00066   void output_dimension_iterate(vcl_ostream& os, vil_nitf2_index_vector indexes,
00067                                 bool& output_yet) const;
00068 
00069  private:
00070   // Value (i,j,...) is stored in m_value_map[(i,j,...)], where the
00071   // length of the index vector (i,j,...) equals member m_num_dimensions.
00072   // A map is used here instead of simple vector for several reasons:
00073   // (1) this single class can represent a vector of any dimensionality;
00074   // (2) due to conditional and blank nodes, a vector may be sparsely
00075   // populated; and (3) a multi-dimensional vector's dimensions may vary.
00076   vcl_map<vil_nitf2_index_vector, T> m_value_map;
00077 };
00078 
00079 //==============================================================================
00080 // implementation
00081 //==============================================================================
00082 
00083 #include "vil_nitf2_index_vector.h"
00084 #include "vil_nitf2_field_formatter.h"
00085 #include "vil_nitf2_typed_field_formatter.h"
00086 #include "vil_nitf2_field_definition.h"
00087 
00088 template<class T>
00089 bool vil_nitf2_typed_array_field<T>::value(
00090   const vil_nitf2_index_vector& indexes, T& out_value) const
00091 {
00092   if ((int)indexes.size() != m_num_dimensions) {
00093     vcl_cerr << "vil_nitf2_typed_array_field index vector wrong length\n";
00094     return false;
00095   }
00096   typename vcl_map<vil_nitf2_index_vector, T>::const_iterator element = m_value_map.find(indexes);
00097   if (element != m_value_map.end()) {
00098     out_value = element->second;
00099     return true;
00100   } else return false;
00101 }
00102 
00103 template<class T>
00104 bool vil_nitf2_typed_array_field<T>::
00105 read_vector_element(vil_nitf2_istream& input, const vil_nitf2_index_vector& indexes,
00106                     int variable_width)
00107 {
00108   VIL_NITF2_LOG(log_debug) << "Reading " << tag() << indexes << ": ";
00109   bool is_blank;
00110   if (!check_index(indexes)) {
00111     VIL_NITF2_LOG(log_debug) << "invalid index!" << vcl_endl;
00112     return false;
00113   }
00114   vil_nitf2_field_formatter* formatter = m_definition->formatter;
00115   // To do: make this cast safe!
00116   vil_nitf2_typed_field_formatter<T>* typed_formatter = (vil_nitf2_typed_field_formatter<T>*)formatter;
00117   // if non-negative variable_width is specified, it overrides the field_width
00118   int saved_field_width = typed_formatter->field_width;
00119   if (variable_width > 0) {
00120     typed_formatter->field_width = variable_width;
00121   }
00122   T val;
00123   bool value_read = typed_formatter->read(input, val, is_blank);
00124   typed_formatter->field_width = saved_field_width;
00125   if (value_read) {
00126     VIL_NITF2_LOG(log_debug) << val << vcl_endl;
00127     m_value_map[indexes] = val;
00128   } else if (is_blank && !m_definition->blanks_ok) {
00129     VIL_NITF2_LOG(log_debug) << "not specified, but required!" << vcl_endl;
00130   } else if (is_blank) {
00131     VIL_NITF2_LOG(log_debug) << "(unspecified)" << vcl_endl;
00132   } else {
00133     VIL_NITF2_LOG(log_debug) << "failed!" << vcl_endl;
00134     return false;
00135   }
00136   return true;
00137 }
00138 
00139 template<class T>
00140 bool vil_nitf2_typed_array_field<T>::
00141 write_vector_element(vil_nitf2_ostream& output, const vil_nitf2_index_vector& indexes,
00142                      int variable_width) const
00143 {
00144   VIL_NITF2_LOG(log_debug) << "Writing tag " << tag() << indexes << ' ';
00145   if (!check_index(indexes)) {
00146     VIL_NITF2_LOG(log_debug) << ": invalid index!" << vcl_endl;
00147     return false;
00148   }
00149   T val;
00150   // To do: make this cast safe!
00151   vil_nitf2_typed_field_formatter<T>* typed_formatter =
00152     (vil_nitf2_typed_field_formatter<T>*)m_definition->formatter;
00153   if (variable_width > 0) typed_formatter->field_width = variable_width;
00154   bool value_defined = value(indexes, val);
00155   if (value_defined) {
00156     VIL_NITF2_LOG(log_debug) << vcl_endl;
00157     return typed_formatter->write(output, val);
00158   } else {
00159     if (!m_definition->blanks_ok) {
00160       VIL_NITF2_LOG(log_debug) << ": required value undefined at this index; writing blanks." << vcl_endl;
00161     }
00162     return typed_formatter->write_blank(output);
00163   }
00164 }
00165 
00166 template<class T>
00167 vcl_ostream& vil_nitf2_typed_array_field<T>::output(vcl_ostream& os) const
00168 {
00169   bool output_yet = false;
00170   output_dimension_iterate(os, vil_nitf2_index_vector(), output_yet);
00171   return os;
00172 }
00173 
00174 template<class T>
00175 void vil_nitf2_typed_array_field<T>::output_dimension_iterate(
00176   vcl_ostream& os, vil_nitf2_index_vector indexes, bool& output_yet) const
00177 {
00178   if ((int)indexes.size()==m_num_dimensions) {
00179     T val;
00180     if (value(indexes, val)) {
00181       // flag output_yet is simply used to print a separator between
00182       // elements within a line.
00183       if (output_yet) {
00184         os << ", ";
00185       } else {
00186         output_yet = true;
00187       }
00188       os << indexes << ' ' << val;
00189     }
00190   } else {
00191     int dim = next_dimension(indexes);
00192     for (int i=0; i < dim; ++i) {
00193       vil_nitf2_index_vector next_indexes(indexes);
00194       next_indexes.push_back(i);
00195       output_dimension_iterate(os, next_indexes, output_yet);
00196     }
00197     os << vcl_endl;
00198     output_yet = false;
00199   }
00200 }
00201 
00202 template<class T>
00203 vcl_ostream& operator << (vcl_ostream& os, const vil_nitf2_typed_array_field<T>& field)
00204 {
00205   return field->output(os);
00206 };
00207 
00208 // Override destructor when T is a pointer type
00209 template<>
00210 inline vil_nitf2_typed_array_field<void*>::~vil_nitf2_typed_array_field()
00211 {
00212   for (vcl_map<vil_nitf2_index_vector, void*>::iterator it = m_value_map.begin();
00213        it != m_value_map.end(); ++it)
00214   {
00215     // vector delete correponds to new char[] for binary data
00216     delete[] (char*) it->second;
00217   }
00218   m_value_map.clear();
00219 }
00220 
00221 template<>
00222 inline vil_nitf2_typed_array_field<vil_nitf2_location*>::~vil_nitf2_typed_array_field()
00223 {
00224   for (vcl_map<vil_nitf2_index_vector, vil_nitf2_location*>::iterator it = m_value_map.begin();
00225        it != m_value_map.end(); ++it)
00226   {
00227     delete it->second;
00228   }
00229   m_value_map.clear();
00230 }
00231 
00232 #endif // VIL_NITF2_TYPED_ARRAY_FIELD_H