Hi,

i have a patch for gdal 1.7.3 to improve isis2 driver.
The patch had
* writing functionality for QUBE object
* grab null value
* improve the type reading
* can read qube with back plane, side plane and bottom plane
* can read a file with label detached or attached.

and i have modify nasakeyword handler to reduce sensibility of parser to little error on comment. (Like if we have char after end comment.)

but i have rewrite/move a lot of lines... I use this patch for a research project from one year ago. I work on hyperspectral data with OTB library.

I think is it possible to easily merge pdsdataset.cpp and isis2dataset.cpp
pdsdataset work on IMAGE tag and isis2 on QUBE tag but it is the same workflow for all object (QUBE, IMAGE or SPECTRAL_QUBE)

Warning for writing no geographical information are writing now, and create_copy is not implemented.

Ludovic.

Index: gdal-1.7.3/frmts/pds/isis2dataset.cpp
===================================================================
--- gdal-1.7.3/frmts/pds/isis2dataset.cpp	(révision 588)
+++ gdal-1.7.3/frmts/pds/isis2dataset.cpp	(révision 613)
@@ -5,6 +5,7 @@
  * Purpose:  Implementation of ISIS2Dataset
  * Author:   Trent Hare (th...@usgs.gov),
  *           Robert Soricone (rsoric...@usgs.gov)
+ * Modify by Ludovic Mercier (ludovic.merc...@gmail.com)
  *
  * NOTE: Original code authored by Trent and Robert and placed in the public 
  * domain as per US government policy.  I have (within my rights) appropriated 
@@ -32,17 +33,39 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
-#define NULL1 0
-#define NULL2 -32768
-//#define NULL3 0xFF7FFFFB //in hex
-//Same as ESRI_GRID_FLOAT_NO_DATA
-//#define NULL3 -340282346638528859811704183484516925440.0
-#define NULL3 -3.4028226550889044521e+38
+/** Null value ( extract of pds documentation )
+ * For Standard ISIS Qubes, the null value is chosen
+ * to be the algebraically smallest value allowed by the
+ * core_item_type and core_item_bytes elements. The general
+ * data type of this element is determined by the
+ * core_item_type element.  If the latter is integer or
+ * unsigned integer, the general data type is integer.  If
+ * core_item_type is real, the value will be hardware-
+ * specific (or rather floating-point-representation-specific)
+ * so that it may be specified exactly at the bottom of the
+ * allowable range of values. A non-decimal (hexadecimal)
+ * general data type is used for this purpose;
+ */
+#define NULL_INTEGER_1 0
+#define NULL_INTEGER_2 -32768
+#define NULL_INTEGER_4 -2147483648
+#define NULL_REAL -3.4028226550889044521e+38
 
 #ifndef PI
 #  define PI 3.1415926535897932384626433832795
 #endif
 
+#define RECORD_SIZE 512
+
+// TODO check if necessary
+#include <fstream>
+#include <sstream>
+#include <exception>
+#include <string>
+#include <iostream>
+#include <stdlib.h>
+// end check
+
 #include "rawdataset.h"
 #include "ogr_spatialref.h"
 #include "cpl_string.h" 
@@ -60,6 +83,20 @@
 /* ==================================================================== */
 /************************************************************************/
 
+class ISIS2DatasetError : public std::exception
+{
+	public:
+	ISIS2DatasetError(CPLString description="ISIS2Dataset internal error") throw() :
+		sDescription(description){}
+
+	private:
+	CPLString sDescription;
+
+	virtual const char* what() const throw(){
+		return sDescription;
+	}
+};
+
 class ISIS2Dataset : public RawDataset
 {
     FILE	*fpImage;	// image data file.
@@ -74,9 +111,22 @@
     int parse_label(const char *file, char *keyword, char *value);
     int strstrip(char instr[], char outstr[], int position);
 
+    struct DataSize {
+    	unsigned int nSample;
+    	unsigned int nLine;
+    	unsigned int nBand;
+    };
+
+    struct SuffixSize {
+    	unsigned int nX; // side plane
+    	unsigned int nY; // bottom plane
+    	unsigned int nZ; // back plane
+    };
+
     CPLString   oTempResult;
 
     void        CleanString( CPLString &osInput );
+    void        SetKeywords();
 
     const char *GetKeyword( const char *pszPath, 
                             const char *pszDefault = "");
@@ -84,10 +134,37 @@
                                int iSubscript, 
                                const char *pszDefault = "");
 
+    unsigned int GetSuffixSize(CPLString sAxeName, unsigned int nAxeDim, unsigned int nDefaultSuffixSizeElement);
+
+ 	static CPLString GetFilename(const char* pszFilename, CPLString & osLabelFile, CPLString & osRasterFile);
+    static void WriteRaster(CPLString osFilename, bool includeLabel, GUIntBig iRecord, GUIntBig iLabelRecords, GDALDataType eType, const char * pszInterleaving);
+
+    static void WriteLabel(CPLString osFilename, CPLString osRasterFile, CPLString sObjectTag, unsigned int nXSize, unsigned int nYSize, unsigned int nBands, GDALDataType eType,
+    						GUIntBig iRecords, const char * pszInterleaving, GUIntBig & iLabelRecords, bool bRelaunch=false);
+    static void WriteQUBE_Information(FILE *fpLabel, unsigned int iLevel, unsigned int & nWritingBytes,
+    						unsigned int nXSize, unsigned int nYSize, unsigned int nBands, const char * pszInterleaving);
+
+    static unsigned int WriteKeyword(FILE *fpLabel, unsigned int iLevel, CPLString key, CPLString value);
+    static unsigned int WriteFormatting(FILE *fpLabel, CPLString data);
+    static GUIntBig RecordSizeCalculation(unsigned int nXSize, unsigned int nYSize, unsigned int nBands, GDALDataType eType );
+    static GUIntBig GrabByteFlag(CPLString sValue, bool & bByteLocation);
+
+    static CPLString GetSampleType(CPLString);
+    static void GetSampleFormat(int itype, CPLString sDataType, GDALDataType & eDataType, double & dfNoData, bool & bNoDataSet, bool bByteUnit);
+    static char GetWordOrder(CPLString sSampleType);
+    static void ComputeOffset(CPLString sLayout, DataSize dataSize, SuffixSize suffixSize, GDALDataType eDataType, int & nPixelOffset, int & nLineOffset, int & nBandOffset);
+    static GDALDataset *OpenQUB(const char *pszObjectName, GDALOpenInfo *poOpenInfo, ISIS2Dataset *poDS);
+    static GDALDataset *OpenIMAGE(const char *pszObjectName, GDALOpenInfo *poOpenInfo, ISIS2Dataset *poDS);
+    static GDALDataset *OpenSPECTRAL_QUBE(const char *pszObjectName, GDALOpenInfo *poOpenInfo, ISIS2Dataset *poDS);
+
+    static int Identify( GDALOpenInfo * poOpenInfo );
+
 public:
     ISIS2Dataset();
     ~ISIS2Dataset();
   
