vector<ImportDescriptor*> EnviLibraryImporter::getImportDescriptors(const string& filename)
{
   vector<ImportDescriptor*> descriptors;

   string headerFile = filename;
   string dataFile;
   // assume filename is a header file and try to parse
   bool bSuccess = mFields.populateFromHeader(filename);
   if (bSuccess == false)
   {
      dataFile = filename;           // was passed data file name instead of header file name
      headerFile = findHeaderFile(dataFile);
      if (headerFile.empty() == false)
      {
         bSuccess = mFields.populateFromHeader(headerFile);
      }
   }
   if (bSuccess == true)
   {
      if (dataFile.empty())  // was passed header file name and now need to find the data file name
      {
         dataFile = findDataFile(headerFile);
      }
      if (dataFile.empty())  // no data file found for the header
      {
         return descriptors;
      }

      EnviField* pField = mFields.find("file type");
      if (pField != NULL)
      {
         if (pField->mValue == "ENVI Spectral Library" || 
             pField->mValue == "Spectral Library")
         {
            // Get the name and dataset from the header values
            string name;
            string dataset;

            EnviField* pBandNamesField = mFields.find("band names");
            if (pBandNamesField != NULL)
            {
               if (pBandNamesField->mChildren.empty() == false)
               {
                  EnviField* pNameField = pBandNamesField->mChildren.front();
                  if (pNameField != NULL)
                  {
                     name = pNameField->mValue;
                  }
               }
            }

            EnviField* pDescriptionField = mFields.find("description");
            if (pDescriptionField != NULL)
            {
               // Library name
               if (name.empty() == true)
               {
                  EnviField* pNameField = pDescriptionField->find("library name");
                  if (pNameField != NULL)
                  {
                     name = pNameField->mValue;
                  }
               }

               // Dataset
               EnviField* pDatasetField = pDescriptionField->find("dataset");
               if (pDatasetField != NULL)
               {
                  dataset = pDatasetField->mValue;
               }
            }

            // Create the data descriptor
            Service<ModelServices> pModel;

            RasterElement* pRasterElement = NULL;
            if (dataset.empty() == false)
            {
               pRasterElement = dynamic_cast<RasterElement*>(pModel->getElement(dataset, "RasterElement", NULL));
            }

            if (name.empty() == true)
            {
               // Create a unique default name
               unsigned int libraryNumber = pModel->getElements(pRasterElement, "SignatureLibrary").size();

               DataElement* pSignatureLibrary = NULL;
               do
               {
                  char buffer[64];
                  sprintf(buffer, "%u", ++libraryNumber);

                  name = "Spectral Library " + string(buffer);
                  pSignatureLibrary = pModel->getElement(name, "SignatureLibrary", pRasterElement);
               }
               while (pSignatureLibrary != NULL);
            }

            ImportDescriptor* pImportDescriptor =
               pModel->createImportDescriptor(name, "SignatureLibrary", pRasterElement);
            if (pImportDescriptor != NULL)
            {
               SignatureDataDescriptor* pDescriptor =
                  dynamic_cast<SignatureDataDescriptor*>(pImportDescriptor->getDataDescriptor());
               if (pDescriptor != NULL)
               {
                  // Metadata
                  FactoryResource<DynamicObject> pMetadata;
                  if (pDescriptionField != NULL)
                  {
                     vector<EnviField*>& children = pDescriptionField->mChildren;
                     for (vector<EnviField*>::iterator iter = children.begin(); iter != children.end(); ++iter)
                     {
                        EnviField* pField = *iter;
                        if (pField != NULL)
                        {
                           if ((pField->mTag.empty() == false) && (pField->mValue.empty() == false))
                           {
                              pMetadata->setAttribute(pField->mTag, pField->mValue);
                           }
                        }
                     }
                  }

                  // Signature names
                  EnviField* pSigNamesField = mFields.find("spectra names");
                  if (pSigNamesField != NULL)
                  {
                     vector<string> sigNames;
                     for (unsigned int i = 0; i < pSigNamesField->mChildren.size(); i++)
                     {
                        EnviField* pField = pSigNamesField->mChildren[i];
                        if (pField != NULL)
                        {
                           vector<char> bufferVector(pField->mValue.size() + 1);
                           char* pBuffer = &bufferVector.front();
                           strcpy(pBuffer, pField->mValue.c_str());

                           char* pPtr = strtok(pBuffer, ",");
                           while (pPtr != NULL)
                           {
                              string sigName = StringUtilities::stripWhitespace(string(pPtr));
                              sigNames.push_back(sigName);

                              pPtr = strtok(NULL, ",");
                           }
                        }
                     }

                     if (sigNames.empty() == false)
                     {
                        pMetadata->setAttribute("Signature Names", sigNames);
                     }
                  }

                  // Signature units - Set custom units into the data descriptor so that the
                  // user can modify them even though units are not loaded from the file
                  FactoryResource<Units> pUnits;
                  pUnits->setUnitName("Custom");
                  pUnits->setUnitType(CUSTOM_UNIT);
                  pDescriptor->setUnits("Reflectance", pUnits.get());

                  // Wavelengths
                  EnviField* pSamplesField = mFields.find("samples");
                  if (pSamplesField != NULL)
                  {
                     unsigned int numWavelengths = StringUtilities::fromXmlString<unsigned int>(pSamplesField->mValue);

                     vector<double> wavelengths;
                     unsigned int uiNanometerValues = 0;

                     EnviField* pWavelengthField = mFields.find("wavelength");
                     if (pWavelengthField != NULL)
                     {
                        vector<unsigned int> goodBands;
                        EnviField* pBblField = mFields.find("bbl");
                        if (pBblField != NULL)
                        {
                           // Parse the bad bands list. This method puts the indices of good bands in ascending order.
                           EnviImporter::parseBbl(pBblField, goodBands);

                           // Sort in descending order so that the last one can be popped later
                           // A pop_back is much faster than an erase on the first element
                           reverse(goodBands.begin(), goodBands.end());
                        }

                        unsigned int numWavelengthsRead = 0;
                        for (std::vector<EnviField*>::const_iterator iter = pWavelengthField->mChildren.begin();
                           iter != pWavelengthField->mChildren.end();
                           ++iter)
                        {
                           EnviField* pField = *iter;
                           if (pField != NULL)
                           {
                              vector<char> bufferVector(pField->mValue.size() + 1);
                              char* pBuffer = &(bufferVector.front());
                              strcpy(pBuffer, pField->mValue.c_str());

                              char* pPtr = strtok(pBuffer, ",");
                              while (pPtr != NULL)
                              {
                                 double dWavelength = 0.0;
                                 if (sscanf(pPtr, "%lf", &dWavelength) == 1)
                                 {
                                    if (dWavelength > 50.0)    // Assumed to be in nanometers
                                    {
                                       uiNanometerValues++;
                                    }

                                    // Restrict the number of wavelengths to the number of samples in the header file
                                    if (numWavelengthsRead < numWavelengths)
                                    {
                                       // Only write the wavelength if the value is valid
                                       // Since the bands are in descending order,
                                       // goodBands.back() always holds the next good band.
                                       if (pBblField == NULL ||
                                          (goodBands.empty() == false && goodBands.back() == numWavelengthsRead))
                                       {
                                          if (goodBands.empty() == false)
                                          {
                                             goodBands.pop_back();
                                          }

                                          wavelengths.push_back(dWavelength);
                                       }
                                    }

                                    ++numWavelengthsRead;
                                 }

                                 pPtr = strtok(NULL, ",");
                              }
                           }
                        }

                        VERIFYNR(goodBands.empty() == true);
                     }

                     // Wavelength units
                     bool bConvertWavelengths = false;
                     bool bDetermineUnits = true;

                     EnviField* pUnitsField = mFields.find("wavelength units");
                     if (pUnitsField != NULL)
                     {
                        if (pUnitsField->mValue == "Micrometers")
                        {
                           bDetermineUnits = false;
                        }
                        else if (pUnitsField->mValue == "Nanometers")
                        {
                           bDetermineUnits = false;
                           bConvertWavelengths = true;
                        }
                     }

                     if (bDetermineUnits)
                     {
                        if ((uiNanometerValues * 100) / wavelengths.size() > 50)
                        {
                           bConvertWavelengths = true;
                        }
                     }

                     if (bConvertWavelengths == true)
                     {
                        for (vector<double>::size_type i = 0; i < wavelengths.size(); i++)
                        {
                           wavelengths[i] *= 0.001;
                        }
                     }

                     string pCenterPath[] = { SPECIAL_METADATA_NAME, BAND_METADATA_NAME, 
                        CENTER_WAVELENGTHS_METADATA_NAME, END_METADATA_NAME };
                     pMetadata->setAttributeByPath(pCenterPath, wavelengths);
                  }

                  if (pMetadata->getNumAttributes() > 0)
                  {
                     pDescriptor->setMetadata(pMetadata.get());
                  }

                  // Create the file descriptor
                  FactoryResource<SignatureFileDescriptor> pFileDescriptor;
                  if (pFileDescriptor.get() != NULL)
                  {
                     pFileDescriptor->setFilename(dataFile);
                     pDescriptor->setFileDescriptor(pFileDescriptor.get());
                  }
               }
               descriptors.push_back(pImportDescriptor);
            }
         }
      }
   }

   return descriptors;
}
Beispiel #2
0
vector<ImportDescriptor*> EnviImporter::getImportDescriptors(const string& filename)
{
   string headerFile = filename;
   string dataFile;
   bool bSuccess = parseHeader(headerFile);
   if (bSuccess == false)
   {
      dataFile = filename;           // was passed data file name instead of header file name
      headerFile = findHeaderFile(headerFile);
      if (headerFile.empty() == false)
      {
         bSuccess = parseHeader(headerFile);
      }
   }

   EnviField* pField = NULL;
   vector<ImportDescriptor*> descriptors;
   if (bSuccess == true)
   {
      if (dataFile.empty() == true)  // was passed header file name and now need to find the data file name
      {
         dataFile = findDataFile(headerFile);
      }

      if (dataFile.empty() == false)
      {
         ImportDescriptor* pImportDescriptor = mpModel->createImportDescriptor(dataFile, "RasterElement", NULL);
         if (pImportDescriptor != NULL)
         {
            RasterDataDescriptor* pDescriptor =
               dynamic_cast<RasterDataDescriptor*>(pImportDescriptor->getDataDescriptor());
            if (pDescriptor != NULL)
            {
               FactoryResource<RasterFileDescriptor> pFileDescriptor;
               if (pFileDescriptor.get() != NULL)
               {
                  // Filename
                  pFileDescriptor->setFilename(dataFile);

                  // Coordinate offset
                  int columnOffset = 0;
                  int rowOffset = 0;

                  pField = mFields.find("x start");
                  if (pField != NULL)
                  {
                     // ENVI numbers are 1 based vs Opticks being 0 based
                     columnOffset = atoi(pField->mValue.c_str()) - 1;
                  }

                  pField = mFields.find("y start");
                  if (pField != NULL)
                  {
                     rowOffset = atoi(pField->mValue.c_str()) - 1; // ENVI numbers are 1 based vs Opticks being 0 based
                  }

                  // Rows
                  vector<DimensionDescriptor> rows;
                  pField = mFields.find("lines");
                  if (pField != NULL)
                  {
                     int numRows = atoi(pField->mValue.c_str());
                     for (int i = 0; i < numRows; ++i)
                     {
                        DimensionDescriptor rowDim;
                        rowDim.setOriginalNumber(static_cast<unsigned int>(rowOffset + i));
                        rowDim.setOnDiskNumber(static_cast<unsigned int>(i));
                        rows.push_back(rowDim);
                     }

                     pDescriptor->setRows(rows);
                     pFileDescriptor->setRows(rows);
                  }

                  string samplesStr = "samples";
                  string bandsStr = "bands";

                  // Special case: if the file type is an ENVI Spectral Library, then swap samples with bands
                  // If no file type field exists, assume this is a normal ENVI header (not a Spectral Library)
                  EnviField* pFileTypeField = mFields.find("file type");
                  if (pFileTypeField != NULL && (pFileTypeField->mValue ==
                     "ENVI Spectral Library" || pFileTypeField->mValue == "Spectral Library"))
                  {
                     samplesStr = "bands";
                     bandsStr = "samples";

                     // Since bands and samples are swapped, force the interleave to BIP
                     pField = mFields.find("interleave");
                     if (pField != NULL)
                     {
                        pField->mValue = "bip";
                     }
                  }

                  // Columns
                  vector<DimensionDescriptor> columns;
                  pField = mFields.find(samplesStr);
                  if (pField != NULL)
                  {
                     int numColumns = atoi(pField->mValue.c_str());
                     for (int i = 0; i < numColumns; ++i)
                     {
                        DimensionDescriptor columnDim;
                        columnDim.setOriginalNumber(static_cast<unsigned int>(columnOffset + i));
                        columnDim.setOnDiskNumber(static_cast<unsigned int>(i));
                        columns.push_back(columnDim);
                     }

                     pDescriptor->setColumns(columns);
                     pFileDescriptor->setColumns(columns);
                  }

                  // Bands
                  vector<DimensionDescriptor> bands;
                  pField = mFields.find(bandsStr);
                  if (pField != NULL)
                  {
                     int numBands = atoi(pField->mValue.c_str());
                     bands = RasterUtilities::generateDimensionVector(numBands, true, false, true);
                     pDescriptor->setBands(bands);
                     pFileDescriptor->setBands(bands);
                  }

                  // Description
                  list<GcpPoint> gcps;

                  pField = mFields.find("description");
                  if (pField != NULL)
                  {
                     // Metadata
                     if (pField->mChildren.empty() == false)
                     {
                        FactoryResource<DynamicObject> pMetadata;
                        for (unsigned int i = 0; i < pField->mChildren.size(); ++i)
                        {
                           EnviField* pChild = pField->mChildren[i];
                           if (pChild != NULL)
                           {
                              if (pChild->mTag == "classification")
                              {
                                 // Classification
                                 FactoryResource<Classification> pClassification;
                                 if (pClassification.get() != NULL)
                                 {
                                    string classLevel;
                                    classLevel.append(1, *(pChild->mValue.data()));
                                    pClassification->setLevel(classLevel);

                                    pDescriptor->setClassification(pClassification.get());
                                 }
                              }
                              else if ((pChild->mTag == "ll") || (pChild->mTag == "lr") || (pChild->mTag == "ul") ||
                                 (pChild->mTag == "ur") || (pChild->mTag == "center"))
                              {
                                 GcpPoint gcp;
                                 bool dmsFormat = false;
                                 char ns;
                                 char ew;

                                 sscanf(pChild->mValue.c_str(), "%lg%c %lg%c", &gcp.mCoordinate.mY, &ew,
                                    &gcp.mCoordinate.mX, &ns);
                                 if (fabs(gcp.mCoordinate.mY) > 180.0 || fabs(gcp.mCoordinate.mX) > 90.0)
                                 {
                                    dmsFormat = true;
                                 }

                                 double deg;
                                 double min;
                                 double sec;
                                 if (dmsFormat == true)
                                 {
                                    deg = static_cast<int>(gcp.mCoordinate.mY / 10000.0);
                                    min = static_cast<int>((gcp.mCoordinate.mY - 10000.0 * deg) / 100.0);
                                    sec = gcp.mCoordinate.mY - 10000.0 * deg - 100.0 * min;
                                    gcp.mCoordinate.mY = deg + (min / 60.0) + (sec / 3600.0);
                                 }

                                 if (ew == 'W' || ew == 'w')
                                 {
                                    gcp.mCoordinate.mY = -gcp.mCoordinate.mY;
                                 }

                                 if (dmsFormat)
                                 {
                                    deg = static_cast<int>(gcp.mCoordinate.mX / 10000.0);
                                    min = static_cast<int>((gcp.mCoordinate.mX - 10000.0 * deg) / 100.0);
                                    sec = gcp.mCoordinate.mX - 10000.0 * deg - 100.0 * min;
                                    gcp.mCoordinate.mX = deg + (min / 60.0) + (sec / 3600.0);
                                 }

                                 if (ns == 'S' || ns == 's')
                                 {
                                    gcp.mCoordinate.mX = -gcp.mCoordinate.mX;
                                 }

                                 // ENVI uses a 1-based pixel coordinate system, with each coordinate referring
                                 // to the top-left corner of the pixel, e.g. (1,1) is the top-left
                                 // corner of the pixel in the top-left of the raster cube
                                 // The ENVI pixel coordinate format is described on p. 1126 of the ENVI 4.2 User's Guide
                                 if (pChild->mTag == "ll")
                                 {
                                    gcp.mPixel.mX = 0.0;
                                    gcp.mPixel.mY = 0.0;
                                 }
                                 else if (pChild->mTag == "lr")
                                 {
                                    gcp.mPixel.mX = columns.size() - 1.0;
                                    gcp.mPixel.mY = 0.0;
                                 }
                                 else if (pChild->mTag == "ul")
                                 {
                                    gcp.mPixel.mX = 0.0;
                                    gcp.mPixel.mY = rows.size() - 1.0;
                                 }
                                 else if (pChild->mTag == "ur")
                                 {
                                    gcp.mPixel.mX = columns.size() - 1.0;
                                    gcp.mPixel.mY = rows.size() - 1.0;
                                 }
                                 else if (pChild->mTag == "center")
                                 {
                                    gcp.mPixel.mX = floor((columns.size() - 1.0) / 2.0);
                                    gcp.mPixel.mY = floor((rows.size() - 1.0) / 2.0);
                                 }

                                 gcps.push_back(gcp);
                              }
                              else if (pChild->mTag.empty() == false)
                              {
                                 pMetadata->setAttribute(pChild->mTag, pChild->mValue);
                              }
                           }
                        }

                        if (pMetadata->getNumAttributes() > 0)
                        {
                           pDescriptor->setMetadata(pMetadata.get());
                        }
                     }
                  }

                  if (gcps.empty())  // not in description, check for geo points keyword
                  {
                     pField = mFields.find("geo points");
                     if (pField != NULL)
                     {
                        vector<double> geoValues;
                        const int expectedNumValues = 16;  // 4 values for each of the 4 corners
                        geoValues.reserve(expectedNumValues);
                        for (unsigned int i = 0; i < pField->mChildren.size(); i++)
                        {
                           vectorFromField(pField->mChildren.at(i), geoValues, "%lf");
                        }

                        if (geoValues.size() == expectedNumValues)
                        {
                           vector<double>::iterator iter = geoValues.begin();
                           GcpPoint gcp;
                           while (iter != geoValues.end())
                           {
                              gcp.mPixel.mX = *iter++ - 1.0;  // adjust ref point for ENVI's use of
                              gcp.mPixel.mY = *iter++ - 1.0;  // upper left corner and one-based first pixel
                              gcp.mCoordinate.mX = *iter++;   // GcpPoint has lat as mX and Lon as mY 
                              gcp.mCoordinate.mY = *iter++;   // geo point field has lat then lon value
                              gcps.push_back(gcp);
                           }
                        }
                     }
                  }

                  // GCPs
                  if (gcps.empty() == false)
                  {
                     pFileDescriptor->setGcps(gcps);
                  }

                  // Header bytes
                  pField = mFields.find("header offset");
                  if (pField != NULL)
                  {
                     int headerBytes = atoi(pField->mValue.c_str());
                     pFileDescriptor->setHeaderBytes(static_cast<unsigned int>(headerBytes));
                  }

                  // Data type
                  pField = mFields.find("data type");
                  if (pField != NULL)
                  {
                     vector<EncodingType> validDataTypes;
                     switch (atoi(pField->mValue.c_str()))
                     {
                        case 1:     // char
                           pDescriptor->setDataType(INT1UBYTE);
                           pFileDescriptor->setBitsPerElement(8);
                           
                           // signed char cannot be represented in ENVI header so use the closest thing
                           validDataTypes.push_back(INT1SBYTE);
                           break;

                        case 2:     // short
                           pDescriptor->setDataType(INT2SBYTES);
                           pFileDescriptor->setBitsPerElement(16);
                           break;

                        case 3:     // int
                           pDescriptor->setDataType(INT4SBYTES);
                           pFileDescriptor->setBitsPerElement(32);
                           break;

                        case 4:     // float
                           pDescriptor->setDataType(FLT4BYTES);
                           pFileDescriptor->setBitsPerElement(32);
                           break;

                        case 5:     // double
                           pDescriptor->setDataType(FLT8BYTES);
                           pFileDescriptor->setBitsPerElement(64);
                           break;

                        case 6:     // float complex
                           pDescriptor->setDataType(FLT8COMPLEX);
                           pFileDescriptor->setBitsPerElement(64);
                           break;

                        case 9:     // double complex
                           // not supported
                           break;

                        case 12:    // unsigned short
                           pDescriptor->setDataType(INT2UBYTES);
                           pFileDescriptor->setBitsPerElement(16);
                           break;

                        case 13:    // unsigned int
                           pDescriptor->setDataType(INT4UBYTES);
                           pFileDescriptor->setBitsPerElement(32);
                           break;

                        case 14:    // 64-bit int
                        case 15:    // unsigned 64-bit int
                           // not supported
                           break;

                        case 99:    // integer complex (recognized only by this application)
                           pDescriptor->setDataType(INT4SCOMPLEX);
                           pFileDescriptor->setBitsPerElement(32);
                           break;

                        default:
                           break;
                     }

                     // Bad values
                     EncodingType dataType = pDescriptor->getDataType();
                     if ((dataType != FLT4BYTES) && (dataType != FLT8COMPLEX) && (dataType != FLT8BYTES))
                     {
                        vector<int> badValues;
                        badValues.push_back(0);

                        pDescriptor->setBadValues(badValues);
                     }

                     validDataTypes.push_back(dataType);
                     pDescriptor->setValidDataTypes(validDataTypes);
                  }

                  // Interleave format
                  pField = mFields.find("interleave");
                  if (pField != NULL)
                  {
                     string interleave = StringUtilities::toLower(pField->mValue);
                     if (interleave == "bip")
                     {
                        pDescriptor->setInterleaveFormat(BIP);
                        pFileDescriptor->setInterleaveFormat(BIP);
                     }
                     else if (interleave == "bil")
                     {
                        pDescriptor->setInterleaveFormat(BIL);
                        pFileDescriptor->setInterleaveFormat(BIL);
                     }
                     else if (interleave == "bsq")
                     {
                        pDescriptor->setInterleaveFormat(BSQ);
                        pFileDescriptor->setInterleaveFormat(BSQ);
                     }
                  }

                  // Endian
                  pField = mFields.find("byte order");
                  if (pField != NULL)
                  {
                     int byteOrder = atoi(pField->mValue.c_str());
                     if (byteOrder == 0)
                     {
                        pFileDescriptor->setEndian(LITTLE_ENDIAN_ORDER);
                     }
                     else if (byteOrder == 1)
                     {
                        pFileDescriptor->setEndian(BIG_ENDIAN_ORDER);
                     }
                  }

                  // check for scaling factor
                  pField = mFields.find("reflectance scale factor");
                  if (pField != NULL)
                  {
                     double scalingFactor = 0.0;
                     stringstream scaleStream(pField->mValue);
                     scaleStream >> scalingFactor;
                     if (!scaleStream.fail() && scalingFactor != 0.0)
                     {
                        Units* pUnits = pDescriptor->getUnits();
                        if (pUnits != NULL)
                        {
                           pUnits->setScaleFromStandard(1.0 / scalingFactor);
                           pUnits->setUnitName("Reflectance");
                           pUnits->setUnitType(REFLECTANCE);
                        }
                     }
                  }

                  // Pixel size
                  pField = mFields.find("pixel size");
                  if (pField != NULL)
                  {
                     if (pField->mChildren.size() == 2)
                     {
                        pField = pField->mChildren[0];
                        if (pField != NULL)
                        {
                           double pixelSize = 1.0;
                           if (sscanf(pField->mValue.c_str(), "%g", &pixelSize) == 1)
                           {
                              pDescriptor->setXPixelSize(pixelSize);
                              pFileDescriptor->setXPixelSize(pixelSize);
                           }
                        }

                        pField = pField->mChildren[1];
                        if (pField != NULL)
                        {
                           double pixelSize = 1.0;
                           if (sscanf(pField->mValue.c_str(), "%g", &pixelSize) == 1)
                           {
                              pDescriptor->setYPixelSize(pixelSize);
                              pFileDescriptor->setYPixelSize(pixelSize);
                           }
                        }
                     }
                  }

                  // Default bands
                  pField = mFields.find("default bands");
                  if (pField != NULL)
                  {
                     vector<unsigned int> displayBands;
                     parseDefaultBands(pField, &displayBands);

                     if (displayBands.size() == 1)
                     {
                        DimensionDescriptor grayBand = pFileDescriptor->getOriginalBand(displayBands[0]);

                        pDescriptor->setDisplayBand(GRAY, grayBand);
                        pDescriptor->setDisplayMode(GRAYSCALE_MODE);
                     }
                     else if (displayBands.size() == 3)
                     {
                        DimensionDescriptor redBand = pFileDescriptor->getOriginalBand(displayBands[0]);
                        DimensionDescriptor greenBand = pFileDescriptor->getOriginalBand(displayBands[1]);
                        DimensionDescriptor blueBand = pFileDescriptor->getOriginalBand(displayBands[2]);

                        pDescriptor->setDisplayBand(RED, redBand);
                        pDescriptor->setDisplayBand(GREEN, greenBand);
                        pDescriptor->setDisplayBand(BLUE, blueBand);
                        pDescriptor->setDisplayMode(RGB_MODE);
                     }
                  }

                  // Bad bands
                  pField = mFields.find("bbl");
                  if (pField != NULL)
                  {
                     vector<unsigned int> validBands;
                     parseBbl(pField, validBands);

                     vector<DimensionDescriptor> bandsToLoad;
                     for (vector<unsigned int>::const_iterator iter = validBands.begin();
                        iter != validBands.end();
                        ++iter)
                     {
                        const unsigned int onDiskNumber = *iter;
                        const DimensionDescriptor dim = pFileDescriptor->getOnDiskBand(onDiskNumber);
                        if (dim.isValid())
                        {
                           bandsToLoad.push_back(dim);
                        }
                     }

                     pDescriptor->setBands(bandsToLoad);
                  }

                  DynamicObject* pMetadata = pDescriptor->getMetadata();

                  // Band names
                  pField = mFields.find("band names");
                  if (pField != NULL)
                  {
                     vector<string> bandNames;
                     bandNames.reserve(bands.size());
                     vector<string> strNames;
                     for (vector<EnviField*>::size_type i = 0; i < pField->mChildren.size(); ++i)
                     {
                        strNames = StringUtilities::split(pField->mChildren[i]->mValue, ',');
                        copy(strNames.begin(), strNames.end(), back_inserter(bandNames));
                     }
                     vector<string>::iterator it;
                     for (it = bandNames.begin(); it != bandNames.end(); ++it)
                     {
                        *it = StringUtilities::stripWhitespace(*it);
                     }

                     if (pMetadata != NULL)
                     {
                        string pNamesPath[] = { SPECIAL_METADATA_NAME, BAND_METADATA_NAME,
                           NAMES_METADATA_NAME, END_METADATA_NAME };
                        pMetadata->setAttributeByPath(pNamesPath, bandNames);
                     }
                  }

                  // wavelength units
                  pField = mFields.find("wavelength units");
                  if (pField != NULL)
                  {
                     mWavelengthUnits = strToType(pField->mValue);
                  }

                  // Wavelengths
                  vector<double> centerWavelengths;
                  pField = mFields.find("wavelength");
                  if (pField != NULL)
                  {
                     if ((parseWavelengths(pField, &centerWavelengths) == true) && (pMetadata != NULL))
                     {
                        string pCenterPath[] = { SPECIAL_METADATA_NAME, BAND_METADATA_NAME,
                           CENTER_WAVELENGTHS_METADATA_NAME, END_METADATA_NAME };
                        pMetadata->setAttributeByPath(pCenterPath, centerWavelengths);
                     }
                  }

                  // FWHM
                  pField = mFields.find("fwhm");
                  if (pField != NULL)
                  {
                     vector<double> startWavelengths;
                     vector<double> endWavelengths;

                     if ((parseFwhm(pField, &startWavelengths, &centerWavelengths, &endWavelengths) == true) &&
                        (pMetadata != NULL))
                     {
                        string pStartPath[] = { SPECIAL_METADATA_NAME, BAND_METADATA_NAME,
                           START_WAVELENGTHS_METADATA_NAME, END_METADATA_NAME };
                        pMetadata->setAttributeByPath(pStartPath, startWavelengths);
                        string pEndPath[] = { SPECIAL_METADATA_NAME, BAND_METADATA_NAME,
                           END_WAVELENGTHS_METADATA_NAME, END_METADATA_NAME };
                        pMetadata->setAttributeByPath(pEndPath, endWavelengths);
                     }
                  }

                  // File descriptor
                  pDescriptor->setFileDescriptor(pFileDescriptor.get());
               }