core/vil/file_formats/vil_nitf2_tagged_record.cxx
Go to the documentation of this file.
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 #include "vil_nitf2_tagged_record.h"
00006 
00007 #include <vcl_sstream.h>
00008 #include <vcl_iomanip.h>
00009 #include <vcl_iostream.h>
00010 #include <vcl_string.h>
00011 
00012 #include <vil/vil_stream_core.h>
00013 #include <vil/vil_stream_section.h>
00014 
00015 #include "vil_nitf2_tagged_record_definition.h"
00016 #include "vil_nitf2_field_definition.h"
00017 #include "vil_nitf2_field_sequence.h"
00018 #include "vil_nitf2_index_vector.h"
00019 #include "vil_nitf2_typed_field_formatter.h"
00020 #include "vil_nitf2_scalar_field.h"
00021 
00022 vil_nitf2_field_definition& vil_nitf2_tagged_record::s_length_definition()
00023 {
00024   static vil_nitf2_field_definition length_definition(
00025     "CEL", "Extension Length", new vil_nitf2_integer_formatter(5));
00026   return length_definition;
00027 }
00028 
00029 vil_nitf2_field_definition& vil_nitf2_tagged_record::s_tag_definition()
00030 {
00031   static vil_nitf2_field_definition tag_definition (
00032     "CETAG", "Extension Tag", new vil_nitf2_string_formatter(6));
00033   return tag_definition;
00034 }
00035 
00036 vil_nitf2_integer_formatter& vil_nitf2_tagged_record::s_length_formatter()
00037 {
00038   static vil_nitf2_integer_formatter length_formatter(5);
00039   return length_formatter;
00040 }
00041 
00042 vil_nitf2_string_formatter& vil_nitf2_tagged_record::s_tag_formatter()
00043 {
00044   static vil_nitf2_string_formatter tag_formatter(6);
00045   return tag_formatter;
00046 }
00047 
00048 vcl_string vil_nitf2_tagged_record::name() const
00049 {
00050   vcl_string cetag;
00051   if ( m_tag_field->value(cetag) ) return cetag;
00052   else                             return "<Unknown>";
00053 }
00054 
00055 vcl_string vil_nitf2_tagged_record::pretty_name() const
00056 {
00057   if ( m_definition ) return m_definition->m_pretty_name;
00058   else                return "<unknown>";
00059 }
00060 
00061 vil_nitf2_tagged_record* vil_nitf2_tagged_record::create(vil_nitf2_istream& input)
00062 {
00063   vil_nitf2_tagged_record* record = new vil_nitf2_tagged_record();
00064   if (record->read(input)) {
00065     return record;
00066   }
00067   else {
00068     delete record;
00069     return 0;
00070   }
00071 }
00072 
00073 bool vil_nitf2_tagged_record::read(vil_nitf2_istream& input)
00074 {
00075   // Read TRE tag
00076   m_tag_field = vil_nitf2_scalar_field::read(input, &s_tag_definition());
00077   if (!m_tag_field) {
00078     vcl_cerr << "Error reading extension tag at offset " << input.tell() << ".\n";
00079     // Can't continue reading file
00080     return false;
00081   }
00082   vcl_string cetag;
00083   m_tag_field->value(cetag);
00084 
00085   // Read TRE data length
00086   m_length_field = vil_nitf2_scalar_field::read(input, &s_length_definition());
00087   if (!m_length_field) {
00088     vcl_cerr << "Error reading extension length for tag " << cetag << ".\n";
00089     // Can't continue reading file
00090     return false;
00091   }
00092   m_length_field->value(m_length);
00093 
00094   // See if this record is defined ...
00095   vil_nitf2_tagged_record_definition* record_definition =
00096     vil_nitf2_tagged_record_definition::find(cetag);
00097 
00098   // ... if not, skip ahead to next record ...
00099   if (record_definition == 0) {
00100     VIL_NITF2_LOG(log_info) << "Skipping unknown record " << cetag << ".\n";
00101     // Return whether I've found end of record
00102     //input.seekg(ceLength, vcl_ios::cur);
00103     input.seek(input.tell()+m_length);
00104     return input.ok();
00105   }
00106   // ... otherwise, populate this record's fields.
00107   // First save the position to check later that we read entire record
00108   vil_streampos record_data_start_pos = input.tell();
00109   m_definition = record_definition;
00110   m_field_sequence = new vil_nitf2_field_sequence(record_definition->field_definitions());
00111   m_field_sequence->read(input);
00112 
00113   // Check that the expected amount of data was read
00114   vil_streampos expected_pos = record_data_start_pos;
00115   expected_pos += m_length;
00116   if (input.tell() != expected_pos) {
00117     vcl_cerr << "vil_nitf2_tagged_record::read(): Read " << input.tell() - record_data_start_pos
00118              << " bytes instead of " << m_length << " as expected in "<<cetag<<".\n";
00119     // Attempt to reposition input stream to end of record; return whether
00120     // successful
00121     input.seek(expected_pos);
00122     return input.ok();
00123   }
00124   // At end of record, as expected
00125   return true;
00126 }
00127 
00128 bool vil_nitf2_tagged_record::get_value(vcl_string tag, int& out_value) const
00129 { return m_field_sequence->get_value(tag, out_value); }
00130 
00131 bool vil_nitf2_tagged_record::get_value(vcl_string tag, double& out_value) const
00132 { return m_field_sequence->get_value(tag, out_value); }
00133 
00134 bool vil_nitf2_tagged_record::get_value(vcl_string tag, char& out_value) const
00135 { return m_field_sequence->get_value(tag, out_value); }
00136 bool vil_nitf2_tagged_record::get_value(vcl_string tag, void*& out_value) const
00137 { return m_field_sequence->get_value(tag, out_value); }
00138 
00139 bool vil_nitf2_tagged_record::get_value(vcl_string tag, vcl_string& out_value) const
00140 { return m_field_sequence->get_value(tag, out_value); }
00141 
00142 bool vil_nitf2_tagged_record::get_value(vcl_string tag, vil_nitf2_location*& out_value) const
00143 { return m_field_sequence->get_value(tag, out_value); }
00144 
00145 bool vil_nitf2_tagged_record::get_value(vcl_string tag, vil_nitf2_date_time& out_value) const
00146 { return m_field_sequence->get_value(tag, out_value); }
00147 
00148 #if VXL_HAS_INT_64
00149 // if not VXL_HAS_INT_64 isn't defined the vil_nitf2_long is the same as just plain 'int'
00150 // and this function will be a duplicate of that get_value
00151 bool vil_nitf2_tagged_record::get_value(vcl_string tag, vil_nitf2_long& out_value) const
00152 { return m_field_sequence->get_value(tag, out_value); }
00153 #endif
00154 
00155 bool vil_nitf2_tagged_record::get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, int& out_value) const
00156 { return m_field_sequence->get_value(tag, indexes, out_value); }
00157 
00158 bool vil_nitf2_tagged_record::get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, double& out_value) const
00159 { return m_field_sequence->get_value(tag, indexes, out_value); }
00160 
00161 bool vil_nitf2_tagged_record::get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, char& out_value) const
00162 { return m_field_sequence->get_value(tag, indexes, out_value); }
00163 
00164 bool vil_nitf2_tagged_record::get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, void*& out_value) const
00165 { return m_field_sequence->get_value(tag, indexes, out_value); }
00166 
00167 bool vil_nitf2_tagged_record::get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, vcl_string& out_value) const
00168 { return m_field_sequence->get_value(tag, indexes, out_value); }
00169 
00170 bool vil_nitf2_tagged_record::get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, vil_nitf2_location*& out_value) const
00171 { return m_field_sequence->get_value(tag, indexes, out_value); }
00172 
00173 bool vil_nitf2_tagged_record::get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, vil_nitf2_date_time& out_value) const
00174 { return m_field_sequence->get_value(tag, indexes, out_value); }
00175 
00176 #if VXL_HAS_INT_64
00177 // if not VXL_HAS_INT_64 isn't defined the vil_nitf2_long is the same as just plain 'int'
00178 // and this function will be a duplicate of that get_value
00179 bool vil_nitf2_tagged_record::get_value(vcl_string tag, const vil_nitf2_index_vector& indexes, vil_nitf2_long& out_value) const
00180 { return m_field_sequence->get_value(tag, indexes, out_value); }
00181 #endif
00182 
00183 // Macro to define both overloads of get_values()
00184 #define VIL_NITF2_TAGGED_RECORD_GET_VALUES(T) \
00185 bool vil_nitf2_tagged_record::get_values(vcl_string tag, const vil_nitf2_index_vector& indexes, \
00186                                          vcl_vector<T>& out_values, bool clear_out_values) const \
00187 { return m_field_sequence->get_values(tag, indexes, out_values, clear_out_values); } \
00188 bool vil_nitf2_tagged_record::get_values(vcl_string tag, vcl_vector<T>& out_values) const \
00189 { return m_field_sequence->get_values(tag, out_values); }
00190 
00191 VIL_NITF2_TAGGED_RECORD_GET_VALUES(int);
00192 VIL_NITF2_TAGGED_RECORD_GET_VALUES(double);
00193 VIL_NITF2_TAGGED_RECORD_GET_VALUES(char);
00194 VIL_NITF2_TAGGED_RECORD_GET_VALUES(void*);
00195 VIL_NITF2_TAGGED_RECORD_GET_VALUES(vcl_string);
00196 VIL_NITF2_TAGGED_RECORD_GET_VALUES(vil_nitf2_location*);
00197 VIL_NITF2_TAGGED_RECORD_GET_VALUES(vil_nitf2_date_time);
00198 #if VXL_HAS_INT_64
00199   VIL_NITF2_TAGGED_RECORD_GET_VALUES(vil_nitf2_long);
00200 #endif
00201 
00202 
00203 vil_nitf2_tagged_record::vil_nitf2_tagged_record()
00204   : m_length_field(0), m_tag_field(0), m_length(0), m_definition(0), m_field_sequence(0)
00205 {}
00206 
00207 // TO DO: rewrite this method a sequence of unit tests!
00208 //
00209 bool vil_nitf2_tagged_record::test()
00210 {
00211   bool error = false;
00212   const char* test_tre_tag = "@TEST@";
00213   // Example Tagged Record Extension definition
00214   vil_nitf2_tagged_record_definition::define(test_tre_tag, "Test Definition" )
00215    .field("MTI_DP",           "Destination Point",     NITF_INT(2))
00216    .field("MTI_PACKET_ID",    "MTI Packed ID Number",  NITF_INT(3))
00217    .field("DATIME",           "Scan Date & Time",      NITF_DAT(14), true)
00218    .field("ACFT_LOC",         "Aircraft Position",     NITF_LOC(21))
00219    .field("ACFT_LOC2",        "Aircraft Position 2",   NITF_LOC(21))
00220    .field("SQUINT_ANGLE",     "Squint Angle",          NITF_DBL(6, 2, true), true)
00221    .field("NO_VALID_TARGETS", "Number of Targets",     NITF_INT(3))
00222    .field("TGT_CAT",        "Target Classification Category",
00223           NITF_ENUM(1, vil_nitf2_enum_values()
00224             .value("H", "Helicopter")
00225             .value("T", "Tracked")
00226             .value("U", "Unknown")
00227             .value("W", "Wheeled")
00228             .value("TOO LONG", "Too long value test")
00229             .value("T", "Duplicate value test")))
00230    .repeat(new vil_nitf2_field_value<int>("NO_VALID_TARGETS"),
00231            vil_nitf2_field_definitions()
00232            .field("TGT_n_SPEED", "Target Estimated Ground Speed", NITF_INT(4), true)
00233            .field("TGT_n_CAT",   "Target Classification Category",
00234                   NITF_ENUM(1, vil_nitf2_enum_values()
00235                             .value("H", "Helicopter")
00236                             .value("T", "Tracked")
00237                             .value("U", "Unknown")
00238                             .value("W", "Wheeled")),
00239                   true))
00240    .field("TEST_NEG_COND", "Test False Condition", NITF_STR_BCSA(14), false,
00241           0, new vil_nitf2_field_value_greater_than<int>("MTI_DP", 5))
00242    .field("TEST_POS_COND", "Test True Condition",  NITF_STR_BCSA(14), false,
00243           0, new vil_nitf2_field_value_greater_than<int>("MTI_DP", 1))
00244    .field("CLASS",  "Security Classification",
00245           NITF_ENUM(1, vil_nitf2_enum_values()
00246             .value("T", "Top Secret")
00247             .value("S", "Secret")
00248             .value("C", "Confindential")
00249             .value("R", "Restricted")
00250             .value("U", "Unclassified")),
00251             true, 0, 0)
00252    .field("CODEW", "Code Words",                  NITF_STR_BCSA(15), false,
00253           0, new vil_nitf2_field_value_one_of<vcl_string>( "CLASS", "T" ) )
00254    .field("CWTEST", "Another Code Word Test",     NITF_STR_BCSA(15), false,
00255           0, new vil_nitf2_field_value_one_of<vcl_string>( "CLASS", "U" ) )
00256    .field("NBANDS", "Number of bands",            NITF_INT(1), false,
00257           0, 0 )
00258    .field("XBANDS", "Large number of bands",      NITF_INT(2), false,
00259           0, new vil_nitf2_field_value_one_of<int>("NBANDS",0))
00260    .repeat(new vil_nitf2_choose_field_value<int>("NBANDS", "XBANDS",
00261              new vil_nitf2_field_value_greater_than<int>("NBANDS", 0)),
00262              vil_nitf2_field_definitions()
00263      .field("BAND_LTR", "Band Description",       NITF_CHAR(), true,
00264             0)
00265    )
00266    .field( "EXP_TEST", "Exponential format test",  NITF_EXP(6,1))
00267    // test nested repeats and functor references to tags within and
00268    // outside repeat loops
00269    .field( "N",   "Test repeat N", NITF_INT(1))
00270    .repeat(new vil_nitf2_field_value<int>("N"), vil_nitf2_field_definitions()
00271            .field("A", "Test repeat A", NITF_INT(1))
00272            .repeat(new vil_nitf2_field_value<int>("N"), vil_nitf2_field_definitions()
00273                    .field("S", "Test repeat S", NITF_STR(3)))
00274            .repeat(new vil_nitf2_field_value<int>("A"), vil_nitf2_field_definitions()
00275                    .field("B", "Test repeat B", NITF_STR_BCSA(3))
00276                    .repeat(new vil_nitf2_field_value<int>("A"), vil_nitf2_field_definitions()
00277                            .field("C", "Test repeat C", NITF_STR_BCSA(4)))))
00278    // test fixed repeat count
00279    .repeat(4, vil_nitf2_field_definitions()
00280            .field("D", "Test fixed repeat", NITF_INT(1))
00281    )
00282   .end();
00283   // Create a test input vcl_string
00284   vcl_string testFieldsStr =
00285     "02"                     // MTI_DP
00286     "003"                    // MTI_PACKET_ID
00287   //"19990908070605"         // DATIME
00288     "              "         // DATIME
00289     "+89.111111-159.222222"  // ACFT_LOC
00290     "890102.33N0091122.00W"  // ACFT_LOC2
00291     "-60.00"                 // SQUINT_ANGLE
00292     "003"                    // NO_VALID_TARGETS
00293     " "                      // TGT_CAT
00294     "2222" "H"               // TGT_1_SPEED2, TGT_1_CAT2
00295     "    " " "               // TGT_2_SPEED2, TGT_2_CAT2
00296     "4444" "T"               // TGT_3_SPEED2, TGT_3_CAT2
00297     ""                       // TEST_NEG_COND not present
00298     "True Condition"         // TEST_POS_COND
00299     "T"                      // CLASS
00300     "RandomCodeWords"        // CODEW (only present if CLASS=T)
00301     ""                       // CWTEST (not present because CLASS!=U
00302     "0"                      // NBANDS (0, so use XBANDS instead)
00303     "12"                     // XBANDS (present because NBANDS=0)
00304     "abcdefghijkl"           // 12 BAND_LTRs (XBAND=12)
00305     "+1.234567E-8"           // Exponential format test
00306     // test nested repeats
00307     "2"       // N
00308     // for i=0...N-1: i=0
00309     "1"       // A[0]
00310     "S00"     // S[0,0]
00311     "S01"     // S[0,1]
00312     //   for j=0...A[i]-1: j=0
00313     "B00"     // B[0,0]
00314     //     for k=0..A[i]-1: k=0
00315     "C000"    // C[0,0,0]
00316     // i=1:
00317     "2"       // A[1]
00318     "S10"     // S[1,0]
00319     "S11"     // S[1,1]
00320     //   for j=0..A[i]: j=0
00321     "B10"     // B[1,0]
00322     //     for k=0..A[i]
00323     "C100"      // C[1,0,0]
00324     "C101"      // C[1,0,1]
00325     "B11"       // B[1,1]
00326     "C110"      // C[1,1,0]
00327     "C111"      // C[1,1,1]
00328     // test fixed repeat
00329     "7890"
00330   ;
00331   vcl_stringstream test_stream;
00332   test_stream << test_tre_tag; // CETAG
00333   test_stream << vcl_setw(5) << vcl_setfill('0') << testFieldsStr.length(); // CELENGTH
00334   test_stream << testFieldsStr; // rest of fields
00335   vcl_string read_string = test_stream.str();
00336   // Write the test input vcl_string to a vil_stream
00337   vil_stream_core* vs = new vil_stream_core();
00338   vs->write(read_string.c_str(), read_string.length());
00339   vs->seek(0);
00340   vil_stream_section* vss = new vil_stream_section(vs, 0, int(read_string.length()));
00341   // Record from the vil_stream
00342   vil_nitf2_tagged_record* record = vil_nitf2_tagged_record::create(*vss);
00343   if (record)
00344   {
00345     vcl_cerr << *record << '\n';
00346     // Now write the record, and compare the output to the test input
00347     vcl_cerr << "\nOriginal string:\n" << read_string
00348              << "\nWrite() output:\n";
00349     vil_stream_core* vs2 = new vil_stream_core();
00350     record->write(*(vil_stream*)vs2);
00351     vil_streampos bufsize = vs2->file_size();
00352     char* buf = new char[(unsigned int)bufsize + 1];
00353     vs2->seek(0);
00354     vs2->read(buf, bufsize);
00355     buf[bufsize]='\0';
00356     vcl_string write_string = vcl_string(buf);
00357     vcl_cerr << write_string << '\n';
00358     if (read_string != write_string) {
00359       vcl_cerr << "\nWrite failed!\n";
00360       error = true;
00361     }
00362     delete buf;
00363     vcl_cerr << "Testing get_value:\n";
00364     int mti_dp;
00365     if (!record->get_value("MTI_DP", mti_dp) || mti_dp!=2) {
00366       vcl_cerr << "Get value failed!\n";
00367       error = true;
00368     }
00369     else {
00370       vcl_cerr << "MTI_DP = " << mti_dp << '\n';
00371     }
00372     int tgt_speed[4];
00373     if (!record->get_value("TGT_n_SPEED", vil_nitf2_index_vector(0), tgt_speed[0])  ||
00374         tgt_speed[0] != 2222 ||
00375         record->get_value("TGT_n_SPEED", vil_nitf2_index_vector(1), tgt_speed[1]) /*should be null*/ ||
00376         !record->get_value("TGT_n_SPEED", vil_nitf2_index_vector(2), tgt_speed[2]) ||
00377         tgt_speed[2] != 4444) {
00378       vcl_cerr << "Get vector value test failed!\n";
00379       error = true;
00380     }
00381     else {
00382       vcl_cerr << "TGT_2_SPEED = " << tgt_speed[2] << '\n';
00383     }
00384     int d2;
00385     if (!record->get_value("D", vil_nitf2_index_vector(2), d2) || d2 != 9) {
00386       vcl_cerr << "Get fixed repeat count test failed!\n";
00387       error = true;
00388     }
00389     // fetch C[*]
00390     vcl_cerr << "Testing get_values (all values)...\n";
00391     vcl_vector<vcl_string> c_values;
00392     if (!record->get_values("C", c_values) ||
00393         c_values.size() != 5 ||
00394         c_values[0]!="C000" ||
00395         c_values[1]!="C100" ||
00396         c_values[2]!="C101" ||
00397         c_values[3]!="C110" ||
00398         c_values[4]!="C111") {
00399       vcl_cerr << "failed!\n\n";
00400       error = true;
00401     }
00402     // Fetch A[1,*]
00403     vcl_cerr << "Get values (partial index)...\n";
00404     vil_nitf2_index_vector indexes;
00405     vcl_vector<int> a_values;
00406     indexes.push_back(1);
00407     if (!record->get_values("A", indexes, a_values) ||
00408         a_values.size() != 1 ||
00409         a_values[0] != 2) {
00410       vcl_cerr << "failed!\n\n";
00411       error = true;
00412     }
00413     // Fetch C[1,*]
00414     if (!record->get_values("C", indexes, c_values) ||
00415         c_values.size() != 4 ||
00416         c_values[0]!="C100" ||
00417         c_values[1]!="C101" ||
00418         c_values[2]!="C110" ||
00419         c_values[3]!="C111")
00420     {
00421       vcl_cerr << "failed!\n\n";
00422     }
00423   }
00424   else {
00425     vcl_cerr << "Didn't create record!\n";
00426     error = true;
00427   }
00428   // Try output of vector field
00429   vcl_cerr << "Output of vector field C:\n"
00430            << *(record->get_field("C"));
00431   // Clean up test definition and test cleanup
00432   if (!vil_nitf2_tagged_record_definition::undefine(test_tre_tag)) {
00433     vcl_cerr << "Error undefining TRE.\n";
00434     error = true;
00435   }
00436   return !error;
00437 }
00438 
00439 vcl_ostream& vil_nitf2_tagged_record::output(vcl_ostream& os) const
00440 {
00441   os << "CETAG: " << name() << '\n'
00442      << "CELEN: " << length() << vcl_endl;
00443   for (vil_nitf2_field_definitions::iterator fieldNode = m_definition->m_field_definitions->begin();
00444        fieldNode != m_definition->m_field_definitions->end(); ++fieldNode)
00445   {
00446     vil_nitf2_field_definition* field_def = (*fieldNode)->field_definition();
00447     // to do: handle other nodes
00448     if (!field_def) break;
00449     vil_nitf2_field* field = get_field(field_def->tag);
00450     os << field_def->tag << ": ";
00451     if (field) {
00452       os << *field << vcl_endl;
00453     }
00454     else {
00455       os << "(undefined)" << vcl_endl;
00456     }
00457   }
00458   return os;
00459 }
00460 
00461 bool vil_nitf2_tagged_record::write(vil_nitf2_ostream& output)
00462 {
00463   // To track of how much is written
00464   vil_streampos start = output.tell();
00465   // Write tag and length fields
00466   if (m_tag_field && m_length_field) {
00467     m_tag_field->write(output);
00468     m_length_field->write(output);
00469   }
00470   else return false;
00471   // Write data fields
00472   m_field_sequence->write(output);
00473   // Check whether the vcl_right amount was written
00474   vil_streampos end = output.tell();
00475   vil_streampos length_written = end - start;
00476   int expected_length = s_tag_formatter().field_width + s_length_formatter().field_width
00477     + length();
00478   return length_written == expected_length;
00479 }
00480 
00481 vil_nitf2_tagged_record::~vil_nitf2_tagged_record()
00482 {
00483   delete m_field_sequence;
00484 }
00485 
00486 vil_nitf2_field_definition* vil_nitf2_field_sequence::find_field_definition(vcl_string tag)
00487 {
00488   for (vil_nitf2_field_definitions::const_iterator node = m_field_definitions->begin();
00489        node != m_field_definitions->end(); ++node)
00490   {
00491     vil_nitf2_field_definition* field_def = (*node)->field_definition();
00492     // to do: search other nodes
00493     if (!field_def) break;
00494 
00495     if (field_def->tag == tag) {
00496       return field_def;
00497     }
00498   }
00499   // tag definition not found
00500   return 0;
00501 }
00502 
00503 vil_nitf2_field::field_tree* vil_nitf2_tagged_record::get_tree() const
00504 {
00505   //create our tree
00506   //we add the field definitions if the TRE was recognized, or we note that we
00507   //skipped it otherwise
00508   vil_nitf2_field::field_tree* tr;
00509   if ( m_field_sequence ) {
00510     tr = m_field_sequence->get_tree();
00511   }
00512   else {
00513     tr = new vil_nitf2_field::field_tree;
00514     vil_nitf2_field::field_tree* skipped_node = new vil_nitf2_field::field_tree;
00515     skipped_node->columns.push_back( "CEDATA" );
00516     skipped_node->columns.push_back( "<skipped unknown TRE>" );
00517     tr->children.push_back( skipped_node );
00518   }
00519 
00520   //add the columns describing the name of the TRE
00521   tr->columns.push_back( name() );
00522   tr->columns.push_back( pretty_name() );
00523   //add the CEL (length) field to the front
00524   vil_nitf2_field::field_tree* first_child = new vil_nitf2_field::field_tree;
00525   first_child->columns.push_back( "CEL" );
00526   first_child->columns.push_back( "Extension Length" );
00527   vcl_stringstream len_stream;
00528   len_stream << length();
00529   first_child->columns.push_back( len_stream.str() );
00530   tr->children.insert( tr->children.begin(), first_child );
00531   return tr;
00532 }
00533 
00534 vcl_ostream& operator << (vcl_ostream& os, const vil_nitf2_tagged_record& record)
00535 {
00536   return record.output(os);
00537 }
00538 
00539 // vil_nitf2_tagged_record_sequence
00540 
00541 vcl_ostream& operator << (vcl_ostream& os, const vil_nitf2_tagged_record_sequence& seq)
00542 {
00543   os << seq.size() << " TRE's:" << vcl_endl;
00544   vil_nitf2_tagged_record_sequence::const_iterator it;
00545   for (it = seq.begin(); it != seq.end(); ++it) {
00546     os << *it << vcl_endl;
00547   }
00548   return os;
00549 }