+    void FlushCache();
+  
     virtual CPLErr GetGeoTransform( double * padfTransform );
     virtual const char *GetProjectionRef(void);
   
@@ -126,6 +203,17 @@
 }
 
 /************************************************************************/
+/*                          FlushCache()                                */
+/************************************************************************/
+void ISIS2Dataset::FlushCache() {
+  CPLDebug("ISIS2", "Flush Cache getdescription = %s", GetDescription());
+  //don't generate auxilary xml file
+  //RawDataset::GDALDataset::FlushCache();
+  RawDataset::FlushCache();
+}
+
+
+/************************************************************************/
 /*                          GetProjectionRef()                          */
 /************************************************************************/
 
@@ -157,18 +245,85 @@
 }
 
 /************************************************************************/
+/*                              Identify()                              */
+/************************************************************************/
+
+int ISIS2Dataset::Identify( GDALOpenInfo * poOpenInfo )
+{
+    if( poOpenInfo->pabyHeader == NULL )
+        return FALSE;
+
+    return strstr((char*)poOpenInfo->pabyHeader,"PDS_VERSION_ID") != NULL;
+}
+
+/************************************************************************/
+/*                            GetSuffixSize()                           */
+/************************************************************************/
+unsigned int ISIS2Dataset::GetSuffixSize(CPLString sAxeName, unsigned int nAxeDim, unsigned int nDefaultSuffixSizeElement)
+{
+	unsigned int nSize(0);
+	if(nAxeDim != 0){
+		CPLString sSuffixName = sAxeName.append("_SUFFIX_ITEM_BYTES");
+		const char * sSuffixValue = GetKeyword( sSuffixName, "NA" );
+		if(EQUAL(sSuffixValue, "NA")){
+			// this case is only for a genralized Qube not isis Qube
+			// @see PDS Standard A.23.2
+			nSize = nAxeDim * nDefaultSuffixSizeElement;
+		}else{
+			if(sSuffixValue[0] == '('){
+				for(unsigned int i=0; i<nAxeDim; ++i){
+					nSize += strtoul(GetKeywordSub( sSuffixName, i+1 ), NULL, 0);
+				}
+			}else{
+				try{
+					nSize = strtoul( sSuffixValue, NULL, 0);
+				}catch(...){
+					throw ISIS2DatasetError(CPLString().Printf("Failed to grab suffix value for axe : %s", sAxeName.c_str()));
+				}
+			}
+		}
+	}
+	return nSize;
+}
+
+/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
 GDALDataset *ISIS2Dataset::Open( GDALOpenInfo * poOpenInfo )
 {
+	CPLDebug("ISIS2","*** Open");
 /* -------------------------------------------------------------------- */
-/*      Does this look like a CUBE dataset?                             */
+/*      Does this look like a CUBE or an IMAGE Primary Data Object      */
+/*      See chapter 4 of PDS Standards Reference                        */
+/* 	    Only the first kilobyte is read by GDAL but a PDS file can      */
+/*      contain other object whith image like HISTOGRAM in first.       */
+/*      So we must check if it a pds data file and after                */
+/*	    if we have an image object (QUBE, IMAGE, etc.)                  */
 /* -------------------------------------------------------------------- */
-    if( poOpenInfo->pabyHeader == NULL
-        || strstr((const char *)poOpenInfo->pabyHeader,"^QUBE") == NULL )
+    if( poOpenInfo->pabyHeader == NULL )
         return NULL;
 
+    if( !Identify( poOpenInfo ) )
+    {
+    	CPLError(CE_Warning, CPLE_WrongFormat,
+                "It appears this is an older PDS image type.  Only PDS_VERSION_ID = PDS3 are currently supported by this gdal PDS reader. I can try to open.");
+    	//return NULL;
+    }
+
+    if( strstr((const char *)poOpenInfo->pabyHeader,"^QUBE") == NULL &&
+    	strstr((const char *)poOpenInfo->pabyHeader,"^IMAGE") == NULL &&
+    	strstr((const char *)poOpenInfo->pabyHeader,"^SPECTRAL_QUBE") == NULL &&
+    	// not an image but an PDS data object
+    	strstr((const char *)poOpenInfo->pabyHeader,"^HISTORY") == NULL &&
+    	strstr((const char *)poOpenInfo->pabyHeader,"^HISTOGRAM") == NULL &&
+    	strstr((const char *)poOpenInfo->pabyHeader,"^PALETTE") == NULL &&
+    	strstr((const char *)poOpenInfo->pabyHeader,"^HEADER") == NULL )
+    {
+    	CPLDebug("header ",CPLString().Printf("nHeaderBytes = %d",poOpenInfo->nHeaderBytes), (const char *)poOpenInfo->pabyHeader);
+        return NULL;
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Open the file using the large file API.                         */
 /* -------------------------------------------------------------------- */
@@ -190,23 +345,236 @@
     
     VSIFCloseL( fpQube );
 
+
+    try{
+		const char *pszQube = poDS->GetKeyword( "^QUBE" );
+		if(!EQUAL(pszQube,"")){
+			CPLDebug("ISIS2","cube keyword found" );
+			return ISIS2Dataset::OpenQUB(pszQube, poOpenInfo, poDS);
+		}
+
+		const char *pszImage = poDS->GetKeyword( "^IMAGE" );
+		if(!EQUAL(pszImage,"")){
+			CPLDebug("ISIS2","image keyword found" );
+			return ISIS2Dataset::OpenIMAGE(pszImage, poOpenInfo, poDS);
+		}
+
+		const char *pszSpectralQube = poDS->GetKeyword( "^SPECTRAL_QUBE" );
+		if(!EQUAL(pszSpectralQube,"")){
+			CPLDebug("ISIS2","spectral cube keyword found" );
+			return ISIS2Dataset::OpenSPECTRAL_QUBE(pszSpectralQube, poOpenInfo, poDS);
+		}
+    }catch(std::exception &e){
+    	CPLError( CE_Failure, CPLE_OpenFailed, e.what());
+    	return NULL;
+	}
+
+    CPLError( CE_Failure, CPLE_OpenFailed,"*** ISIS 2 failed to find good object : QUB, IMAGE or SPECTRAL_QUBE");
+    return NULL;
+}
+
+
+GDALDataset *ISIS2Dataset::OpenSPECTRAL_QUBE(const char* pszObjectName, GDALOpenInfo *poOpenInfo, ISIS2Dataset *poDS){
+	CPLError( CE_Failure, CPLE_OpenFailed,"*** ISIS 2 spectral qube reading no implemented");
+	return NULL;
+}
+
+/**
+ * PDS Datatype are described in chapter3 of PDS Standards Refecrences
+ */
+CPLString ISIS2Dataset::GetSampleType(CPLString sSampleType) {
+	CPLString sOutSampleType;
+	if( EQUAL(sSampleType, "MSB_INTEGER") || EQUAL(sSampleType, "INTEGER") ||
+		EQUAL(sSampleType, "LSB_INTEGER") || EQUAL(sSampleType, "PC_INTEGER"))
+		sOutSampleType = "INTEGER";
+	else if( EQUAL(sSampleType, "MSB_UNSIGNED_INTEGER") || EQUAL(sSampleType, "UNSIGNED_INTEGER") ||
+			 EQUAL(sSampleType, "LSB_UNSIGNED_INTEGER") || EQUAL(sSampleType, "PC_UNSIGNED_INTEGER"))
+		sOutSampleType = "UNSIGNED_INTEGER";
+	else if(EQUAL(sSampleType, "IEEE_REAL") || EQUAL(sSampleType, "REAL") ||
+			EQUAL(sSampleType, "FLOAT") || EQUAL(sSampleType, "PC_REAL"))
+		sOutSampleType = "REAL";
+	else
+		throw ISIS2DatasetError(CPLString().Printf("*** ISIS2 Invalid sample type : %s", sSampleType.c_str()));
+	return sOutSampleType;
+}
+
+/**
+ * PDS Data format are describe in chapter3 and annexe of PDS Standards References
+ */
+void ISIS2Dataset::GetSampleFormat(int itype, CPLString sDataType, GDALDataType & eDataType,
+									double & dfNoData, bool & bNoDataSet, bool bByteUnit) {
+	bool bInvalidSampleType = true;
+	if(bByteUnit)
+		itype = itype * 8;
+	switch(itype) {
+		case 8 :
+			if( EQUAL(sDataType, "INTEGER") ||
+				EQUAL(sDataType, "MSB_INTEGER") ||
+				EQUAL(sDataType, "UNSIGNED_INTEGER") ||
+				EQUAL(sDataType, "MSB_UNSIGNED_INTEGER")) {
+				eDataType = GDT_Byte;
+				bInvalidSampleType = false;
+				dfNoData = NULL_INTEGER_1;
+				bNoDataSet = TRUE;
+			}
+			break;
+		case 16 :
+			if( EQUAL(sDataType, "INTEGER") ||
+				EQUAL(sDataType, "MSB_INTEGER") ||
+				EQUAL(sDataType, "UNSIGNED_INTEGER") ||
+				EQUAL(sDataType, "MSB_UNSIGNED_INTEGER")) {
+				eDataType = GDT_Int16;
+				bInvalidSampleType = false;
+				dfNoData = NULL_INTEGER_2;
+				bNoDataSet = TRUE;
+			}
+			break;
+		case 32 :
+			if( EQUAL(sDataType, "INTEGER")) {
+				eDataType = GDT_Int32;
+				bInvalidSampleType = false;
+				dfNoData = NULL_INTEGER_4;
+				bNoDataSet = TRUE;
+			}
+			else if( EQUAL(sDataType, "UNSIGNED_INTEGER") ||
+					 EQUAL(sDataType, "MSB_UNSIGNED_INTEGER")) {
+				eDataType = GDT_UInt32;
+				bInvalidSampleType = false;
+				dfNoData = NULL_INTEGER_4;
+				bNoDataSet = TRUE;
+			}
+			else if( EQUAL(sDataType, "REAL")) {
+				eDataType = GDT_Float32;
+				bInvalidSampleType = false;
+				dfNoData = NULL_REAL;
+				bNoDataSet = TRUE;
+			}
+			bNoDataSet = TRUE;
+			break;
+		case 64 :
+			if( EQUAL(sDataType, "REAL") ) {
+				eDataType = GDT_Float64;
+				bInvalidSampleType = false;
+				dfNoData = NULL_REAL;
+				bNoDataSet = TRUE;
+			}
+		default :
+			break;
+		}
+	if(bInvalidSampleType){
+		throw ISIS2DatasetError(
+				CPLString().Printf("*** ISIS2 Sample bits of %d with sample type %s is not supported in ISIS 2.",
+						itype,
+						sDataType.c_str()));
+	}
+}
+
+/**
+ * default to MSB (Most Significant Byte)
+ */
+char ISIS2Dataset::GetWordOrder(CPLString sSampleType){
+	if( EQUAL(sSampleType,"PC_INTEGER") ||
+		EQUAL(sSampleType,"LSB_INTEGER") ||
+		EQUAL(sSampleType,"VAX_INTEGER") ||
+		EQUAL(sSampleType,"PC_UNSIGNED_INTEGER") ||
+		EQUAL(sSampleType,"LSB_UNSIGNED_INTEGER") ||
+		EQUAL(sSampleType,"VAX_UNSIGNED_INTEGER") ||
+		EQUAL(sSampleType,"PC_REAL"))
+		return 'I';
+	return 'M';
+}
+
+/**
+ *      Compute the pixel, line and band offset.
+ */
+void ISIS2Dataset::ComputeOffset(CPLString sLayout, DataSize dataSize, SuffixSize suffixSize, GDALDataType eDataType, int & nPixelOffset, int & nLineOffset, int & nBandOffset) {
+	CPLDebug("ISIS2", CPLString().Printf("suffix size %d, %d, %d\n", suffixSize.nX, suffixSize.nY, suffixSize.nZ));
+	int nItemSize = GDALGetDataTypeSize(eDataType)/8;
+
+	if( EQUAL(sLayout,"BIP") ) /* band interleave by pixel : BAND,SAMPLE,LINE */
+	{
+		nBandOffset = nItemSize;
+		nPixelOffset = nBandOffset * dataSize.nBand + suffixSize.nX;
+		nLineOffset = nPixelOffset * dataSize.nSample + suffixSize.nY * dataSize.nBand;
+
+	}
+	else if( EQUAL(sLayout,"BSQ") ) /* band sequential : SAMPLE,LINE,BAND */
+	{
+		nPixelOffset = nItemSize;
+		nLineOffset = nPixelOffset * dataSize.nSample + suffixSize.nX;
+		nBandOffset = nLineOffset * dataSize.nLine + suffixSize.nY * dataSize.nSample;
+	}
+	else /* assume BIL, band interleave by line : SAMPLE, BAND, LINE */
+	{
+		nPixelOffset = nItemSize;
+		nBandOffset  = nPixelOffset * dataSize.nSample + suffixSize.nX;
+		nLineOffset  = nBandOffset * dataSize.nBand + suffixSize.nY * dataSize.nSample;
+	}
+}
+
+
+/*
+ * Open Image Object @see Pds standard
+ * In this time the pdsdataset containt the IMAGE tag parser.
+ */
+GDALDataset *ISIS2Dataset::OpenIMAGE(const char* pszObjectName, GDALOpenInfo *poOpenInfo, ISIS2Dataset *poDS){
+	CPLError( CE_Failure, CPLE_OpenFailed,"*** ISIS 2 image reading no implemented");
+	return NULL;
+}
+
+/* For objectName (sValue) see OpenQUB
+ * Extract nnn value and check BYTES flag
+ */
+GUIntBig ISIS2Dataset::GrabByteFlag(CPLString sValue, bool & bByteLocation){
+	GUIntBig n;
+	char **papszTokens = CSLTokenizeString2( sValue, "<>", CSLT_STRIPLEADSPACES );
+	try {
+		n = atoll(papszTokens[0]);
+	}catch(...){
+		throw ISIS2DatasetError(CPLString().Printf("Failed to grab object value : %s", sValue.c_str()));
+	}
+	if(papszTokens[1] != NULL){
+		bByteLocation = EQUAL(papszTokens[1], "BYTES");
+	}
+    CSLDestroy( papszTokens );
+    return n;
+}
+
+GDALDataset *ISIS2Dataset::OpenQUB(const char *pszObjectName, GDALOpenInfo *poOpenInfo, ISIS2Dataset *poDS){
+	CPLDebug("ISIS2", "*** OpenQUB");
 /* -------------------------------------------------------------------- */
-/*	We assume the user is pointing to the label (ie. .lab) file.  	*/
+	/*	We assume the user is pointing to the label (ie. .lab, .lbl) file.  */
 /* -------------------------------------------------------------------- */
     // QUBE can be inline or detached and point to an image name
-    // ^QUBE = 76
-    // ^QUBE = ("ui31s015.img",6441<BYTES>) - has another label on the image
-    // ^QUBE = "ui31s015.img" - which implies no label or skip value
+    // ^QUBE = nnn
+	// ^QUBE = nnn <BYTES>
+    // ^QUBE = ("filename", nnn)
+    // ^QUBE = ("filename", nnn <BYTES>) - has another label on the image
+    // ^QUBE = "filename" - which implies no label or skip value
 
-    const char *pszQube = poDS->GetKeyword( "^QUBE" );
-    int nQube = atoi(pszQube);
+    GUIntBig nQube(0);
+    bool bByteLocation = false;
+    CPLString osTargetFile = poOpenInfo->pszFilename; // default target file is current file
 
-    if( pszQube[0] == '"' || pszQube[0] == '(' )
+    if( pszObjectName[0] == '"' )
     {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "ISIS2 driver does not support detached images." );
-        return NULL;
+    	CPLString osTPath = CPLGetPath(poOpenInfo->pszFilename);
+    	CPLString osFilename = pszObjectName;
+    	poDS->CleanString( osFilename );
+    	osTargetFile = CPLFormCIFilename( osTPath, osFilename, NULL );
     }
+    else if( pszObjectName[0] == '(' )
+    {
+        CPLString osTPath = CPLGetPath(poOpenInfo->pszFilename);
+        CPLString osFilename = poDS->GetKeywordSub("^QUBE",1,"");
+        poDS->CleanString( osFilename );
+        osTargetFile = CPLFormCIFilename( osTPath, osFilename, NULL );
+    	CPLString sNnn = poDS->GetKeywordSub("^QUBE",2,"1");
+    	nQube = ISIS2Dataset::GrabByteFlag(sNnn, bByteLocation);
+    }
+    else {
+    	nQube = ISIS2Dataset::GrabByteFlag(pszObjectName, bByteLocation);
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Check if file an ISIS2 header file?  Read a few lines of text   */
@@ -216,12 +584,11 @@
     OGRSpatialReference oSRS;
 
     //image parameters
-    int	nRows, nCols, nBands = 1;
     int nSkipBytes = 0;
     int itype;
-    int  s_ix, s_iy, s_iz; // check SUFFIX_ITEMS params.
+    unsigned int  s_ix, s_iy, s_iz; // check SUFFIX_ITEMS params.
     int record_bytes;
-    int	bNoDataSet = FALSE;
+    bool bNoDataSet = false;
     char chByteOrder = 'M';  //default to MSB
  
     //Georef parameters
@@ -246,92 +613,109 @@
 
     /* -------------------------------------------------------------------- */
     /*      Checks to see if this is valid ISIS2 cube                       */
-    /*      SUFFIX_ITEM tag in .cub file should be (0,0,0); no side-planes  */
+    /*      SUFFIX_ITEM tag in .cub file should be (X,Y,Z);                 */
     /* -------------------------------------------------------------------- */
-    s_ix = atoi(poDS->GetKeywordSub( "QUBE.SUFFIX_ITEMS", 1 ));
-    s_iy = atoi(poDS->GetKeywordSub( "QUBE.SUFFIX_ITEMS", 2 ));
-    s_iz = atoi(poDS->GetKeywordSub( "QUBE.SUFFIX_ITEMS", 3 ));
+    s_ix = strtoul(poDS->GetKeywordSub( "QUBE.SUFFIX_ITEMS", 1 ), NULL, 0);
+    s_iy = strtoul(poDS->GetKeywordSub( "QUBE.SUFFIX_ITEMS", 2 ), NULL, 0);
+    s_iz = strtoul(poDS->GetKeywordSub( "QUBE.SUFFIX_ITEMS", 3 ), NULL, 0);
      
-    if( s_ix != 0 || s_iy != 0 || s_iz != 0 ) 
-    {
-        CPLError( CE_Failure, CPLE_OpenFailed, 
-                  "*** ISIS 2 cube file has invalid SUFFIX_ITEMS parameters:\n"
-                  "*** gdal isis2 driver requires (0, 0, 0), thus no sideplanes or backplanes\n"
-                  "found: (%i, %i, %i)\n\n", s_ix, s_iy, s_iz );
-        return NULL;
-    } 
-
-    /**************** end SUFFIX_ITEM check ***********************/
+    unsigned int nDefaultSuffixSize  = strtoul(poDS->GetKeyword( "QUBE.SUFFIX_BYTES"), NULL, 0);
+    SuffixSize suffixSize;
     
-    
-    /***********   Grab layout type (BSQ, BIP, BIL) ************/
-    //  AXIS_NAME = (SAMPLE,LINE,BAND)
-    /***********************************************************/
-    const char *value;
+    /***********   Grab layout type (BSQ, BIP, BIL) and grab sample, line, band  ********/
+    /*  AXIS_NAME = (SAMPLE, LINE, BAND) - Band Sequential (BSQ)                        */
+    /*              (SAMPLE, BAND, LINE) - Band Interleaved by Line (BIL)               */
+    /*              (BAND, SAMPLE, LINE) - Band Interleaved by Pixel (BIP)              */
+    /************************************************************************************/
 
-    char szLayout[10] = "BSQ"; //default to band seq.
-    value = poDS->GetKeyword( "QUBE.AXIS_NAME", "" );
-    if (EQUAL(value,"(SAMPLE,LINE,BAND)") )
-        strcpy(szLayout,"BSQ");
-    else if (EQUAL(value,"(BAND,LINE,SAMPLE)") )
-        strcpy(szLayout,"BIP");
-    else if (EQUAL(value,"(SAMPLE,BAND,LINE)") || EQUAL(value,"") )
-        strcpy(szLayout,"BSQ");
+    DataSize dataSize;
+    CPLString sLayout("BSQ"); //default to band seq.
+    CPLString sValue = poDS->GetKeyword( "QUBE.AXIS_NAME", "(SAMPLE,LINE,BAND)" );
+
+    if (EQUAL(sValue,"(SAMPLE,LINE,BAND)") || EQUAL(sValue, "")){
+        sLayout = "BSQ";
+        dataSize.nSample = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS",1));
+        dataSize.nLine = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS",2));
+        dataSize.nBand = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS",3));
+        suffixSize.nX = poDS->GetSuffixSize("SAMPLE", s_ix, nDefaultSuffixSize);
+        suffixSize.nY = poDS->GetSuffixSize("LINE", s_iy, nDefaultSuffixSize);
+        suffixSize.nZ = poDS->GetSuffixSize("BAND", s_iz, nDefaultSuffixSize);
+    } 
+    else if (EQUAL(sValue,"(SAMPLE,BAND,LINE)") ){
+        sLayout = "BIL";
+        dataSize.nSample = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS",1));
+        dataSize.nBand = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS",2));
+        dataSize.nLine = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS",3));
+        suffixSize.nX = poDS->GetSuffixSize("SAMPLE", s_ix, nDefaultSuffixSize);
+        suffixSize.nY = poDS->GetSuffixSize("BAND", s_iy, nDefaultSuffixSize);
+        suffixSize.nZ = poDS->GetSuffixSize("LINE", s_iz, nDefaultSuffixSize);
+    }
+    else if (EQUAL(sValue,"(BAND,SAMPLE,LINE)") ){
+        sLayout = "BIP";
+        dataSize.nBand = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS",1));
+        dataSize.nSample = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS",2));
+        dataSize.nLine = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS",3));
+        suffixSize.nX = poDS->GetSuffixSize("BAND", s_ix, nDefaultSuffixSize);
+        suffixSize.nY = poDS->GetSuffixSize("SAMPLE", s_iy, nDefaultSuffixSize);
+        suffixSize.nZ = poDS->GetSuffixSize("LINE", s_iz, nDefaultSuffixSize);
+    }
     else {
         CPLError( CE_Failure, CPLE_OpenFailed, 
-                  "%s layout not supported. Abort\n\n", value);
+                  "%s layout not supported. Abort\n\n", sValue.c_str());
         return NULL;
     }
-
-    /***********   Grab samples lines band ************/
-    nCols = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS",1));
-    nRows = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS",2));
-    nBands = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS",3));
     
     /***********   Grab Qube record bytes  **********/
     record_bytes = atoi(poDS->GetKeyword("RECORD_BYTES"));
 
+    if (bByteLocation)
+    		record_bytes = 1;
     if (nQube > 0)
         nSkipBytes = (nQube - 1) * record_bytes;     
     else
         nSkipBytes = 0;     
      
-    /********   Grab format type - isis2 only supports 8,16,32 *******/
+    /********   Grab format type - isis2 only supports 8,16,32,64 bits *******/
+
+    CPLString sCoreType = poDS->GetKeyword( "QUBE.CORE_ITEM_TYPE" );
+    poDS->CleanString(sCoreType);
+    CPLString sDataDescription = ISIS2Dataset::GetSampleType(sCoreType);
+
     itype = atoi(poDS->GetKeyword("QUBE.CORE_ITEM_BYTES",""));
-    switch(itype) {
-      case 1 :
-        eDataType = GDT_Byte;
-        dfNoData = NULL1;
-        bNoDataSet = TRUE;
-        break;
-      case 2 :
-        eDataType = GDT_Int16;
-        dfNoData = NULL2;
-        bNoDataSet = TRUE;
-        break;
-      case 4 :
-        eDataType = GDT_Float32;
-        dfNoData = NULL3;
-        bNoDataSet = TRUE;
-        break;
-      default :
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Itype of %d is not supported in ISIS 2.",
-                  itype); 
-        delete poDS;
-        return NULL;
+    ISIS2Dataset::GetSampleFormat(itype, sDataDescription, eDataType, dfNoData, bNoDataSet, true);
+
+    /***********   Grab NULL value ********************/
+    /* load null value dynamically and convert it to a real */
+    CPLString sCoreNull = poDS->GetKeyword("QUBE.CORE_NULL","");
+    if(sCoreNull != ""){
+    	try{
+    		int nx = sCoreNull.find('#');
+    		if(nx != -1){
+    			CPLString sBase = sCoreNull.substr(0,nx);
+    			if(EQUAL(sBase, "16")){
+    				// we have an hex string
+    				CPLString sValue = sCoreNull.substr(nx+1,sCoreNull.length()-nx-2);
+    				unsigned long l = strtoul(CPLString().Printf("0x%s", sValue.c_str()), NULL, 0);
+    				dfNoData = *reinterpret_cast<float const*>(&l);
+    				CPLDebug("ISIS2", CPLString().Printf("NoData value is %f", dfNoData));
+    				bNoDataSet = TRUE;
+    			}else{
+    				CPLDebug("ISIS2", CPLString().Printf("Failed to read CORE_NULL value; This base is not supported : %s", sBase.c_str()));
+    			}
+    		}else{
+    			// try to read a standard value
+    			dfNoData = strtod(sCoreNull, NULL);
+    		}
+    	}catch(...){
+    		throw ISIS2DatasetError(CPLString().Printf("Failed to read CORE_NULL value : %s", sCoreNull.c_str()));
+    	}
     }
 
-    /***********   Grab samples lines band ************/
-    value = poDS->GetKeyword( "QUBE.CORE_ITEM_TYPE" );
-    if( (EQUAL(value,"PC_INTEGER")) || 
-        (EQUAL(value,"PC_UNSIGNED_INTEGER")) || 
-        (EQUAL(value,"PC_REAL")) ) {
-        chByteOrder = 'I';
-    }
+    /***********   Grab word order ************/
+    chByteOrder = ISIS2Dataset::GetWordOrder(sCoreType);
     
     /***********   Grab Cellsize ************/
-    value = poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.MAP_SCALE");
+    CPLString value = poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.MAP_SCALE");
     if (strlen(value) > 0 ) {
         dfXDim = (float) atof(value) * 1000.0; /* convert from km to m */
         dfYDim = (float) atof(value) * 1000.0 * -1;
@@ -354,8 +738,7 @@
     }
      
     /***********  Grab TARGET_NAME  ************/
-    /**** This is the planets name i.e. MARS ***/
-    CPLString target_name = poDS->GetKeyword("QUBE.TARGET_NAME");
+    CPLString target_name = poDS->GetKeyword("TARGET_NAME");
      
     /***********   Grab MAP_PROJECTION_TYPE ************/
     CPLString map_proj_name = 
@@ -517,11 +900,14 @@
 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
     
 /* -------------------------------------------------------------------- */
+/*     Is the CUB detached - if so, reset name to binary file?          */
+/* -------------------------------------------------------------------- */
+/* -------------------------------------------------------------------- */
 /*      Did we get the required keywords?  If not we return with        */
 /*      this never having been considered to be a match. This isn't     */
 /*      an error!                                                       */
 /* -------------------------------------------------------------------- */
-    if( nRows < 1 || nCols < 1 || nBands < 1 )
+    if( dataSize.nLine < 1 || dataSize.nSample < 1 || dataSize.nBand < 1 )
     {
         return NULL;
     }
@@ -529,60 +915,39 @@
 /* -------------------------------------------------------------------- */
 /*      Capture some information from the file that is of interest.     */
 /* -------------------------------------------------------------------- */
-    poDS->nRasterXSize = nCols;
-    poDS->nRasterYSize = nRows;
+    poDS->nRasterXSize = dataSize.nSample;
+    poDS->nRasterYSize = dataSize.nLine;
 
 /* -------------------------------------------------------------------- */
 /*      Open target binary file.                                        */
 /* -------------------------------------------------------------------- */
-    
+    CPLDebug("ISIS2", "osTargetFile=%s\n", osTargetFile.c_str());
     if( poOpenInfo->eAccess == GA_ReadOnly )
-        poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
+        poDS->fpImage = VSIFOpenL( osTargetFile, "rb" );
     else
-        poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
+        poDS->fpImage = VSIFOpenL( osTargetFile, "r+b" );
 
     if( poDS->fpImage == NULL )
     {
         CPLError( CE_Failure, CPLE_OpenFailed, 
                   "Failed to open %s with write permission.\n%s", 
-                  poOpenInfo->pszFilename, VSIStrerror( errno ) );
+                  osTargetFile.c_str(),
+                  VSIStrerror( errno ) );
         delete poDS;
         return NULL;
     }
 
     poDS->eAccess = poOpenInfo->eAccess;
