vector<ImportDescriptor*> SignatureImporter::getImportDescriptors(const string& filename)
{
   vector<ImportDescriptor*> descriptors;
   if (filename.empty())
   {
      return descriptors;
   }

   LargeFileResource pSigFile;
   if (!pSigFile.open(filename, O_RDONLY | O_BINARY, S_IREAD))
   {
      return descriptors;
   }

   // load the data
   FactoryResource<DynamicObject> pMetadata;
   VERIFYRV(pMetadata.get() != NULL, descriptors);

   bool readError = false;
   string line;
   string unitName("Reflectance");
   UnitType unitType(REFLECTANCE);
   double unitScale(1.0);

   // parse the metadata
   for (line = pSigFile.readLine(&readError);
      (readError == false) && (line.find('=') != string::npos);
      line = pSigFile.readLine(&readError))
   {
      vector<string> metadataEntry;

      trim(line);
      split(metadataEntry, line, is_any_of("="));
      if (metadataEntry.size() == 2)
      {
         string key = metadataEntry[0];
         string value = metadataEntry[1];
         trim(key);
         trim(value);
         if (ends_with(key, "Bands") || key == "Pixels")
         {
            pMetadata->setAttribute(key, StringUtilities::fromXmlString<unsigned long>(value));
         }
         else if (key == "UnitName")
         {
            unitName = value;
         }
         else if (key == "UnitType")
         {
            unitType = StringUtilities::fromXmlString<UnitType>(value);
         }
         else if (key == "UnitScale")
         {
            unitScale = StringUtilities::fromXmlString<double>(value);
         }
         else
         {
            pMetadata->setAttribute(key, value);
         }
      }
   }
   if ((readError == true) && (pSigFile.eof() != 1))
   {
      return descriptors;
   }
   // Verify that the next line contains float float pairs
   vector<string> dataEntry;

   trim(line);
   split(dataEntry, line, is_space());
   if (dataEntry.size() != 2)
   {
      return descriptors;
   }
   bool error = false;
   StringUtilities::fromXmlString<float>(dataEntry[0], &error);
   !error && StringUtilities::fromXmlString<float>(dataEntry[1], &error);
   if (error)
   {
      return descriptors;
   }

   string datasetName = dv_cast<string>(pMetadata->getAttribute("Name"), filename);

   ImportDescriptorResource pImportDescriptor(datasetName, "Signature");
   VERIFYRV(pImportDescriptor.get() != NULL, descriptors);
   SignatureDataDescriptor* pDataDescriptor =
      dynamic_cast<SignatureDataDescriptor*>(pImportDescriptor->getDataDescriptor());
   VERIFYRV(pDataDescriptor != NULL, descriptors);

   FactoryResource<SignatureFileDescriptor> pFileDescriptor;
   VERIFYRV(pFileDescriptor.get() != NULL, descriptors);
   pFileDescriptor->setFilename(filename);

   FactoryResource<Units> pReflectanceUnits;
   VERIFYRV(pReflectanceUnits.get() != NULL, descriptors);
   pReflectanceUnits->setUnitName(unitName);
   pReflectanceUnits->setUnitType(unitType);
   if (unitScale != 0.0)
   {
      pReflectanceUnits->setScaleFromStandard(1.0 / unitScale);
   }
   pDataDescriptor->setUnits("Reflectance", pReflectanceUnits.get());
   pFileDescriptor->setUnits("Reflectance", pReflectanceUnits.get());

   pDataDescriptor->setFileDescriptor(pFileDescriptor.get());
   pDataDescriptor->setMetadata(pMetadata.get());
   descriptors.push_back(pImportDescriptor.release());
   return descriptors;
}
bool Nitf::importMetadata(const unsigned int& currentImage, const Nitf::OssimFileResource& pFile,
   const ossimNitfFileHeaderV2_X* pFileHeader, const ossimNitfImageHeaderV2_X* pImageSubheader,
   RasterDataDescriptor* pDescriptor, map<string, TrePlugInResource>& parsers, string& errorMessage)
{
//#pragma message(__FILE__ "(" STRING(__LINE__) ") : warning : Separate the file header parsing " \
//   "from the subheader parsing (dadkins)")

   VERIFY(pFileHeader != NULL && pImageSubheader != NULL && pDescriptor != NULL);

   // Add metadata for the NITF File Header and the supported subheaders
   const string fileVersion = pFileHeader->getVersion();
   Nitf::FileHeader fileHeader(fileVersion);
   if (fileHeader.importMetadata(pFileHeader, pDescriptor) == false)
   {
      errorMessage += "Unable to import metadata from the file header.\n";
      return false;
   }

   unsigned int numDes = pFileHeader->getNumberOfDataExtSegments();
   for (unsigned int i = 0; i < numDes; ++i)
   {
      auto_ptr<ossimNitfDataExtensionSegment> pDes(pFile->getNewDataExtensionSegment(i));
      if (pDes.get() != NULL)
      {
         Nitf::DesSubheader desSubheader(fileVersion, i);
         if (desSubheader.importMetadata(pDes.get(), pDescriptor) == false)
         {
            stringstream errorStream;
            errorStream << "Unable to retrieve DES subheader #" << i << "." << endl;
            errorMessage += errorStream.str();
         }
      }
   }

   Nitf::ImageSubheader imageSubheader(fileVersion);
   if (imageSubheader.importMetadata(pImageSubheader, pDescriptor) == false)
   {
      errorMessage += "Unable to import metadata from the image subheader.\n";
      return false;
   }

   // Now do the TREs
   FactoryResource<DynamicObject> pTres;
   FactoryResource<DynamicObject> pTreInfo;

   const unsigned int numImageTags = pImageSubheader->getNumberOfTags();
   for (unsigned int imageTag = 0; imageTag < numImageTags; ++imageTag)
   {
      ossimNitfTagInformation tagInfo;
      if (pImageSubheader->getTagInformation(tagInfo, imageTag) == false)
      {
         stringstream errorStream;
         errorStream << "Unable to retrieve tag #" << imageTag << " from the image subheader." << endl;
         errorMessage += errorStream.str();
      }
      else
      {
         addTagToMetadata(currentImage, tagInfo, pDescriptor, pTres.get(), pTreInfo.get(), parsers, errorMessage);
      }
   }

   const unsigned int numFileTags = pFileHeader->getNumberOfTags();
   for (unsigned int fileTag = 0; fileTag < numFileTags; ++fileTag)
   {
      ossimNitfTagInformation tagInfo;
      if (pFileHeader->getTagInformation(tagInfo, fileTag) == false)
      {
         stringstream errorStream;
         errorStream << "Unable to retrieve tag #" << fileTag << " from the file header." << endl;
         errorMessage += errorStream.str();
      }
      else
      {
         // For file headers, currentImage is always 0.
         addTagToMetadata(0, tagInfo, pDescriptor, pTres.get(), pTreInfo.get(), parsers, errorMessage);
      }
   }

   // FTITLE parsing requires the metadata object to be populated first
   DynamicObject* pMetadata = pDescriptor->getMetadata();
   VERIFY(pMetadata != NULL);
   pMetadata->setAttributeByPath(Nitf::NITF_METADATA + "/" + Nitf::TRE_METADATA, *pTres.get());
   pMetadata->setAttributeByPath(Nitf::NITF_METADATA + "/" + Nitf::TRE_INFO_METADATA, *pTreInfo.get());

//#pragma message(__FILE__ "(" STRING(__LINE__) ") : warning : Consider moving this into ChipConverter (leckels)")
   // We have two equations of the form:
   // FI_x = a*OP_x + b*OP_y + c and
   // FI_y = d*OP_x + e*OP_y + f
   //
   // The coefficients a-f are as follows (from Todd's implementation of FTITLE -> ICHIPB Coefficients
   // a = 1.0;
   // b = 0.0
   // c = (row-1)*x_pixel_block_size, where row comes from FTITLE
   // d = 0.0
   // e = 1.0
   // f = (column-1)*y_pixel_block_size, where column comes from FTITLE
   //
   // Solving for OP_x, OP_y, and substituting for a-f, we get:
   // FI_x - c = OP_x
   // FI_y - f = OP_y
   // Building the ICHIPB requires solving for OP_x and OP_y, since a-f can be derived from the FTITLE

   // Special case if NTM: build and insert an ICHIPB if it is missing
   // trust the ICHIPB more than the other tags; only create an ICHIPB if none exist
   if (pTres->getAttribute("STDIDB").isValid() == true && pTres->getAttribute("ICHIPB").isValid() == false)
   {
      int x_pixel_block_size = pImageSubheader->getNumberOfPixelsPerBlockHoriz();
      int y_pixel_block_size = pImageSubheader->getNumberOfPixelsPerBlockVert();

      unsigned int imgRows = pImageSubheader->getNumberOfRows();
      unsigned int imgCols = pImageSubheader->getNumberOfCols();

      int blockRow = 1;
      int blockCol = 1;
      //the ftitle we only need a small portion of, we can extract
      //the displayed blocks included in this image from a properly
      //named ftitle.  

      string ftitle = pFileHeader->getTitle();
      string::size_type index = ftitle.find_first_of('_');
      if (index != string::npos)
      {
         string fubstring = ftitle.substr(index+1);
         if (fubstring.size() > 16)
         {
            char tempRow[3] = {0};
            char tempCol[6] = {0};
            istringstream strm(fubstring);
            if (strm.good())
            {
               strm.read(tempRow, 2);
            }

            stringstream t(tempRow);
            t >> blockRow;

            if (strm.good())
            {
               strm.read(tempCol, 5);
            }

            t.clear();
            t << tempCol;
            t >> blockCol;
         }