Handle<Value> DatasetBands::create(const Arguments& args) { HandleScope scope; Handle<Object> parent = args.This()->GetHiddenValue(String::NewSymbol("parent_"))->ToObject(); Dataset *ds = ObjectWrap::Unwrap<Dataset>(parent); if (ds->uses_ogr){ return NODE_THROW("Dataset does not support getting creating bands"); } GDALDataset* raw = ds->getDataset(); if (!raw) { return NODE_THROW("Dataset object has already been destroyed"); } GDALDataType type; Handle<Array> band_options = Array::New(0); char **options = NULL; std::string *options_str = NULL; //NODE_ARG_ENUM(0, "data type", GDALDataType, type); if(args.Length() < 1) { return NODE_THROW("data type argument needed"); } if(args[0]->IsString()){ std::string type_name = TOSTR(args[0]); type = GDALGetDataTypeByName(type_name.c_str()); } else if (args[0]->IsNull() || args[0]->IsUndefined()) { type = GDT_Unknown; } else { return NODE_THROW("data type must be string or undefined"); } NODE_ARG_ARRAY_OPT(1, "band creation options", band_options); if (band_options->Length() > 0) { options = new char* [band_options->Length()]; options_str = new std::string [band_options->Length()]; for (unsigned int i = 0; i < band_options->Length(); ++i) { options_str[i] = TOSTR(band_options->Get(i)); options[i] = (char*) options_str[i].c_str(); } } CPLErr err = raw->AddBand(type, options); if(options) delete [] options; if(options_str) delete [] options_str; if (err) { return NODE_THROW_CPLERR(err); } return scope.Close(RasterBand::New(raw->GetRasterBand(raw->GetRasterCount()), raw)); }
GDALDataset * RasterCreate( const char * pszFormat, const char * pszFilename, char ** papszOptions /*=NULL*/ ) { int nXSize = atoi(CSLFetchNameValue(papszOptions, "XSize")); int nYSize = atoi(CSLFetchNameValue(papszOptions, "YSize")); int nBands = atoi(CSLFetchNameValue(papszOptions, "Bands")); GDALDataType eBandType = GDALGetDataTypeByName(CSLFetchNameValue(papszOptions, "DataType")); char ** papszCreate = NULL; papszCreate = CSLSetNameValue(papszCreate, "BLOCKXSIZE", "256"); papszCreate = CSLSetNameValue( papszCreate, "BLOCKYSIZE", "1" ); GDALDriver * poDriver = GetRasterDriver(pszFormat); GDALDataset * poDS = poDriver->Create( pszFilename, nXSize, nYSize, nBands, eBandType, papszCreate) ; CSLDestroy(papszCreate); return poDS; }
CPLErr VRTDerivedRasterBand::XMLInit(CPLXMLNode *psTree, const char *pszVRTPath) { CPLErr eErr; const char *pszTypeName; eErr = VRTSourcedRasterBand::XMLInit( psTree, pszVRTPath ); if( eErr != CE_None ) return eErr; /* ---- Read derived pixel function type ---- */ this->SetPixelFunctionName (CPLGetXMLValue(psTree, "PixelFunctionType", NULL)); /* ---- Read optional source transfer data type ---- */ pszTypeName = CPLGetXMLValue(psTree, "SourceTransferType", NULL); if (pszTypeName != NULL) { this->eSourceTransferType = GDALGetDataTypeByName(pszTypeName); } return CE_None; }
GDALDataset *AAIGDataset::CommonOpen( GDALOpenInfo *poOpenInfo, GridFormat eFormat ) { if( poOpenInfo->fpL == nullptr ) return nullptr; // Create a corresponding GDALDataset. AAIGDataset *poDS = nullptr; if (eFormat == FORMAT_AAIG) poDS = new AAIGDataset(); else poDS = new GRASSASCIIDataset(); const char *pszDataTypeOption = eFormat == FORMAT_AAIG ? "AAIGRID_DATATYPE" : "GRASSASCIIGRID_DATATYPE"; const char *pszDataType = CPLGetConfigOption(pszDataTypeOption, nullptr); if( pszDataType == nullptr ) pszDataType = CSLFetchNameValue(poOpenInfo->papszOpenOptions, "DATATYPE"); if (pszDataType != nullptr) { poDS->eDataType = GDALGetDataTypeByName(pszDataType); if (!(poDS->eDataType == GDT_Int32 || poDS->eDataType == GDT_Float32 || poDS->eDataType == GDT_Float64)) { CPLError(CE_Warning, CPLE_NotSupported, "Unsupported value for %s : %s", pszDataTypeOption, pszDataType); poDS->eDataType = GDT_Int32; pszDataType = nullptr; } } // Parse the header. if (!poDS->ParseHeader((const char *)poOpenInfo->pabyHeader, pszDataType)) { delete poDS; return nullptr; } poDS->fp = poOpenInfo->fpL; poOpenInfo->fpL = nullptr; // Find the start of real data. int nStartOfData = 0; for( int i = 2; true; i++ ) { if( poOpenInfo->pabyHeader[i] == '\0' ) { CPLError(CE_Failure, CPLE_AppDefined, "Couldn't find data values in ASCII Grid file."); delete poDS; return nullptr; } if( poOpenInfo->pabyHeader[i - 1] == '\n' || poOpenInfo->pabyHeader[i - 2] == '\n' || poOpenInfo->pabyHeader[i - 1] == '\r' || poOpenInfo->pabyHeader[i - 2] == '\r' ) { if( !isalpha(poOpenInfo->pabyHeader[i]) && poOpenInfo->pabyHeader[i] != '\n' && poOpenInfo->pabyHeader[i] != '\r') { nStartOfData = i; // Beginning of real data found. break; } } } // Recognize the type of data. CPLAssert(nullptr != poDS->fp); if( pszDataType == nullptr && poDS->eDataType != GDT_Float32 && poDS->eDataType != GDT_Float64) { // Allocate 100K chunk + 1 extra byte for NULL character. constexpr size_t nChunkSize = 1024 * 100; GByte *pabyChunk = static_cast<GByte *>( VSI_CALLOC_VERBOSE(nChunkSize + 1, sizeof(GByte))); if (pabyChunk == nullptr) { delete poDS; return nullptr; } pabyChunk[nChunkSize] = '\0'; if( VSIFSeekL(poDS->fp, nStartOfData, SEEK_SET) < 0 ) { delete poDS; VSIFree(pabyChunk); return nullptr; } // Scan for dot in subsequent chunks of data. while( !VSIFEofL(poDS->fp) ) { CPL_IGNORE_RET_VAL(VSIFReadL(pabyChunk, nChunkSize, 1, poDS->fp)); for( int i = 0; i < static_cast<int>(nChunkSize); i++) { GByte ch = pabyChunk[i]; if (ch == '.' || ch == ',' || ch == 'e' || ch == 'E') { poDS->eDataType = GDT_Float32; break; } } } // Deallocate chunk. VSIFree(pabyChunk); } // Create band information objects. AAIGRasterBand *band = new AAIGRasterBand(poDS, nStartOfData); poDS->SetBand(1, band); if (band->panLineOffset == nullptr) { delete poDS; return nullptr; } // Try to read projection file. char *const pszDirname = CPLStrdup(CPLGetPath(poOpenInfo->pszFilename)); char *const pszBasename = CPLStrdup(CPLGetBasename(poOpenInfo->pszFilename)); poDS->osPrjFilename = CPLFormFilename(pszDirname, pszBasename, "prj"); int nRet = 0; { VSIStatBufL sStatBuf; nRet = VSIStatL(poDS->osPrjFilename, &sStatBuf); } if( nRet != 0 && VSIIsCaseSensitiveFS(poDS->osPrjFilename) ) { poDS->osPrjFilename = CPLFormFilename(pszDirname, pszBasename, "PRJ"); VSIStatBufL sStatBuf; nRet = VSIStatL(poDS->osPrjFilename, &sStatBuf); } if( nRet == 0 ) { poDS->papszPrj = CSLLoad(poDS->osPrjFilename); CPLDebug("AAIGrid", "Loaded SRS from %s", poDS->osPrjFilename.c_str()); OGRSpatialReference oSRS; if( oSRS.importFromESRI(poDS->papszPrj) == OGRERR_NONE ) { // If geographic values are in seconds, we must transform. // Is there a code for minutes too? if( oSRS.IsGeographic() && EQUAL(OSR_GDS(poDS->papszPrj, "Units", ""), "DS") ) { poDS->adfGeoTransform[0] /= 3600.0; poDS->adfGeoTransform[1] /= 3600.0; poDS->adfGeoTransform[2] /= 3600.0; poDS->adfGeoTransform[3] /= 3600.0; poDS->adfGeoTransform[4] /= 3600.0; poDS->adfGeoTransform[5] /= 3600.0; } CPLFree(poDS->pszProjection); oSRS.exportToWkt(&(poDS->pszProjection)); } } CPLFree(pszDirname); CPLFree(pszBasename); // Initialize any PAM information. poDS->SetDescription(poOpenInfo->pszFilename); poDS->TryLoadXML(); // Check for external overviews. poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles()); return poDS; }
CPLErr VRTDataset::AddBand( GDALDataType eType, char **papszOptions ) { int i; const char *pszSubClass = CSLFetchNameValue(papszOptions, "subclass"); bNeedsFlush = 1; /* ==================================================================== */ /* Handle a new raw band. */ /* ==================================================================== */ if( pszSubClass != NULL && EQUAL(pszSubClass,"VRTRawRasterBand") ) { int nWordDataSize = GDALGetDataTypeSize( eType ) / 8; vsi_l_offset nImageOffset = 0; int nPixelOffset = nWordDataSize; int nLineOffset = nWordDataSize * GetRasterXSize(); const char *pszFilename; const char *pszByteOrder = NULL; int bRelativeToVRT = FALSE; /* -------------------------------------------------------------------- */ /* Collect required information. */ /* -------------------------------------------------------------------- */ if( CSLFetchNameValue(papszOptions, "ImageOffset") != NULL ) nImageOffset = atoi(CSLFetchNameValue(papszOptions, "ImageOffset")); if( CSLFetchNameValue(papszOptions, "PixelOffset") != NULL ) nPixelOffset = atoi(CSLFetchNameValue(papszOptions,"PixelOffset")); if( CSLFetchNameValue(papszOptions, "LineOffset") != NULL ) nLineOffset = atoi(CSLFetchNameValue(papszOptions, "LineOffset")); if( CSLFetchNameValue(papszOptions, "ByteOrder") != NULL ) pszByteOrder = CSLFetchNameValue(papszOptions, "ByteOrder"); if( CSLFetchNameValue(papszOptions, "SourceFilename") != NULL ) pszFilename = CSLFetchNameValue(papszOptions, "SourceFilename"); else { CPLError( CE_Failure, CPLE_AppDefined, "AddBand() requires a SourceFilename option for VRTRawRasterBands." ); return CE_Failure; } bRelativeToVRT = CSLFetchBoolean( papszOptions, "RelativeToVRT", FALSE ); /* -------------------------------------------------------------------- */ /* Create and initialize the band. */ /* -------------------------------------------------------------------- */ CPLErr eErr; VRTRawRasterBand *poBand = new VRTRawRasterBand( this, GetRasterCount() + 1, eType ); eErr = poBand->SetRawLink( pszFilename, NULL, FALSE, nImageOffset, nPixelOffset, nLineOffset, pszByteOrder ); if( eErr != CE_None ) { delete poBand; return eErr; } SetBand( GetRasterCount() + 1, poBand ); return CE_None; } /* ==================================================================== */ /* Handle a new "sourced" band. */ /* ==================================================================== */ else { VRTSourcedRasterBand *poBand; /* ---- Check for our sourced band 'derived' subclass ---- */ if(pszSubClass != NULL && EQUAL(pszSubClass,"VRTDerivedRasterBand")) { /* We'll need a pointer to the subclass in case we need */ /* to set the new band's pixel function below. */ VRTDerivedRasterBand* poDerivedBand; poDerivedBand = new VRTDerivedRasterBand (this, GetRasterCount() + 1, eType, GetRasterXSize(), GetRasterYSize()); /* Set the pixel function options it provided. */ const char* pszFuncName = CSLFetchNameValue(papszOptions, "PixelFunctionType"); if (pszFuncName != NULL) poDerivedBand->SetPixelFunctionName(pszFuncName); const char* pszTransferTypeName = CSLFetchNameValue(papszOptions, "SourceTransferType"); if (pszTransferTypeName != NULL) { GDALDataType eTransferType = GDALGetDataTypeByName(pszTransferTypeName); if (eTransferType == GDT_Unknown) { CPLError( CE_Failure, CPLE_AppDefined, "invalid SourceTransferType: \"%s\".", pszTransferTypeName); delete poDerivedBand; return CE_Failure; } poDerivedBand->SetSourceTransferType(eTransferType); } /* We're done with the derived band specific stuff, so */ /* we can assigned the base class pointer now. */ poBand = poDerivedBand; } else { /* ---- Standard sourced band ---- */ poBand = new VRTSourcedRasterBand (this, GetRasterCount() + 1, eType, GetRasterXSize(), GetRasterYSize()); } SetBand( GetRasterCount() + 1, poBand ); for( i=0; papszOptions != NULL && papszOptions[i] != NULL; i++ ) { if( EQUALN(papszOptions[i],"AddFuncSource=", 14) ) { VRTImageReadFunc pfnReadFunc = NULL; void *pCBData = NULL; double dfNoDataValue = VRT_NODATA_UNSET; char **papszTokens = CSLTokenizeStringComplex( papszOptions[i]+14, ",", TRUE, FALSE ); if( CSLCount(papszTokens) < 1 ) { CPLError( CE_Failure, CPLE_AppDefined, "AddFuncSource() ... required argument missing." ); } sscanf( papszTokens[0], "%p", &pfnReadFunc ); if( CSLCount(papszTokens) > 1 ) sscanf( papszTokens[1], "%p", &pCBData ); if( CSLCount(papszTokens) > 2 ) dfNoDataValue = atof( papszTokens[2] ); poBand->AddFuncSource( pfnReadFunc, pCBData, dfNoDataValue ); } } return CE_None; } }
GDALDataset *GXFDataset::Open( GDALOpenInfo * poOpenInfo ) { GXFHandle l_hGXF; int i, bFoundKeyword, bFoundIllegal; /* -------------------------------------------------------------------- */ /* Before trying GXFOpen() we first verify that there is at */ /* least one "\n#keyword" type signature in the first chunk of */ /* the file. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->nHeaderBytes < 50 ) return NULL; bFoundKeyword = FALSE; bFoundIllegal = FALSE; for( i = 0; i < poOpenInfo->nHeaderBytes-1; i++ ) { if( (poOpenInfo->pabyHeader[i] == 10 || poOpenInfo->pabyHeader[i] == 13) && poOpenInfo->pabyHeader[i+1] == '#' ) { if( STARTS_WITH((const char*)poOpenInfo->pabyHeader + i + 2, "include") ) return NULL; if( STARTS_WITH((const char*)poOpenInfo->pabyHeader + i + 2, "define") ) return NULL; if( STARTS_WITH((const char*)poOpenInfo->pabyHeader + i + 2, "ifdef") ) return NULL; bFoundKeyword = TRUE; } if( poOpenInfo->pabyHeader[i] == 0 ) { bFoundIllegal = TRUE; break; } } if( !bFoundKeyword || bFoundIllegal ) return NULL; /* -------------------------------------------------------------------- */ /* At this point it is plausible that this is a GXF file, but */ /* we also now verify that there is a #GRID keyword before */ /* passing it off to GXFOpen(). We check in the first 50K. */ /* -------------------------------------------------------------------- */ #define BIGBUFSIZE 50000 int nBytesRead, bGotGrid = FALSE; FILE *fp; fp = VSIFOpen( poOpenInfo->pszFilename, "rb" ); if( fp == NULL ) return NULL; char *pszBigBuf = (char *) CPLMalloc(BIGBUFSIZE); nBytesRead = static_cast<int>(VSIFRead( pszBigBuf, 1, BIGBUFSIZE, fp )); VSIFClose( fp ); for( i = 0; i < nBytesRead - 5 && !bGotGrid; i++ ) { if( pszBigBuf[i] == '#' && STARTS_WITH_CI(pszBigBuf+i+1, "GRID") ) bGotGrid = TRUE; } CPLFree( pszBigBuf ); if( !bGotGrid ) return NULL; /* -------------------------------------------------------------------- */ /* Try opening the dataset. */ /* -------------------------------------------------------------------- */ l_hGXF = GXFOpen( poOpenInfo->pszFilename ); if( l_hGXF == NULL ) return( NULL ); /* -------------------------------------------------------------------- */ /* Confirm the requested access is supported. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->eAccess == GA_Update ) { GXFClose(l_hGXF); CPLError( CE_Failure, CPLE_NotSupported, "The GXF driver does not support update access to existing" " datasets.\n" ); return NULL; } /* -------------------------------------------------------------------- */ /* Create a corresponding GDALDataset. */ /* -------------------------------------------------------------------- */ GXFDataset *poDS; poDS = new GXFDataset(); const char* pszGXFDataType = CPLGetConfigOption("GXF_DATATYPE", "Float32"); GDALDataType eDT = GDALGetDataTypeByName(pszGXFDataType); if (!(eDT == GDT_Float32 || eDT == GDT_Float64)) { CPLError(CE_Warning, CPLE_NotSupported, "Unsupported value for GXF_DATATYPE : %s", pszGXFDataType); eDT = GDT_Float32; } poDS->hGXF = l_hGXF; poDS->eDataType = eDT; /* -------------------------------------------------------------------- */ /* Establish the projection. */ /* -------------------------------------------------------------------- */ poDS->pszProjection = GXFGetMapProjectionAsOGCWKT( l_hGXF ); /* -------------------------------------------------------------------- */ /* Capture some information from the file that is of interest. */ /* -------------------------------------------------------------------- */ GXFGetRawInfo( l_hGXF, &(poDS->nRasterXSize), &(poDS->nRasterYSize), NULL, NULL, NULL, &(poDS->dfNoDataValue) ); if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0) { CPLError( CE_Failure, CPLE_AppDefined, "Invalid dimensions : %d x %d", poDS->nRasterXSize, poDS->nRasterYSize); delete poDS; return NULL; } /* -------------------------------------------------------------------- */ /* Create band information objects. */ /* -------------------------------------------------------------------- */ poDS->nBands = 1; poDS->SetBand( 1, new GXFRasterBand( poDS, 1 )); /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ poDS->SetDescription( poOpenInfo->pszFilename ); poDS->TryLoadXML(); /* -------------------------------------------------------------------- */ /* Check for external overviews. */ /* -------------------------------------------------------------------- */ poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() ); return( poDS ); }
CPLErr VRTRasterBand::XMLInit( CPLXMLNode * psTree, const char *pszVRTPath ) { /* -------------------------------------------------------------------- */ /* Validate a bit. */ /* -------------------------------------------------------------------- */ if( psTree == NULL || psTree->eType != CXT_Element || !EQUAL(psTree->pszValue,"VRTRasterBand") ) { CPLError( CE_Failure, CPLE_AppDefined, "Invalid node passed to VRTRasterBand::XMLInit()." ); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Set the band if provided as an attribute. */ /* -------------------------------------------------------------------- */ const char* pszBand = CPLGetXMLValue( psTree, "band", NULL); if( pszBand != NULL ) { nBand = atoi(pszBand); } /* -------------------------------------------------------------------- */ /* Set the band if provided as an attribute. */ /* -------------------------------------------------------------------- */ const char *pszDataType = CPLGetXMLValue( psTree, "dataType", NULL); if( pszDataType != NULL ) { eDataType = GDALGetDataTypeByName(pszDataType); } /* -------------------------------------------------------------------- */ /* Apply any band level metadata. */ /* -------------------------------------------------------------------- */ oMDMD.XMLInit( psTree, TRUE ); /* -------------------------------------------------------------------- */ /* Collect various other items of metadata. */ /* -------------------------------------------------------------------- */ SetDescription( CPLGetXMLValue( psTree, "Description", "" ) ); if( CPLGetXMLValue( psTree, "NoDataValue", NULL ) != NULL ) SetNoDataValue( CPLAtofM(CPLGetXMLValue( psTree, "NoDataValue", "0" )) ); if( CPLGetXMLValue( psTree, "HideNoDataValue", NULL ) != NULL ) bHideNoDataValue = CSLTestBoolean( CPLGetXMLValue( psTree, "HideNoDataValue", "0" ) ); SetUnitType( CPLGetXMLValue( psTree, "UnitType", NULL ) ); SetOffset( atof(CPLGetXMLValue( psTree, "Offset", "0.0" )) ); SetScale( atof(CPLGetXMLValue( psTree, "Scale", "1.0" )) ); if( CPLGetXMLValue( psTree, "ColorInterp", NULL ) != NULL ) { const char *pszInterp = CPLGetXMLValue( psTree, "ColorInterp", NULL ); SetColorInterpretation(GDALGetColorInterpretationByName(pszInterp)); } /* -------------------------------------------------------------------- */ /* Category names. */ /* -------------------------------------------------------------------- */ if( CPLGetXMLNode( psTree, "CategoryNames" ) != NULL ) { CPLXMLNode *psEntry; CSLDestroy( papszCategoryNames ); papszCategoryNames = NULL; CPLStringList oCategoryNames; for( psEntry = CPLGetXMLNode( psTree, "CategoryNames" )->psChild; psEntry != NULL; psEntry = psEntry->psNext ) { if( psEntry->eType != CXT_Element || !EQUAL(psEntry->pszValue,"Category") || (psEntry->psChild != NULL && psEntry->psChild->eType != CXT_Text) ) continue; oCategoryNames.AddString( (psEntry->psChild) ? psEntry->psChild->pszValue : ""); } papszCategoryNames = oCategoryNames.StealList(); } /* -------------------------------------------------------------------- */ /* Collect a color table. */ /* -------------------------------------------------------------------- */ if( CPLGetXMLNode( psTree, "ColorTable" ) != NULL ) { CPLXMLNode *psEntry; GDALColorTable oTable; int iEntry = 0; for( psEntry = CPLGetXMLNode( psTree, "ColorTable" )->psChild; psEntry != NULL; psEntry = psEntry->psNext ) { GDALColorEntry sCEntry; sCEntry.c1 = (short) atoi(CPLGetXMLValue( psEntry, "c1", "0" )); sCEntry.c2 = (short) atoi(CPLGetXMLValue( psEntry, "c2", "0" )); sCEntry.c3 = (short) atoi(CPLGetXMLValue( psEntry, "c3", "0" )); sCEntry.c4 = (short) atoi(CPLGetXMLValue( psEntry, "c4", "255" )); oTable.SetColorEntry( iEntry++, &sCEntry ); } SetColorTable( &oTable ); } /* -------------------------------------------------------------------- */ /* Histograms */ /* -------------------------------------------------------------------- */ CPLXMLNode *psHist = CPLGetXMLNode( psTree, "Histograms" ); if( psHist != NULL ) { CPLXMLNode *psNext = psHist->psNext; psHist->psNext = NULL; psSavedHistograms = CPLCloneXMLTree( psHist ); psHist->psNext = psNext; } /* ==================================================================== */ /* Overviews */ /* ==================================================================== */ CPLXMLNode *psNode; for( psNode = psTree->psChild; psNode != NULL; psNode = psNode->psNext ) { if( psNode->eType != CXT_Element || !EQUAL(psNode->pszValue,"Overview") ) continue; /* -------------------------------------------------------------------- */ /* Prepare filename. */ /* -------------------------------------------------------------------- */ char *pszSrcDSName = NULL; CPLXMLNode* psFileNameNode=CPLGetXMLNode(psNode,"SourceFilename"); const char *pszFilename = psFileNameNode ? CPLGetXMLValue(psFileNameNode,NULL, NULL) : NULL; if( pszFilename == NULL ) { CPLError( CE_Warning, CPLE_AppDefined, "Missing <SourceFilename> element in Overview." ); return CE_Failure; } if (EQUALN(pszFilename, "MEM:::", 6) && pszVRTPath != NULL && !CSLTestBoolean(CPLGetConfigOption("VRT_ALLOW_MEM_DRIVER", "NO"))) { CPLError( CE_Failure, CPLE_AppDefined, "<SourceFilename> points to a MEM dataset, which is rather suspect! " "If you know what you are doing, define the VRT_ALLOW_MEM_DRIVER configuration option to YES" ); return CE_Failure; } if( pszVRTPath != NULL && atoi(CPLGetXMLValue( psFileNameNode, "relativetoVRT", "0")) ) { pszSrcDSName = CPLStrdup( CPLProjectRelativeFilename( pszVRTPath, pszFilename ) ); } else pszSrcDSName = CPLStrdup( pszFilename ); /* -------------------------------------------------------------------- */ /* Get the raster band. */ /* -------------------------------------------------------------------- */ int nSrcBand = atoi(CPLGetXMLValue(psNode,"SourceBand","1")); apoOverviews.resize( apoOverviews.size() + 1 ); apoOverviews[apoOverviews.size()-1].osFilename = pszSrcDSName; apoOverviews[apoOverviews.size()-1].nBand = nSrcBand; CPLFree( pszSrcDSName ); } /* ==================================================================== */ /* Mask band (specific to that raster band) */ /* ==================================================================== */ CPLXMLNode* psMaskBandNode = CPLGetXMLNode(psTree, "MaskBand"); if (psMaskBandNode) psNode = psMaskBandNode->psChild; else psNode = NULL; for( ; psNode != NULL; psNode = psNode->psNext ) { if( psNode->eType != CXT_Element || !EQUAL(psNode->pszValue,"VRTRasterBand") ) continue; if( ((VRTDataset*)poDS)->poMaskBand != NULL) { CPLError( CE_Warning, CPLE_AppDefined, "Illegal mask band at raster band level when a dataset mask band already exists." ); break; } const char *pszSubclass = CPLGetXMLValue( psNode, "subclass", "VRTSourcedRasterBand" ); VRTRasterBand *poBand = NULL; if( EQUAL(pszSubclass,"VRTSourcedRasterBand") ) poBand = new VRTSourcedRasterBand( GetDataset(), 0 ); else if( EQUAL(pszSubclass, "VRTDerivedRasterBand") ) poBand = new VRTDerivedRasterBand( GetDataset(), 0 ); else if( EQUAL(pszSubclass, "VRTRawRasterBand") ) poBand = new VRTRawRasterBand( GetDataset(), 0 ); else if( EQUAL(pszSubclass, "VRTWarpedRasterBand") ) poBand = new VRTWarpedRasterBand( GetDataset(), 0 ); else { CPLError( CE_Failure, CPLE_AppDefined, "VRTRasterBand of unrecognised subclass '%s'.", pszSubclass ); break; } if( poBand->XMLInit( psNode, pszVRTPath ) == CE_None ) { SetMaskBand(poBand); } break; } return CE_None; }
CPLErr GDALWMSDataset::Initialize(CPLXMLNode *config) { CPLErr ret = CE_None; char* pszXML = CPLSerializeXMLTree( config ); if (pszXML) { m_osXML = pszXML; CPLFree(pszXML); } // Initialize the minidriver, which can set parameters for the dataset using member functions CPLXMLNode *service_node = CPLGetXMLNode(config, "Service"); if (service_node != NULL) { const CPLString service_name = CPLGetXMLValue(service_node, "name", ""); if (!service_name.empty()) { GDALWMSMiniDriverManager *const mdm = GetGDALWMSMiniDriverManager(); GDALWMSMiniDriverFactory *const mdf = mdm->Find(service_name); if (mdf != NULL) { m_mini_driver = mdf->New(); m_mini_driver->m_parent_dataset = this; if (m_mini_driver->Initialize(service_node) == CE_None) { m_mini_driver_caps.m_capabilities_version = -1; m_mini_driver->GetCapabilities(&m_mini_driver_caps); if (m_mini_driver_caps.m_capabilities_version == -1) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Internal error, mini-driver capabilities version not set."); ret = CE_Failure; } } else { delete m_mini_driver; m_mini_driver = NULL; CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Failed to initialize minidriver."); ret = CE_Failure; } } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No mini-driver registered for '%s'.", service_name.c_str()); ret = CE_Failure; } } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No Service specified."); ret = CE_Failure; } } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No Service specified."); ret = CE_Failure; } /* Parameters that could be set by minidriver already, based on server side information. If the size is set, minidriver has done this already A "server" side minidriver needs to set at least: - Blocksize (x and y) - Clamp flag (defaults to true) - DataWindow - Band Count - Data Type It should also initialize and register the bands and overviews. */ if (m_data_window.m_sx<1) { int nOverviews = 0; if (ret == CE_None) { m_block_size_x = atoi(CPLGetXMLValue(config, "BlockSizeX", CPLString().Printf("%d", m_default_block_size_x))); m_block_size_y = atoi(CPLGetXMLValue(config, "BlockSizeY", CPLString().Printf("%d", m_default_block_size_y))); if (m_block_size_x <= 0 || m_block_size_y <= 0) { CPLError( CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value in BlockSizeX or BlockSizeY" ); ret = CE_Failure; } } if (ret == CE_None) { m_clamp_requests = StrToBool(CPLGetXMLValue(config, "ClampRequests", "true")); if (m_clamp_requests<0) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of ClampRequests, true/false expected."); ret = CE_Failure; } } if (ret == CE_None) { CPLXMLNode *data_window_node = CPLGetXMLNode(config, "DataWindow"); if (data_window_node == NULL && m_bNeedsDataWindow) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: DataWindow missing."); ret = CE_Failure; } else { CPLString osDefaultX0, osDefaultX1, osDefaultY0, osDefaultY1; CPLString osDefaultTileCountX, osDefaultTileCountY, osDefaultTileLevel; CPLString osDefaultOverviewCount; osDefaultX0.Printf("%.8f", m_default_data_window.m_x0); osDefaultX1.Printf("%.8f", m_default_data_window.m_x1); osDefaultY0.Printf("%.8f", m_default_data_window.m_y0); osDefaultY1.Printf("%.8f", m_default_data_window.m_y1); osDefaultTileCountX.Printf("%d", m_default_tile_count_x); osDefaultTileCountY.Printf("%d", m_default_tile_count_y); if (m_default_data_window.m_tlevel >= 0) osDefaultTileLevel.Printf("%d", m_default_data_window.m_tlevel); if (m_default_overview_count >= 0) osDefaultOverviewCount.Printf("%d", m_default_overview_count); const char *overview_count = CPLGetXMLValue(config, "OverviewCount", osDefaultOverviewCount); const char *ulx = CPLGetXMLValue(data_window_node, "UpperLeftX", osDefaultX0); const char *uly = CPLGetXMLValue(data_window_node, "UpperLeftY", osDefaultY0); const char *lrx = CPLGetXMLValue(data_window_node, "LowerRightX", osDefaultX1); const char *lry = CPLGetXMLValue(data_window_node, "LowerRightY", osDefaultY1); const char *sx = CPLGetXMLValue(data_window_node, "SizeX", ""); const char *sy = CPLGetXMLValue(data_window_node, "SizeY", ""); const char *tx = CPLGetXMLValue(data_window_node, "TileX", "0"); const char *ty = CPLGetXMLValue(data_window_node, "TileY", "0"); const char *tlevel = CPLGetXMLValue(data_window_node, "TileLevel", osDefaultTileLevel); const char *str_tile_count_x = CPLGetXMLValue(data_window_node, "TileCountX", osDefaultTileCountX); const char *str_tile_count_y = CPLGetXMLValue(data_window_node, "TileCountY", osDefaultTileCountY); const char *y_origin = CPLGetXMLValue(data_window_node, "YOrigin", "default"); if (ret == CE_None) { if ((ulx[0] != '\0') && (uly[0] != '\0') && (lrx[0] != '\0') && (lry[0] != '\0')) { m_data_window.m_x0 = CPLAtof(ulx); m_data_window.m_y0 = CPLAtof(uly); m_data_window.m_x1 = CPLAtof(lrx); m_data_window.m_y1 = CPLAtof(lry); } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Mandatory elements of DataWindow missing: UpperLeftX, UpperLeftY, LowerRightX, LowerRightY."); ret = CE_Failure; } } m_data_window.m_tlevel = atoi(tlevel); if (ret == CE_None) { if ((sx[0] != '\0') && (sy[0] != '\0')) { m_data_window.m_sx = atoi(sx); m_data_window.m_sy = atoi(sy); } else if ((tlevel[0] != '\0') && (str_tile_count_x[0] != '\0') && (str_tile_count_y[0] != '\0')) { int tile_count_x = atoi(str_tile_count_x); int tile_count_y = atoi(str_tile_count_y); m_data_window.m_sx = tile_count_x * m_block_size_x * (1 << m_data_window.m_tlevel); m_data_window.m_sy = tile_count_y * m_block_size_y * (1 << m_data_window.m_tlevel); } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Mandatory elements of DataWindow missing: SizeX, SizeY."); ret = CE_Failure; } } if (ret == CE_None) { if ((tx[0] != '\0') && (ty[0] != '\0')) { m_data_window.m_tx = atoi(tx); m_data_window.m_ty = atoi(ty); } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Mandatory elements of DataWindow missing: TileX, TileY."); ret = CE_Failure; } } if (ret == CE_None) { if (overview_count[0] != '\0') { nOverviews = atoi(overview_count); } else if (tlevel[0] != '\0') { nOverviews = m_data_window.m_tlevel; } else { const int min_overview_size = MAX(32, MIN(m_block_size_x, m_block_size_y)); double a = log(static_cast<double>(MIN(m_data_window.m_sx, m_data_window.m_sy))) / log(2.0) - log(static_cast<double>(min_overview_size)) / log(2.0); nOverviews = MAX(0, MIN(static_cast<int>(ceil(a)), 32)); } } if (ret == CE_None) { CPLString y_origin_str = y_origin; if (y_origin_str == "top") { m_data_window.m_y_origin = GDALWMSDataWindow::TOP; } else if (y_origin_str == "bottom") { m_data_window.m_y_origin = GDALWMSDataWindow::BOTTOM; } else if (y_origin_str == "default") { m_data_window.m_y_origin = GDALWMSDataWindow::DEFAULT; } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: DataWindow YOrigin must be set to " "one of 'default', 'top', or 'bottom', not '%s'.", y_origin_str.c_str()); ret = CE_Failure; } } } } if (ret == CE_None) { if (nBands<1) nBands=atoi(CPLGetXMLValue(config,"BandsCount","3")); if (nBands<1) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Bad number of bands."); ret = CE_Failure; } } if (ret == CE_None) { const char *data_type = CPLGetXMLValue(config, "DataType", "Byte"); m_data_type = GDALGetDataTypeByName( data_type ); if ( m_data_type == GDT_Unknown || m_data_type >= GDT_TypeCount ) { CPLError( CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value in DataType. Data type \"%s\" is not supported.", data_type ); ret = CE_Failure; } } // Initialize the bands and the overviews. Assumes overviews are powers of two if (ret == CE_None) { nRasterXSize = m_data_window.m_sx; nRasterYSize = m_data_window.m_sy; if (!GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize) || !GDALCheckBandCount(nBands, TRUE)) { return CE_Failure; } GDALColorInterp default_color_interp[4][4] = { { GCI_GrayIndex, GCI_Undefined, GCI_Undefined, GCI_Undefined }, { GCI_GrayIndex, GCI_AlphaBand, GCI_Undefined, GCI_Undefined }, { GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_Undefined }, { GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_AlphaBand } }; for (int i = 0; i < nBands; ++i) { GDALColorInterp color_interp = (nBands <= 4 && i <= 3 ? default_color_interp[nBands - 1][i] : GCI_Undefined); GDALWMSRasterBand *band = new GDALWMSRasterBand(this, i, 1.0); band->m_color_interp = color_interp; SetBand(i + 1, band); double scale = 0.5; for (int j = 0; j < nOverviews; ++j) { band->AddOverview(scale); band->m_color_interp = color_interp; scale *= 0.5; } } } } // UserPwd const char *pszUserPwd = CPLGetXMLValue(config, "UserPwd", ""); if (pszUserPwd[0] != '\0') m_osUserPwd = pszUserPwd; const char *pszUserAgent = CPLGetXMLValue(config, "UserAgent", ""); if (pszUserAgent[0] != '\0') m_osUserAgent = pszUserAgent; const char *pszReferer = CPLGetXMLValue(config, "Referer", ""); if (pszReferer[0] != '\0') m_osReferer = pszReferer; if (ret == CE_None) { const char *pszHttpZeroBlockCodes = CPLGetXMLValue(config, "ZeroBlockHttpCodes", ""); if(pszHttpZeroBlockCodes[0] == '\0') { m_http_zeroblock_codes.push_back(204); } else { char **kv = CSLTokenizeString2(pszHttpZeroBlockCodes,",",CSLT_HONOURSTRINGS); int nCount = CSLCount(kv); for(int i=0; i<nCount; i++) { int code = atoi(kv[i]); if(code <= 0) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of ZeroBlockHttpCodes \"%s\", comma separated HTTP response codes expected.", kv[i]); ret = CE_Failure; break; } m_http_zeroblock_codes.push_back(code); } CSLDestroy(kv); } } if (ret == CE_None) { const char *pszZeroExceptions = CPLGetXMLValue(config, "ZeroBlockOnServerException", ""); if(pszZeroExceptions[0] != '\0') { m_zeroblock_on_serverexceptions = StrToBool(pszZeroExceptions); if (m_zeroblock_on_serverexceptions == -1) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of ZeroBlockOnServerException \"%s\", true/false expected.", pszZeroExceptions); ret = CE_Failure; } } } if (ret == CE_None) { const char *max_conn = CPLGetXMLValue(config, "MaxConnections", ""); if (max_conn[0] != '\0') { m_http_max_conn = atoi(max_conn); } else { m_http_max_conn = 2; } } if (ret == CE_None) { const char *timeout = CPLGetXMLValue(config, "Timeout", ""); if (timeout[0] != '\0') { m_http_timeout = atoi(timeout); } else { m_http_timeout = 300; } } if (ret == CE_None) { const char *offline_mode = CPLGetXMLValue(config, "OfflineMode", ""); if (offline_mode[0] != '\0') { const int offline_mode_bool = StrToBool(offline_mode); if (offline_mode_bool == -1) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of OfflineMode, true / false expected."); ret = CE_Failure; } else { m_offline_mode = offline_mode_bool; } } else { m_offline_mode = 0; } } if (ret == CE_None) { const char *advise_read = CPLGetXMLValue(config, "AdviseRead", ""); if (advise_read[0] != '\0') { const int advise_read_bool = StrToBool(advise_read); if (advise_read_bool == -1) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of AdviseRead, true / false expected."); ret = CE_Failure; } else { m_use_advise_read = advise_read_bool; } } else { m_use_advise_read = 0; } } if (ret == CE_None) { const char *verify_advise_read = CPLGetXMLValue(config, "VerifyAdviseRead", ""); if (m_use_advise_read) { if (verify_advise_read[0] != '\0') { const int verify_advise_read_bool = StrToBool(verify_advise_read); if (verify_advise_read_bool == -1) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of VerifyAdviseRead, true / false expected."); ret = CE_Failure; } else { m_verify_advise_read = verify_advise_read_bool; } } else { m_verify_advise_read = 1; } } } // Let the local configuration override the minidriver supplied projection if (ret == CE_None) { const char *proj = CPLGetXMLValue(config, "Projection", ""); if (proj[0] != '\0') { m_projection = ProjToWKT(proj); if (m_projection.size() == 0) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Bad projection specified."); ret = CE_Failure; } } } // Same for Min, Max and NoData, defined per band or per dataset // If they are set as null strings, they clear the server declared values if (ret == CE_None) { // Data values are attributes, they include NoData Min and Max // TODO: document those options if (0!=CPLGetXMLNode(config,"DataValues")) { const char *nodata=CPLGetXMLValue(config,"DataValues.NoData",NULL); if (nodata!=NULL) WMSSetNoDataValue(nodata); const char *min=CPLGetXMLValue(config,"DataValues.min",NULL); if (min!=NULL) WMSSetMinValue(min); const char *max=CPLGetXMLValue(config,"DataValues.max",NULL); if (max!=NULL) WMSSetMaxValue(max); } } if (ret == CE_None) { CPLXMLNode *cache_node = CPLGetXMLNode(config, "Cache"); if (cache_node != NULL) { m_cache = new GDALWMSCache(); if (m_cache->Initialize(cache_node) != CE_None) { delete m_cache; m_cache = NULL; CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Failed to initialize cache."); ret = CE_Failure; } } } if (ret == CE_None) { const int v = StrToBool(CPLGetXMLValue(config, "UnsafeSSL", "false")); if (v == -1) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of UnsafeSSL: true or false expected."); ret = CE_Failure; } else { m_unsafeSsl = v; } } if (ret == CE_None) { /* If we dont have projection already set ask mini-driver. */ if (!m_projection.size()) { const char *proj = m_mini_driver->GetProjectionInWKT(); if (proj != NULL) { m_projection = proj; } } } return ret; }
CPLErr GDALWMSMiniDriver_TiledWMS::Initialize(CPLXMLNode *config, CPL_UNUSED char **OpenOptions) { CPLErr ret = CE_None; CPLXMLNode *tileServiceConfig=NULL; CPLHTTPResult *psResult=NULL; CPLXMLNode *TG=NULL; char **requests=NULL; char **substs=NULL; char **keys=NULL; for (int once=1;once;once--) { // Something to break out of // Parse info from the service m_end_url = CPLGetXMLValue(config,"AdditionalArgs",""); m_base_url = CPLGetXMLValue(config, "ServerURL", ""); if (m_base_url.empty()) { CPLError(ret=CE_Failure, CPLE_AppDefined, "%s ServerURL missing.",SIG); break; } CPLString tiledGroupName (CPLGetXMLValue(config, "TiledGroupName", "")); if (tiledGroupName.empty()) { CPLError(ret=CE_Failure, CPLE_AppDefined, "%s TiledGroupName missing.",SIG); break; } // Change strings, key is an attribute, value is the value of the Change node // Multiple substitutions are possible TG=CPLSearchXMLNode(config, "Change"); while(TG!=NULL) { CPLString name=CPLGetXMLValue(TG,"key",""); if (name.empty()) { CPLError(ret=CE_Failure, CPLE_AppDefined, "%s Change element needs a non-empty \"key\" attribute",SIG); break; } substs=CSLSetNameValue(substs,name,CPLGetXMLValue(TG,"","")); TG=SearchXMLSiblings(TG,"Change"); } if (ret!=CE_None) break; CPLString getTileServiceUrl = m_base_url + "request=GetTileService"; psResult = CPLHTTPFetch(getTileServiceUrl, NULL); if (NULL==psResult) { CPLError(ret=CE_Failure, CPLE_AppDefined, "%s Can't use HTTP", SIG); break; } if ((psResult->nStatus!=0)||(NULL==psResult->pabyData)||('\0'==psResult->pabyData[0])) { CPLError(ret=CE_Failure, CPLE_AppDefined, "%s Server response error on GetTileService.",SIG); break; } if (NULL==(tileServiceConfig=CPLParseXMLString((const char*)psResult->pabyData))) { CPLError(ret=CE_Failure,CPLE_AppDefined, "%s Error parsing the GetTileService response.",SIG); break; } if (NULL==(TG=CPLSearchXMLNode(tileServiceConfig, "TiledPatterns"))) { CPLError(ret=CE_Failure,CPLE_AppDefined, "%s Can't locate TiledPatterns in server response.",SIG); break; } // Get the global base_url and bounding box, these can be overwritten at the tileGroup level // They are just pointers into existing structures, cleanup is not required const char *global_base_url=CPLGetXMLValue(tileServiceConfig,"TiledPatterns.OnlineResource.xlink:href",""); CPLXMLNode *global_latlonbbox=CPLGetXMLNode(tileServiceConfig, "TiledPatterns.LatLonBoundingBox"); CPLXMLNode *global_bbox=CPLGetXMLNode(tileServiceConfig, "TiledPatterns.BoundingBox"); if (NULL==(TG=SearchLeafGroupName(TG->psChild,tiledGroupName))) { CPLError(ret=CE_Failure,CPLE_AppDefined, "%s Can't locate TiledGroup ""%s"" in server response.",SIG, tiledGroupName.c_str()); break; } int band_count=atoi(CPLGetXMLValue(TG, "Bands", "3")); if (!GDALCheckBandCount(band_count, FALSE)) { CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s",SIG, "Invalid number of bands in server response"); break; } // Collect all keys defined by this tileset if (NULL!=CPLGetXMLNode(TG,"Key")) { CPLXMLNode *node=CPLGetXMLNode(TG,"Key"); while (NULL!=node) { const char *val=CPLGetXMLValue(node,NULL,NULL); if (val) keys=CSLAddString(keys,val); node=SearchXMLSiblings(node,"Key"); } } // Data values are attributes, they include NoData Min and Max if (NULL!=CPLGetXMLNode(TG,"DataValues")) { const char *nodata=CPLGetXMLValue(TG,"DataValues.NoData",NULL); if (nodata!=NULL) m_parent_dataset->WMSSetNoDataValue(nodata); const char *min=CPLGetXMLValue(TG,"DataValues.min",NULL); if (min!=NULL) m_parent_dataset->WMSSetMinValue(min); const char *max=CPLGetXMLValue(TG,"DataValues.max",NULL); if (max!=NULL) m_parent_dataset->WMSSetMaxValue(max); } m_parent_dataset->WMSSetBandsCount(band_count); m_parent_dataset->WMSSetDataType(GDALGetDataTypeByName(CPLGetXMLValue(TG, "DataType", "Byte"))); m_projection_wkt=CPLGetXMLValue(TG, "Projection",""); m_base_url=CPLGetXMLValue(TG,"OnlineResource.xlink:href",global_base_url); if (m_base_url[0]=='\0') { CPLError(ret=CE_Failure,CPLE_AppDefined, "%s%s",SIG, "Can't locate OnlineResource in the server response."); break; } // Bounding box, local, global, local lat-lon, global lat-lon, in this order CPLXMLNode *bbox = CPLGetXMLNode(TG, "BoundingBox"); if (NULL==bbox) bbox=global_bbox; if (NULL==bbox) bbox=CPLGetXMLNode(TG, "LatLonBoundingBox"); if (NULL==bbox) bbox=global_latlonbbox; if (NULL==bbox) { CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s",SIG, "Can't locate the LatLonBoundingBox in server response."); break; } m_data_window.m_x0=CPLAtof(CPLGetXMLValue(bbox,"minx","0")); m_data_window.m_x1=CPLAtof(CPLGetXMLValue(bbox,"maxx","-1")); m_data_window.m_y0=CPLAtof(CPLGetXMLValue(bbox,"maxy","0")); m_data_window.m_y1=CPLAtof(CPLGetXMLValue(bbox,"miny","-1")); if ((m_data_window.m_x1-m_data_window.m_x0)<0) { CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s", SIG, "Coordinate order in BBox, problem in server response"); break; } // Is there a palette? // // Format is // <Palette> // <Size>N</Size> : Optional // <Model>RGBA|RGB|CMYK|HSV|HLS|L</Model> :mandatory // <Entry idx=i c1=v1 c2=v2 c3=v3 c4=v4/> :Optional // <Entry .../> // </Palette> // the idx attribute is optional, it autoincrements // The entries are actually vertices, interpolation takes place inside // The palette starts initialized with zeros // HSV and HLS are the similar, with c2 and c3 swapped // RGB or RGBA are same // GDALColorTable *poColorTable=NULL; if ((band_count==1) && CPLGetXMLNode(TG,"Palette")) { CPLXMLNode *node=CPLGetXMLNode(TG,"Palette"); int entries=static_cast<int>(getXMLNum(node,"Size","255")); GDALPaletteInterp eInterp=GPI_RGB; CPLString pModel=CPLGetXMLValue(node,"Model","RGB"); if (!pModel.empty() && pModel.find("RGB")!=std::string::npos) eInterp=GPI_RGB; else { CPLError(CE_Failure, CPLE_AppDefined, "%s Palette Model %s is unknown, use RGB or RGBA", SIG, pModel.c_str()); return CE_Failure; } if ((entries>0)&&(entries<257)) { int start_idx, end_idx; GDALColorEntry ce_start={0,0,0,255},ce_end={0,0,0,255}; // Create it and initialize it to nothing poColorTable = new GDALColorTable(eInterp); poColorTable->CreateColorRamp(0,&ce_start,entries-1,&ce_end); // Read the values CPLXMLNode *p=CPLGetXMLNode(node,"Entry"); if (p) { // Initialize the first entry start_idx=static_cast<int>(getXMLNum(p,"idx","0")); ce_start=GetXMLColorEntry(p); if (start_idx<0) { CPLError(CE_Failure, CPLE_AppDefined, "%s Palette index %d not allowed",SIG,start_idx); delete poColorTable; return CE_Failure; } poColorTable->SetColorEntry(start_idx,&ce_start); while (NULL!=(p=SearchXMLSiblings(p,"Entry"))) { // For every entry, create a ramp ce_end=GetXMLColorEntry(p); end_idx=static_cast<int>(getXMLNum(p,"idx",CPLString().FormatC(start_idx+1).c_str())); if ((end_idx<=start_idx)||(start_idx>=entries)) { CPLError(CE_Failure, CPLE_AppDefined, "%s Index Error at index %d",SIG,end_idx); delete poColorTable; return CE_Failure; } poColorTable->CreateColorRamp(start_idx,&ce_start, end_idx,&ce_end); ce_start=ce_end; start_idx=end_idx; } } m_parent_dataset->SetColorTable(poColorTable); } else { CPLError(CE_Failure, CPLE_AppDefined,"%s Palette definition error",SIG); return CE_Failure; } } int overview_count=0; CPLXMLNode *Pattern=TG->psChild; m_bsx=m_bsy=-1; m_data_window.m_sx=m_data_window.m_sy=0; for (int once2=1;once2;once2--) { // Something to break out of while ((NULL!=Pattern)&&(NULL!=(Pattern=SearchXMLSiblings(Pattern,"=TilePattern")))) { int mbsx,mbsy; CPLString request; FindChangePattern(Pattern->psChild->pszValue,substs,keys,request); char **papszTokens=CSLTokenizeString2(request,"&",0); const char* pszWIDTH = CSLFetchNameValue(papszTokens,"WIDTH"); const char* pszHEIGHT = CSLFetchNameValue(papszTokens,"HEIGHT"); if (pszWIDTH == NULL || pszHEIGHT == NULL) { CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s",SIG, "Cannot find width and/or height parameters."); overview_count=0; CSLDestroy(papszTokens); break; } mbsx=atoi(pszWIDTH); mbsy=atoi(pszHEIGHT); if (m_projection_wkt.empty()) { m_projection_wkt = CSLFetchNameValueDef(papszTokens,"SRS", ""); if (!m_projection_wkt.empty()) m_projection_wkt=ProjToWKT(m_projection_wkt); } if (-1==m_bsx) m_bsx=mbsx; if (-1==m_bsy) m_bsy=mbsy; if ((m_bsx!=mbsx)||(m_bsy!=mbsy)) { CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s",SIG, "Tileset uses different block sizes."); overview_count=0; CSLDestroy(papszTokens); break; } double x,y,X,Y; if (CPLsscanf(CSLFetchNameValueDef(papszTokens,"BBOX", ""),"%lf,%lf,%lf,%lf",&x,&y,&X,&Y)!=4) { CPLError(ret=CE_Failure,CPLE_AppDefined, "%s Error parsing BBOX, pattern %d\n",SIG,overview_count+1); CSLDestroy(papszTokens); break; } // Pick the largest size int sx=static_cast<int>((m_data_window.m_x1-m_data_window.m_x0)/(X-x)*m_bsx); int sy=static_cast<int>(fabs((m_data_window.m_y1-m_data_window.m_y0)/(Y-y)*m_bsy)); if (sx>m_data_window.m_sx) m_data_window.m_sx=sx; if (sy>m_data_window.m_sy) m_data_window.m_sy=sy; CSLDestroy(papszTokens); // Only use overlays where the top coordinate is within a pixel from the top of coverage double pix_off,temp; pix_off=m_bsy*modf(fabs((Y-m_data_window.m_y0)/(Y-y)),&temp); if ((pix_off<1)||((m_bsy-pix_off)<1)) { requests=CSLAddString(requests,request); overview_count++; } else CPLError(CE_Warning,CPLE_AppDefined, "%s Overlay size %dX%d can't be used due to alignment",SIG,sx,sy); Pattern=Pattern->psNext; } // The tlevel is needed, the tx and ty are not used by this minidriver m_data_window.m_tlevel = 0; m_data_window.m_tx = 0; m_data_window.m_ty = 0; // Make sure the parent_dataset values are set before creating the bands m_parent_dataset->WMSSetBlockSize(m_bsx,m_bsy); m_parent_dataset->WMSSetRasterSize(m_data_window.m_sx,m_data_window.m_sy); m_parent_dataset->WMSSetDataWindow(m_data_window); //m_parent_dataset->WMSSetOverviewCount(overview_count); m_parent_dataset->WMSSetClamp(false); // Ready for the Rasterband creation for (int i=0;i<overview_count;i++) { CPLString request=GetLowestScale(requests,i); double scale=Scale(request); // Base scale should be very close to 1 if ((0==i)&&(fabs(scale-1) > 1e-6)) { CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s",SIG, "Base resolution pattern missing."); break; } // Prepare the request and insert it back into the list // Find returns an answer relative to the original string start! size_t startBbox=FindBbox(request); size_t endBbox=request.find('&',startBbox); if (endBbox==std::string::npos) endBbox=request.size(); request.replace(startBbox,endBbox-startBbox,"${GDAL_BBOX}"); requests = CSLInsertString(requests,i,request); // Create the Rasterband or overview for (int j = 1; j <= band_count; j++) { if (i!=0) m_parent_dataset->mGetBand(j)->AddOverview(scale); else { // Base resolution GDALWMSRasterBand *band=new GDALWMSRasterBand(m_parent_dataset,j,1); if (poColorTable!=NULL) band->SetColorInterpretation(GCI_PaletteIndex); else band->SetColorInterpretation(BandInterp(band_count,j)); m_parent_dataset->mSetBand(j, band); }; } } if ((overview_count==0)||(m_bsx<1)||(m_bsy<1)) { CPLError(ret=CE_Failure,CPLE_AppDefined, "%s No usable TilePattern elements found",SIG); break; } } } CSLDestroy(keys); CSLDestroy(substs); if (tileServiceConfig) CPLDestroyXMLNode(tileServiceConfig); if (psResult) CPLHTTPDestroyResult(psResult); m_requests=requests; return ret; }
CPLErr GDALWMSDataset::Initialize(CPLXMLNode *config) { CPLErr ret = CE_None; if (ret == CE_None) { const char *max_conn = CPLGetXMLValue(config, "MaxConnections", ""); if (max_conn[0] != '\0') { m_http_max_conn = atoi(max_conn); } else { m_http_max_conn = 2; } } if (ret == CE_None) { const char *timeout = CPLGetXMLValue(config, "Timeout", ""); if (timeout[0] != '\0') { m_http_timeout = atoi(timeout); } else { m_http_timeout = 300; } } if (ret == CE_None) { const char *offline_mode = CPLGetXMLValue(config, "OfflineMode", ""); if (offline_mode[0] != '\0') { const int offline_mode_bool = StrToBool(offline_mode); if (offline_mode_bool == -1) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of OfflineMode, true / false expected."); ret = CE_Failure; } else { m_offline_mode = offline_mode_bool; } } else { m_offline_mode = 0; } } if (ret == CE_None) { const char *advise_read = CPLGetXMLValue(config, "AdviseRead", ""); if (advise_read[0] != '\0') { const int advise_read_bool = StrToBool(advise_read); if (advise_read_bool == -1) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of AdviseRead, true / false expected."); ret = CE_Failure; } else { m_use_advise_read = advise_read_bool; } } else { m_use_advise_read = 0; } } if (ret == CE_None) { const char *verify_advise_read = CPLGetXMLValue(config, "VerifyAdviseRead", ""); if (m_use_advise_read) { if (verify_advise_read[0] != '\0') { const int verify_advise_read_bool = StrToBool(verify_advise_read); if (verify_advise_read_bool == -1) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of VerifyAdviseRead, true / false expected."); ret = CE_Failure; } else { m_verify_advise_read = verify_advise_read_bool; } } else { m_verify_advise_read = 1; } } } if (ret == CE_None) { const char *block_size_x = CPLGetXMLValue(config, "BlockSizeX", "1024"); const char *block_size_y = CPLGetXMLValue(config, "BlockSizeY", "1024"); m_block_size_x = atoi(block_size_x); m_block_size_y = atoi(block_size_y); if (m_block_size_x <= 0 || m_block_size_y <= 0) { CPLError( CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value in BlockSizeX or BlockSizeY" ); ret = CE_Failure; } } if (ret == CE_None) { const char *data_type = CPLGetXMLValue(config, "DataType", "Byte"); m_data_type = GDALGetDataTypeByName( data_type ); if ( m_data_type == GDT_Unknown || m_data_type >= GDT_TypeCount ) { CPLError( CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value in DataType. Data type \"%s\" is not supported.", data_type ); ret = CE_Failure; } } if (ret == CE_None) { const int clamp_requests_bool = StrToBool(CPLGetXMLValue(config, "ClampRequests", "true")); if (clamp_requests_bool == -1) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of ClampRequests, true / false expected."); ret = CE_Failure; } else { m_clamp_requests = clamp_requests_bool; } } if (ret == CE_None) { CPLXMLNode *data_window_node = CPLGetXMLNode(config, "DataWindow"); if (data_window_node == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: DataWindow missing."); ret = CE_Failure; } else { const char *overview_count = CPLGetXMLValue(config, "OverviewCount", ""); const char *ulx = CPLGetXMLValue(data_window_node, "UpperLeftX", "-180.0"); const char *uly = CPLGetXMLValue(data_window_node, "UpperLeftY", "90.0"); const char *lrx = CPLGetXMLValue(data_window_node, "LowerRightX", "180.0"); const char *lry = CPLGetXMLValue(data_window_node, "LowerRightY", "-90.0"); const char *sx = CPLGetXMLValue(data_window_node, "SizeX", ""); const char *sy = CPLGetXMLValue(data_window_node, "SizeY", ""); const char *tx = CPLGetXMLValue(data_window_node, "TileX", "0"); const char *ty = CPLGetXMLValue(data_window_node, "TileY", "0"); const char *tlevel = CPLGetXMLValue(data_window_node, "TileLevel", ""); const char *str_tile_count_x = CPLGetXMLValue(data_window_node, "TileCountX", "1"); const char *str_tile_count_y = CPLGetXMLValue(data_window_node, "TileCountY", "1"); const char *y_origin = CPLGetXMLValue(data_window_node, "YOrigin", "default"); if (ret == CE_None) { if ((ulx[0] != '\0') && (uly[0] != '\0') && (lrx[0] != '\0') && (lry[0] != '\0')) { m_data_window.m_x0 = atof(ulx); m_data_window.m_y0 = atof(uly); m_data_window.m_x1 = atof(lrx); m_data_window.m_y1 = atof(lry); } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Mandatory elements of DataWindow missing: UpperLeftX, UpperLeftY, LowerRightX, LowerRightY."); ret = CE_Failure; } } if (ret == CE_None) { if (tlevel[0] != '\0') { m_data_window.m_tlevel = atoi(tlevel); } else { m_data_window.m_tlevel = 0; } } if (ret == CE_None) { if ((sx[0] != '\0') && (sy[0] != '\0')) { m_data_window.m_sx = atoi(sx); m_data_window.m_sy = atoi(sy); } else if ((tlevel[0] != '\0') && (str_tile_count_x[0] != '\0') && (str_tile_count_y[0] != '\0')) { int tile_count_x = atoi(str_tile_count_x); int tile_count_y = atoi(str_tile_count_y); m_data_window.m_sx = tile_count_x * m_block_size_x * (1 << m_data_window.m_tlevel); m_data_window.m_sy = tile_count_y * m_block_size_y * (1 << m_data_window.m_tlevel); } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Mandatory elements of DataWindow missing: SizeX, SizeY."); ret = CE_Failure; } } if (ret == CE_None) { if ((tx[0] != '\0') && (ty[0] != '\0')) { m_data_window.m_tx = atoi(tx); m_data_window.m_ty = atoi(ty); } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Mandatory elements of DataWindow missing: TileX, TileY."); ret = CE_Failure; } } if (ret == CE_None) { if (overview_count[0] != '\0') { m_overview_count = atoi(overview_count); } else if (tlevel[0] != '\0') { m_overview_count = m_data_window.m_tlevel; } else { const int min_overview_size = MAX(32, MIN(m_block_size_x, m_block_size_y)); double a = log(static_cast<double>(MIN(m_data_window.m_sx, m_data_window.m_sy))) / log(2.0) - log(static_cast<double>(min_overview_size)) / log(2.0); m_overview_count = MAX(0, MIN(static_cast<int>(ceil(a)), 32)); } } if (ret == CE_None) { CPLString y_origin_str = y_origin; if (y_origin_str == "top") { m_data_window.m_y_origin = GDALWMSDataWindow::TOP; } else if (y_origin_str == "bottom") { m_data_window.m_y_origin = GDALWMSDataWindow::BOTTOM; } else if (y_origin_str == "default") { m_data_window.m_y_origin = GDALWMSDataWindow::DEFAULT; } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: DataWindow YOrigin must be set to " "one of 'default', 'top', or 'bottom', not '%s'.", y_origin_str.c_str()); ret = CE_Failure; } } } } if (ret == CE_None) { const char *proj = CPLGetXMLValue(config, "Projection", ""); if (proj[0] != '\0') { m_projection = ProjToWKT(proj); if (m_projection.size() == 0) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Bad projection specified."); ret = CE_Failure; } } } const char *bands_count = CPLGetXMLValue(config, "BandsCount", "3"); int nBandCount = atoi(bands_count); if (ret == CE_None) { CPLXMLNode *cache_node = CPLGetXMLNode(config, "Cache"); if (cache_node != NULL) { m_cache = new GDALWMSCache(); if (m_cache->Initialize(cache_node) != CE_None) { delete m_cache; m_cache = NULL; CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Failed to initialize cache."); ret = CE_Failure; } } } if (ret == CE_None) { CPLXMLNode *service_node = CPLGetXMLNode(config, "Service"); if (service_node != NULL) { const char *service_name = CPLGetXMLValue(service_node, "name", ""); if (service_name[0] != '\0') { GDALWMSMiniDriverManager *const mdm = GetGDALWMSMiniDriverManager(); GDALWMSMiniDriverFactory *const mdf = mdm->Find(CPLString(service_name)); if (mdf != NULL) { m_mini_driver = mdf->New(); m_mini_driver->m_parent_dataset = this; if (m_mini_driver->Initialize(service_node) == CE_None) { m_mini_driver_caps.m_capabilities_version = -1; m_mini_driver->GetCapabilities(&m_mini_driver_caps); if (m_mini_driver_caps.m_capabilities_version == -1) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Internal error, mini-driver capabilities version not set."); ret = CE_Failure; } } else { delete m_mini_driver; m_mini_driver = NULL; CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Failed to initialize minidriver."); ret = CE_Failure; } } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No mini-driver registered for '%s'.", service_name); ret = CE_Failure; } } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No Service specified."); ret = CE_Failure; } } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No Service specified."); ret = CE_Failure; } } if (ret == CE_None) { nRasterXSize = m_data_window.m_sx; nRasterYSize = m_data_window.m_sy; if (!GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize) || !GDALCheckBandCount(nBandCount, TRUE)) { return CE_Failure; } for (int i = 0; i < nBandCount; ++i) { GDALWMSRasterBand *band = new GDALWMSRasterBand(this, i, 1.0); SetBand(i + 1, band); double scale = 0.5; for (int j = 0; j < m_overview_count; ++j) { band->AddOverview(scale); scale *= 0.5; } } } if (ret == CE_None) { /* If we dont have projection already set ask mini-driver. */ if (!m_projection.size()) { const char *proj = m_mini_driver->GetProjectionInWKT(); if (proj != NULL) { m_projection = proj; } } } return ret; }
GDALDataset *ISCEDataset::Open( GDALOpenInfo *poOpenInfo ) { /* -------------------------------------------------------------------- */ /* Confirm that the header is compatible with a ISCE dataset. */ /* -------------------------------------------------------------------- */ if ( !Identify(poOpenInfo) ) { return NULL; } /* -------------------------------------------------------------------- */ /* Open and parse the .xml file */ /* -------------------------------------------------------------------- */ const CPLString osXMLFilename = getXMLFilename( poOpenInfo ); CPLXMLNode *psNode = CPLParseXMLFile( osXMLFilename ); if ( psNode == NULL || CPLGetXMLNode( psNode, "=imageFile" ) == NULL ) { CPLDestroyXMLNode( psNode ); return NULL; } CPLXMLNode *psCur = CPLGetXMLNode( psNode, "=imageFile" )->psChild; char **papszXmlProps = NULL; while ( psCur != NULL ) { const char *name, *value; if ( strcmp(psCur->pszValue, "property") != 0) { psCur = psCur->psNext; continue; } name = CPLGetXMLValue( psCur, "name", NULL ); value = CPLGetXMLValue( psCur, "value.", NULL ); papszXmlProps = CSLSetNameValue( papszXmlProps, name, value ); psCur = psCur->psNext; } /* TODO: extract <component name=Coordinate[12]> for georeferencing */ CPLDestroyXMLNode( psNode ); /* -------------------------------------------------------------------- */ /* Fetch required fields. */ /* -------------------------------------------------------------------- */ if ( CSLFetchNameValue( papszXmlProps, "WIDTH" ) == NULL || CSLFetchNameValue( papszXmlProps, "LENGTH" ) == NULL || CSLFetchNameValue( papszXmlProps, "NUMBER_BANDS" ) == NULL || CSLFetchNameValue( papszXmlProps, "DATA_TYPE" ) == NULL || CSLFetchNameValue( papszXmlProps, "SCHEME" ) == NULL ) { CSLDestroy( papszXmlProps ); return NULL; } const int nWidth = atoi( CSLFetchNameValue( papszXmlProps, "WIDTH" ) ); const int nFileLength = atoi( CSLFetchNameValue( papszXmlProps, "LENGTH" ) ); /* -------------------------------------------------------------------- */ /* Update byte order info if image specify something. */ /* -------------------------------------------------------------------- */ bool bNativeOrder = true; if ( CSLFetchNameValue( papszXmlProps, "BYTE_ORDER" ) != NULL ) { const char *sByteOrder = CSLFetchNameValue( papszXmlProps, "BYTE_ORDER" ); #ifdef CPL_LSB if ( EQUAL( sByteOrder, "b" ) ) #else if ( EQUAL( sByteOrder, "l" ) ) #endif bNativeOrder = false; } /* -------------------------------------------------------------------- */ /* Create a corresponding GDALDataset. */ /* -------------------------------------------------------------------- */ ISCEDataset *poDS = new ISCEDataset(); poDS->nRasterXSize = nWidth; poDS->nRasterYSize = nFileLength; poDS->eAccess = poOpenInfo->eAccess; poDS->pszXMLFilename = CPLStrdup( osXMLFilename.c_str() ); /* -------------------------------------------------------------------- */ /* Reopen file in update mode if necessary. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->eAccess == GA_Update ) { poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb+" ); } else { poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb" ); } if( poDS->fpImage == NULL ) { CSLDestroy( papszXmlProps ); delete poDS; CPLError( CE_Failure, CPLE_OpenFailed, "Failed to re-open %s within ISCE driver.\n", poOpenInfo->pszFilename ); return NULL; } /* -------------------------------------------------------------------- */ /* Create band information objects. */ /* -------------------------------------------------------------------- */ const char *sDataType = CSLFetchNameValue( (char **)apszISCE2GDALDatatypes, CSLFetchNameValue( papszXmlProps, "DATA_TYPE" ) ); const GDALDataType eDataType = GDALGetDataTypeByName( sDataType ); const int nBands = atoi( CSLFetchNameValue( papszXmlProps, "NUMBER_BANDS" ) ); const char *sScheme = CSLFetchNameValue( papszXmlProps, "SCHEME" ); int nPixelOffset, nLineOffset, nBandOffset; if ( EQUAL( sScheme, "BIL" ) ) { poDS->eScheme = BIL; nPixelOffset = GDALGetDataTypeSize(eDataType)/8; nLineOffset = nPixelOffset * nWidth * nBands; nBandOffset = GDALGetDataTypeSize(eDataType)/8 * nWidth; } else if ( EQUAL( sScheme, "BIP" ) ) { poDS->eScheme = BIP; nPixelOffset = GDALGetDataTypeSize(eDataType)/8 * nBands; nLineOffset = nPixelOffset * nWidth; if( nBands > 1 ) { // GDAL 2.1.0 had a value of nLineOffset that was equal to the theoretical // nLineOffset multiplied by nBands... VSIFSeekL( poDS->fpImage, 0, SEEK_END ); const GUIntBig nWrongFileSize = GDALGetDataTypeSizeBytes(eDataType) * nWidth * (static_cast<GUIntBig>(nFileLength - 1) * nBands * nBands + nBands); if( VSIFTellL( poDS->fpImage ) == nWrongFileSize ) { CPLError(CE_Warning, CPLE_AppDefined, "This file has been incorrectly generated by an older " "GDAL version whose line offset computation was erroneous. " "Taking that into account, but the file should be re-encoded ideally"); nLineOffset = nLineOffset * nBands; } } nBandOffset = GDALGetDataTypeSize(eDataType)/8; } else if ( EQUAL( sScheme, "BSQ" ) ) { poDS->eScheme = BSQ; nPixelOffset = GDALGetDataTypeSize(eDataType)/8; nLineOffset = nPixelOffset * nWidth; nBandOffset = nLineOffset * nFileLength; } else { CSLDestroy( papszXmlProps ); delete poDS; CPLError( CE_Failure, CPLE_OpenFailed, "Unknown scheme \"%s\" within ISCE raster.\n", CSLFetchNameValue( papszXmlProps, "SCHEME" ) ); return NULL; } poDS->nBands = nBands; for (int b = 0; b < nBands; b++) { poDS->SetBand( b + 1, new ISCERasterBand( poDS, b + 1, poDS->fpImage, nBandOffset * b, nPixelOffset, nLineOffset, eDataType, TRUE, bNativeOrder, FALSE ) ); } /* -------------------------------------------------------------------- */ /* Interpret georeferencing, if present. */ /* -------------------------------------------------------------------- */ /* TODO */ /* -------------------------------------------------------------------- */ /* Set all the other header metadata into the ISCE domain */ /* -------------------------------------------------------------------- */ for (int i = 0; papszXmlProps != NULL && papszXmlProps[i] != NULL; i++) { char **papszTokens; papszTokens = CSLTokenizeString2( papszXmlProps[i], "=", CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES); if ( strcmp( papszTokens[0], "WIDTH" ) == 0 || strcmp( papszTokens[0], "LENGTH" ) == 0 || strcmp( papszTokens[0], "NUMBER_BANDS" ) == 0 || strcmp( papszTokens[0], "DATA_TYPE" ) == 0 || strcmp( papszTokens[0], "SCHEME" ) == 0 ) { CSLDestroy( papszTokens ); continue; } poDS->SetMetadataItem(papszTokens[0], papszTokens[1], "ISCE"); CSLDestroy( papszTokens ); } /* -------------------------------------------------------------------- */ /* Free papszXmlProps */ /* -------------------------------------------------------------------- */ CSLDestroy( papszXmlProps ); /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ poDS->SetDescription( poOpenInfo->pszFilename ); poDS->TryLoadXML(); /* -------------------------------------------------------------------- */ /* Check for overviews. */ /* -------------------------------------------------------------------- */ poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); return( poDS ); }
/** Apply a vertical shift grid to a source (DEM typically) dataset. * * hGridDataset will typically use WGS84 as horizontal datum (but this is * not a requirement) and its values are the values to add to go from geoid * elevations to WGS84 ellipsoidal heights. * * hGridDataset will be on-the-fly reprojected and resampled to the projection * and resolution of hSrcDataset, using bilinear resampling by default. * * Both hSrcDataset and hGridDataset must be single band datasets, and have * a valid geotransform and projection. * * On success, a reference will be taken on hSrcDataset and hGridDataset. * Reference counting semantics on the source and grid datasets should be * honoured. That is, don't just GDALClose() it, unless it was opened with * GDALOpenShared(), but rather use GDALReleaseDataset() if wanting to * immediately release the reference(s) and make the returned dataset the * owner of them. * * Valid use cases: * * \code * hSrcDataset = GDALOpen(...) * hGridDataset = GDALOpen(...) * hDstDataset = GDALApplyVerticalShiftGrid(hSrcDataset, hGridDataset, ...) * GDALReleaseDataset(hSrcDataset); * GDALReleaseDataset(hGridDataset); * if( hDstDataset ) * { * // Do things with hDstDataset * GDALClose(hDstDataset) // will close hSrcDataset and hGridDataset * } * \endcode * * @param hSrcDataset source (DEM) dataset. Must not be NULL. * @param hGridDataset vertical grid shift dataset. Must not be NULL. * @param bInverse if set to FALSE, hGridDataset values will be added to * hSrcDataset. If set to TRUE, they will be subtracted. * @param dfSrcUnitToMeter the factor to convert values from hSrcDataset to * meters (1.0 if source values are in meter). * @param dfDstUnitToMeter the factor to convert shifted values from meter * (1.0 if output values must be in meter). * @param papszOptions list of options, or NULL. Supported options are: * <ul> * <li>RESAMPLING=NEAREST/BILINEAR/CUBIC. Defaults to BILINEAR.</li> * <li>MAX_ERROR=val. Maximum error measured in input pixels that is allowed in * approximating the transformation (0.0 for exact calculations). Defaults * to 0.125</li> * <li>DATATYPE=Byte/UInt16/Int16/Float32/Float64. Output data type. If not * specified will be the same as the one of hSrcDataset. * <li>ERROR_ON_MISSING_VERT_SHIFT=YES/NO. Whether a missing/nodata value in * hGridDataset should cause I/O requests to fail. Default is NO (in which case * 0 will be used) * <li>SRC_SRS=srs_def. Override projection on hSrcDataset; * </ul> * * @return a new dataset corresponding to hSrcDataset adjusted with * hGridDataset, or NULL. If not NULL, it must be closed with GDALClose(). * * @since GDAL 2.2 */ GDALDatasetH GDALApplyVerticalShiftGrid( GDALDatasetH hSrcDataset, GDALDatasetH hGridDataset, int bInverse, double dfSrcUnitToMeter, double dfDstUnitToMeter, const char* const* papszOptions ) { VALIDATE_POINTER1( hSrcDataset, "GDALApplyVerticalShiftGrid", nullptr ); VALIDATE_POINTER1( hGridDataset, "GDALApplyVerticalShiftGrid", nullptr ); double adfSrcGT[6]; if( GDALGetGeoTransform(hSrcDataset, adfSrcGT) != CE_None ) { CPLError(CE_Failure, CPLE_NotSupported, "Source dataset has no geotransform."); return nullptr; } const char* pszSrcProjection = CSLFetchNameValueDef(papszOptions, "SRC_SRS", GDALGetProjectionRef(hSrcDataset)); if( pszSrcProjection == nullptr || pszSrcProjection[0] == '\0' ) { CPLError(CE_Failure, CPLE_NotSupported, "Source dataset has no projection."); return nullptr; } if( GDALGetRasterCount(hSrcDataset) != 1 ) { CPLError(CE_Failure, CPLE_NotSupported, "Only single band source dataset is supported."); return nullptr; } double adfGridGT[6]; if( GDALGetGeoTransform(hGridDataset, adfGridGT) != CE_None ) { CPLError(CE_Failure, CPLE_NotSupported, "Grid dataset has no geotransform."); return nullptr; } const char* pszGridProjection = GDALGetProjectionRef(hGridDataset); if( pszGridProjection == nullptr || pszGridProjection[0] == '\0' ) { CPLError(CE_Failure, CPLE_NotSupported, "Grid dataset has no projection."); return nullptr; } if( GDALGetRasterCount(hGridDataset) != 1 ) { CPLError(CE_Failure, CPLE_NotSupported, "Only single band grid dataset is supported."); return nullptr; } GDALDataType eDT = GDALGetRasterDataType(GDALGetRasterBand(hSrcDataset,1)); const char* pszDataType = CSLFetchNameValue(papszOptions, "DATATYPE"); if( pszDataType ) eDT = GDALGetDataTypeByName(pszDataType); if( eDT == GDT_Unknown ) { CPLError(CE_Failure, CPLE_NotSupported, "Invalid DATATYPE=%s", pszDataType); return nullptr; } const int nSrcXSize = GDALGetRasterXSize(hSrcDataset); const int nSrcYSize = GDALGetRasterYSize(hSrcDataset); OGRSpatialReference oSRS; CPLString osSrcProjection(pszSrcProjection); oSRS.SetFromUserInput(osSrcProjection); if( oSRS.IsCompound() ) { OGR_SRSNode* poNode = oSRS.GetRoot()->GetChild(1); if( poNode != nullptr ) { char* pszWKT = nullptr; poNode->exportToWkt(&pszWKT); osSrcProjection = pszWKT; CPLFree(pszWKT); } } void* hTransform = GDALCreateGenImgProjTransformer3( pszGridProjection, adfGridGT, osSrcProjection, adfSrcGT ); if( hTransform == nullptr ) return nullptr; GDALWarpOptions* psWO = GDALCreateWarpOptions(); psWO->hSrcDS = hGridDataset; psWO->eResampleAlg = GRA_Bilinear; const char* pszResampling = CSLFetchNameValue(papszOptions, "RESAMPLING"); if( pszResampling ) { if( EQUAL(pszResampling, "NEAREST") ) psWO->eResampleAlg = GRA_NearestNeighbour; else if( EQUAL(pszResampling, "BILINEAR") ) psWO->eResampleAlg = GRA_Bilinear; else if( EQUAL(pszResampling, "CUBIC") ) psWO->eResampleAlg = GRA_Cubic; } psWO->eWorkingDataType = GDT_Float32; int bHasNoData = FALSE; const double dfSrcNoData = GDALGetRasterNoDataValue( GDALGetRasterBand(hGridDataset, 1), &bHasNoData ); if( bHasNoData ) { psWO->padfSrcNoDataReal = static_cast<double*>(CPLMalloc(sizeof(double))); psWO->padfSrcNoDataReal[0] = dfSrcNoData; } psWO->padfDstNoDataReal = static_cast<double*>(CPLMalloc(sizeof(double))); const bool bErrorOnMissingShift = CPLFetchBool( papszOptions, "ERROR_ON_MISSING_VERT_SHIFT", false ); psWO->padfDstNoDataReal[0] = (bErrorOnMissingShift) ? -std::numeric_limits<float>::infinity() : 0.0; psWO->papszWarpOptions = CSLSetNameValue(psWO->papszWarpOptions, "INIT_DEST", "NO_DATA"); psWO->pfnTransformer = GDALGenImgProjTransform; psWO->pTransformerArg = hTransform; const double dfMaxError = CPLAtof(CSLFetchNameValueDef(papszOptions, "MAX_ERROR", "0.125")); if( dfMaxError > 0.0 ) { psWO->pTransformerArg = GDALCreateApproxTransformer( psWO->pfnTransformer, psWO->pTransformerArg, dfMaxError ); psWO->pfnTransformer = GDALApproxTransform; GDALApproxTransformerOwnsSubtransformer(psWO->pTransformerArg, TRUE); } psWO->nBandCount = 1; psWO->panSrcBands = static_cast<int *>(CPLMalloc(sizeof(int))); psWO->panSrcBands[0] = 1; psWO->panDstBands = static_cast<int *>(CPLMalloc(sizeof(int))); psWO->panDstBands[0] = 1; VRTWarpedDataset* poReprojectedGrid = new VRTWarpedDataset(nSrcXSize, nSrcYSize); // This takes a reference on hGridDataset CPLErr eErr = poReprojectedGrid->Initialize(psWO); CPLAssert(eErr == CE_None); CPL_IGNORE_RET_VAL(eErr); GDALDestroyWarpOptions(psWO); poReprojectedGrid->SetGeoTransform(adfSrcGT); poReprojectedGrid->AddBand(GDT_Float32, nullptr); GDALApplyVSGDataset* poOutDS = new GDALApplyVSGDataset( reinterpret_cast<GDALDataset*>(hSrcDataset), poReprojectedGrid, eDT, CPL_TO_BOOL(bInverse), dfSrcUnitToMeter, dfDstUnitToMeter, // Undocumented option. For testing only atoi(CSLFetchNameValueDef(papszOptions, "BLOCKSIZE", "256")) ); poReprojectedGrid->ReleaseRef(); if( !poOutDS->IsInitOK() ) { delete poOutDS; return nullptr; } poOutDS->SetDescription( GDALGetDescription( hSrcDataset ) ); return reinterpret_cast<GDALDatasetH>(poOutDS); }