-
-/* -------------------------------------------------------------------- */
-/*      Compute the line offset.                                        */
-/* -------------------------------------------------------------------- */
-    int     nItemSize = GDALGetDataTypeSize(eDataType)/8;
     int		nLineOffset, nPixelOffset, nBandOffset;
     
-    if( EQUAL(szLayout,"BIP") )
-    {
-        nPixelOffset = nItemSize * nBands;
-        nLineOffset = nPixelOffset * nCols;
-        nBandOffset = nItemSize;
-    }
-    else if( EQUAL(szLayout,"BSQ") )
-    {
-        nPixelOffset = nItemSize;
-        nLineOffset = nPixelOffset * nCols;
-        nBandOffset = nLineOffset * nRows;
-    }
-    else /* assume BIL */
-    {
-        nPixelOffset = nItemSize;
-        nLineOffset = nItemSize * nBands * nCols;
-        nBandOffset = nItemSize * nCols;
-    }
+    ComputeOffset(sLayout, dataSize, suffixSize, eDataType, nPixelOffset, nLineOffset, nBandOffset);
     
 /* -------------------------------------------------------------------- */
 /*      Create band information objects.                                */
 /* -------------------------------------------------------------------- */
     int i;
 
-    poDS->nBands = nBands;;
+    poDS->nBands = dataSize.nBand;;
     for( i = 0; i < poDS->nBands; i++ )
     {
         RawRasterBand	*poBand;
@@ -592,8 +957,10 @@
                                nSkipBytes + nBandOffset * i, 
                                nPixelOffset, nLineOffset, eDataType,
 #ifdef CPL_LSB                               
+                               /* IBM architecture or least significant byte first */
                                chByteOrder == 'I' || chByteOrder == 'L',
 #else
+                               /* Most significant byte first */
                                chByteOrder == 'M',
 #endif        
                                TRUE );
@@ -662,6 +1029,13 @@
             GDALReadWorldFile( poOpenInfo->pszFilename, "wld", 
                                poDS->adfGeoTransform );
 
+    poDS->SetKeywords();
+
+/* -------------------------------------------------------------------- */
+/*      Check for overviews.                                            */
+/* -------------------------------------------------------------------- */
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
+
 /* -------------------------------------------------------------------- */ 
 /*      Initialize any PAM information.                                 */ 
 /* -------------------------------------------------------------------- */ 
@@ -677,6 +1051,24 @@
 }
 
 /************************************************************************/
+/*                             SetAllKeywords()                         */
+/************************************************************************/
+void ISIS2Dataset::SetKeywords()
+{
+    char **papszKeywordList = oKeywords.GetKeywordList();
+    for(int i=0; papszKeywordList[i] != NULL; i++){
+      const char *pszKeyWordEntry = papszKeywordList[i];
+
+      char **papszTokens = CSLTokenizeString2( pszKeyWordEntry, "=",
+                                                     CSLT_HONOURSTRINGS );
+
+      //CPLDebug("ISIS2","keyword = %s", papszTokens[0]);
+      const char *pszKeywordValue = this->GetKeyword(papszTokens[0], "");
+      this->SetMetadataItem( papszTokens[0], pszKeywordValue);
+    }
+}
+
+/************************************************************************/
 /*                             GetKeyword()                             */
 /************************************************************************/
 
@@ -751,6 +1143,281 @@
 }
 
 /************************************************************************/
+/*                           Create()                                   */
+/************************************************************************/
+/**
+ * Creation Options:
+ * INTERLEAVE=BSQ/BIP/BIL: Force the generation specified type of interleaving.
+ *  BSQ --- band sequental (default),
+ *  BIP --- band interleaved by pixel,
+ *  BIL --- band interleaved by line.
+ * LABELING_METHOD=attached/detached
+ * LABEL_EXTENSION=???, if null default is "pds"
+ * OBJECT=QUBE/IMAGE/SPECTRAL_QUBE, if null default is QUBE
+ */
+
+GDALDataset *ISIS2Dataset::Create(const char* pszFilename,
+    int nXSize, int nYSize, int nBands,
+    GDALDataType eType, char** papszParmList) {
+
+  /* Verify settings. In Isis 2 core pixel values can be represented in
+   * three different ways : 1, 2 or 4 Bytes */
+  if( eType != GDT_Byte && eType != GDT_Int16 && eType != GDT_Float32){
+    CPLError(CE_Failure, CPLE_AppDefined,
+             "The ISIS2 driver does not supporting creating files of types %s.",
+             GDALGetDataTypeName( eType ) );
+    return NULL;
+  }
+
+  /*  (SAMPLE, LINE, BAND) - Band Sequential (BSQ) - default choice
+      (SAMPLE, BAND, LINE) - Band Interleaved by Line (BIL)
+      (BAND, SAMPLE, LINE) - Band Interleaved by Pixel (BIP) */
+  const char *pszInterleaving = "(SAMPLE,LINE,BAND)";
+  const char *pszInterleavingParam = CSLFetchNameValue( papszParmList, "INTERLEAVE" );
+  if ( pszInterleavingParam ) {
+    if ( EQUALN( pszInterleavingParam, "bip", 3 ) )
+      pszInterleaving = "(BAND, SAMPLE, LINE)";
+    else if ( EQUALN( pszInterleavingParam, "bil", 3 ) )
+      pszInterleaving = "(SAMPLE, BAND, LINE)";
+    else
+      pszInterleaving = "(SAMPLE,LINE,BAND)";
+  }
+
+  /* default labeling method is attached */
+  bool bAttachedLabelingMethod = true;
+  /* check if labeling method is set : check the all three first chars */
+  const char *pszLabelingMethod = CSLFetchNameValue( papszParmList, "LABELING_METHOD" );
+  if ( pszLabelingMethod ){
+	  if ( EQUALN( pszLabelingMethod, "detached", 3 ) ){
+		  bAttachedLabelingMethod = false;
+	  }
+	  if ( EQUALN( pszLabelingMethod, "attached", 3 ) ){
+		  bAttachedLabelingMethod = true;
+	  }
+  }
+
+  /*  set the label and data files */
+  CPLString osLabelFile, osRasterFile, osOutFile;
+  if( bAttachedLabelingMethod ) {
+	  osLabelFile = "";
+	  osRasterFile = pszFilename;
+	  osOutFile = osRasterFile;
+  }
+  else
+  {
+	  /* default extension is pds */
+	  CPLString sExtension = "pds";
+	  const char* pszExtension = CSLFetchNameValue( papszParmList, "LABEL_EXTENSION" );
+	  if( pszExtension ){
+		  sExtension = pszExtension;
+	  }
+
+	  if( EQUAL(CPLGetExtension( pszFilename ), sExtension) )
+	  {
+		  osLabelFile = pszFilename;
+		  osRasterFile = osLabelFile.substr(0,osLabelFile.length()-4);
+	  }else{
+		  osRasterFile = pszFilename;
+		  osLabelFile = osRasterFile + "." + sExtension;
+	  }
+	  osOutFile = osLabelFile;
+  }
+
+  CPLDebug("ISIS2", "outfile = %s, labelfile = %s, rasterfile = %s", osOutFile.c_str(), osLabelFile.c_str(), osRasterFile.c_str());
+  const char *pszObject = CSLFetchNameValue( papszParmList, "OBJECT" );
+  CPLString sObject = "QUBE"; // default choice
+  if (pszObject) {
+	  if ( EQUAL( pszObject, "IMAGE") ){
+		  sObject = "IMAGE";
+	  }
+	  if ( EQUAL( pszObject, "SPECTRAL_QUBE")){
+		  sObject = "SPECTRAL_QUBE";
+	  }
+  }
+
+  try{
+    GUIntBig iRecords = ISIS2Dataset::RecordSizeCalculation(nXSize, nYSize, nBands, eType);
+	CPLDebug("ISIS2","irecord = %i",static_cast<int>(iRecords));
+    GUIntBig iLabelRecords(2);
+    if( bAttachedLabelingMethod ) {
+    	ISIS2Dataset::WriteLabel(osRasterFile, "", sObject, nXSize, nYSize, nBands, eType, iRecords, pszInterleaving, iLabelRecords, true);
+    }else{
+    	ISIS2Dataset::WriteLabel(osLabelFile, osRasterFile, sObject, nXSize, nYSize, nBands, eType, iRecords, pszInterleaving, iLabelRecords);
+    }
+    ISIS2Dataset::WriteRaster(osRasterFile, bAttachedLabelingMethod, iRecords, iLabelRecords, eType, pszInterleaving);
+  }catch (ISIS2DatasetError){
+    CPLError(CE_Failure, CPLE_AppDefined, "Error on WriteRaster or Label");
+    return NULL;
+  }
+
+  return (GDALDataset *) GDALOpen( osOutFile, GA_Update );
+}
+
+
+/************************************************************************/
+/*                         Writing methods WriteRaster                  */
+/************************************************************************/
+
+void ISIS2Dataset::WriteRaster(CPLString osFilename, bool includeLabel, GUIntBig iRecords, GUIntBig iLabelRecords, GDALDataType eType, const char * pszInterleaving) {
+  GUIntBig nSize;
+  GByte byZero(0);
+  CPLString pszAccess("wb");
+  if(includeLabel)
+	  pszAccess = "ab";
+
+  FILE *fpBin = VSIFOpenL( osFilename, pszAccess.c_str() );
+  if( fpBin == NULL ) {
+    CPLError( CE_Failure, CPLE_FileIO,
+        "Failed to create %s:\n%s",
+        osFilename.c_str(), VSIStrerror( errno ) );
+    throw ISIS2DatasetError();
+  }
+
+  nSize = iRecords * RECORD_SIZE;
+  CPLDebug("ISIS2","nSize = %i", static_cast<int>(nSize));
+
+  if(includeLabel)
+	 nSize = iLabelRecords * RECORD_SIZE + nSize;
+
+  // write last byte
+  if(VSIFSeekL( fpBin, nSize-1, SEEK_SET ) != 0 ||
+		  VSIFWriteL( &byZero, 1, 1, fpBin ) != 1){
+	  CPLError( CE_Failure, CPLE_FileIO,
+			  "Failed to write %s:\n%s",
+			  osFilename.c_str(), VSIStrerror( errno ) );
+	  throw ISIS2DatasetError();
+  }
+  VSIFCloseL( fpBin );
+}
+
+GUIntBig ISIS2Dataset::RecordSizeCalculation(unsigned int nXSize, unsigned int nYSize, unsigned int nBands, GDALDataType eType ){
+	GUIntBig n = nXSize * nYSize * nBands * (  GDALGetDataTypeSize(eType) / 8);
+	// size of pds file is a multiple of RECORD_SIZE Bytes.
+	CPLDebug("ISIS2","n = %i", static_cast<int>(n));
+	CPLDebug("ISIS2","RECORD SIZE = %i", RECORD_SIZE);
+	CPLDebug("ISIS2","nXSize = %i", nXSize);
+	CPLDebug("ISIS2","nYSize = %i", nYSize);
+	CPLDebug("ISIS2","nBands = %i", nBands);
+	CPLDebug("ISIS2","DataTypeSize = %i", GDALGetDataTypeSize(eType));
+	return (GUIntBig) ceil(static_cast<float>(n)/RECORD_SIZE);
+}
+
+void ISIS2Dataset::WriteQUBE_Information(FILE *fpLabel, unsigned int iLevel, unsigned int & nWritingBytes,
+			unsigned int nXSize, unsigned int nYSize, unsigned int nBands, const char * pszInterleaving){
+
+	  nWritingBytes += ISIS2Dataset::WriteFormatting( fpLabel, "");
+	  nWritingBytes += ISIS2Dataset::WriteFormatting( fpLabel, "/* Qube structure */");
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "OBJECT", "QUBE");
+	  iLevel++;
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "AXES", "3");
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "AXIS_NAME", pszInterleaving);
+	  nWritingBytes += ISIS2Dataset::WriteFormatting( fpLabel, "/* Core description */");
+
+	  CPLDebug("ISIS2","%d,%d,%d",nXSize,nYSize,nBands);
+
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "CORE_ITEMS",CPLString().Printf("(%d,%d,%d)",nXSize,nYSize,nBands));
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "CORE_NAME", "\"RAW DATA NUMBER\"");
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "CORE_UNIT", "\"N/A\"");
+	  // TODO change for eType
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "CORE_ITEM_TYPE", "PC_REAL");
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "CORE_ITEM_BYTES", "4");
+	  // TODO add core null value
+
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "CORE_BASE", "0.0");
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "CORE_MULTIPLIER", "1.0");
+	  nWritingBytes += ISIS2Dataset::WriteFormatting( fpLabel, "/* Suffix description */");
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "SUFFIX_BYTES", "4");
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "SUFFIX_ITEMS", "( 0, 0, 0)");
+	  iLevel--;
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "END_OBJECT", "QUBE");
+}
+
+/******************************************************************************************************/
+/*                      WriteLabel                                                                    */
+/* osRasterFile : name of raster file but if it is empty we have only one file with an attached label */
+/* sObjectTag : QUBE, IMAGE or SPECTRAL_QUBE                                                          */
+/* bRelaunch : flag to allow recursiv call                                                            */
+/******************************************************************************************************/
+void ISIS2Dataset::WriteLabel(CPLString osFilename, CPLString osRasterFile,
+		CPLString sObjectTag,
+		unsigned int nXSize, unsigned int nYSize, unsigned int nBands, GDALDataType eType,
+		GUIntBig iRecords, const char * pszInterleaving, GUIntBig & iLabelRecords, bool bRelaunch) {
+  CPLDebug("ISIS2", "Write Label filename = %s, rasterfile = %s",osFilename.c_str(),osRasterFile.c_str());
+  bool bAttachedLabel = EQUAL(osRasterFile, "");
+
+  FILE *fpLabel = VSIFOpenL( osFilename, "w" );
+
+  if( fpLabel == NULL ){
+    CPLError( CE_Failure, CPLE_FileIO,
+              "Failed to create %s:\n%s",
+              osFilename.c_str(), VSIStrerror( errno ) );
+    throw ISIS2DatasetError();
+  }
+
+  unsigned int iLevel(0);
+  unsigned int nWritingBytes(0);
+
+  /* write common header */
+  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "PDS_VERSION_ID", "PDS3" );
+  nWritingBytes += ISIS2Dataset::WriteFormatting( fpLabel, "");
+  nWritingBytes += ISIS2Dataset::WriteFormatting( fpLabel, "/* File identification and structure */");
+  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "RECORD_TYPE", "FIXED_LENGTH" );
+  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "RECORD_BYTES", CPLString().Printf("%d",RECORD_SIZE));
+  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "FILE_RECORDS", CPLString().Printf("%lu",(long unsigned int)(iRecords)));
+  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "LABEL_RECORDS", CPLString().Printf("%llu", iLabelRecords));
+  if(!bAttachedLabel){
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, "FILE_NAME", CPLGetFilename(osRasterFile));
+  }
+  nWritingBytes += ISIS2Dataset::WriteFormatting( fpLabel, "");
+
+  nWritingBytes += ISIS2Dataset::WriteFormatting( fpLabel, "/* Pointers to Data Objects */");
+
+  if(bAttachedLabel){
+  	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, CPLString().Printf("^%s",sObjectTag.c_str()), CPLString().Printf("%llu",iLabelRecords+1));
+  }else{
+	  nWritingBytes += ISIS2Dataset::WriteKeyword( fpLabel, iLevel, CPLString().Printf("^%s",sObjectTag.c_str()), CPLString().Printf("(\"%s\",1)",CPLGetFilename(osRasterFile)));
+  }
+
+  if(EQUAL(sObjectTag, "QUBE")){
+	  ISIS2Dataset::WriteQUBE_Information(fpLabel, iLevel, nWritingBytes, nXSize, nYSize, nBands, pszInterleaving);
+  }
+
+  nWritingBytes += ISIS2Dataset::WriteFormatting( fpLabel, "END");
+
+  // check if file record is correct
+  unsigned int q = nWritingBytes/RECORD_SIZE;
+  if( q <= iLabelRecords){
+	  // correct we add space after the label end for complete from iLabelRecords
+	  unsigned int nSpaceBytesToWrite = iLabelRecords * RECORD_SIZE - nWritingBytes;
+	  VSIFPrintfL(fpLabel,"%*c", nSpaceBytesToWrite, ' ');
+  }else{
+	  iLabelRecords = q+1;
+	  ISIS2Dataset::WriteLabel(osFilename, osRasterFile, sObjectTag, nXSize, nYSize, nBands, eType, iRecords, pszInterleaving, iLabelRecords);
+  }
+  VSIFCloseL( fpLabel );
+}
+
+unsigned int ISIS2Dataset::WriteKeyword(FILE *fpLabel, unsigned int iLevel, CPLString key, CPLString value){
+	CPLString tab = "";
+	iLevel *= 4; // each struct is idented by 4 spaces
+	int ret = VSIFPrintfL(fpLabel,"%*s%s=%s\n", iLevel, tab.c_str(), key.c_str(), value.c_str());
+	if(ret == -1){
+		CPLError( CE_Failure, CPLE_FileIO, "Failed to write key %s\n", key.c_str());
+		throw ISIS2DatasetError();
+	}
+	return ret;
+}
+
+unsigned int ISIS2Dataset::WriteFormatting(FILE *fpLabel, CPLString data){
+	int ret = VSIFPrintfL(fpLabel,"%s\n", data.c_str());
+	if(ret == -1){
+		CPLError( CE_Failure, CPLE_FileIO, "Failed to write %s\n", data.c_str());
+		throw ISIS2DatasetError();
+	}
+	return ret;
+}
+
+/************************************************************************/
 /*                         GDALRegister_ISIS2()                         */
 /************************************************************************/
 
@@ -768,8 +1435,11 @@
                                    "USGS Astrogeology ISIS cube (Version 2)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
                                    "frmt_various.html#ISIS2" );
+		poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte Int16 Int32 Float32 Float64");
 
         poDriver->pfnOpen = ISIS2Dataset::Open;
+ 		poDriver->pfnCreate = ISIS2Dataset::Create;
+        poDriver->pfnCreateCopy = NULL;
 
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
Index: gdal-1.7.3/frmts/pds/nasakeywordhandler.cpp
===================================================================
--- gdal-1.7.3/frmts/pds/nasakeywordhandler.cpp	(révision 588)
+++ gdal-1.7.3/frmts/pds/nasakeywordhandler.cpp	(révision 613)
@@ -369,6 +369,15 @@
             }
 
             pszHeaderNext += 2;
+
+            // consume till end of line.
+            // reduce sensibility to a label error
+            while( *pszHeaderNext != '\0'
+            		&& *pszHeaderNext != 10
+            		&& *pszHeaderNext != 13 )
+            {
+            	pszHeaderNext++;
+            }
             continue;
         }
 
@@ -418,3 +427,12 @@
         return pszResult;
 }
 
+/************************************************************************/
+/*                             GetKeywordList()                         */
+/************************************************************************/
+ 
+char **NASAKeywordHandler::GetKeywordList()
+{
+    return papszKeywordList;
+}
+
Index: gdal-1.7.3/frmts/pds/nasakeywordhandler.h
===================================================================
--- gdal-1.7.3/frmts/pds/nasakeywordhandler.h	(révision 588)
+++ gdal-1.7.3/frmts/pds/nasakeywordhandler.h	(révision 613)
@@ -23,4 +23,5 @@
     int     Ingest( FILE *fp, int nOffset );
 
     const char *GetKeyword( const char *pszPath, const char *pszDefault );
+    char **GetKeywordList();
 };
_______________________________________________
gdal-dev mailing list
gdal-dev@lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/gdal-dev

Reply via email to