CPLErr GDALWMSMiniDriver_VirtualEarth::Initialize(CPLXMLNode *config)
{
    CPLErr ret = CE_None;

    if (ret == CE_None) {
        const char *base_url = CPLGetXMLValue(config, "ServerURL", "");
        if (base_url[0] != '\0') {
            m_base_url = base_url;
            if (m_base_url.find("${quadkey}") == std::string::npos) {
                CPLError(CE_Failure, CPLE_AppDefined,
                         "GDALWMS, VirtualEarth mini-driver: ${quadkey} missing in ServerURL.");
                ret = CE_Failure;
            }
        } else {
            CPLError(CE_Failure, CPLE_AppDefined,
                     "GDALWMS, VirtualEarth mini-driver: ServerURL missing.");
            ret = CE_Failure;
        }
    }

    m_parent_dataset->WMSSetDefaultBlockSize(256, 256);
    m_parent_dataset->WMSSetDefaultDataWindowCoordinates(-20037508.34,20037508.34,20037508.34,-20037508.34);
    m_parent_dataset->WMSSetDefaultTileLevel(19);
    m_parent_dataset->WMSSetDefaultOverviewCount(18);
    m_parent_dataset->WMSSetNeedsDataWindow(FALSE);

    m_projection_wkt=ProjToWKT("EPSG:900913");

    return ret;
}
示例#2
0
CPLErr WMSMiniDriver_AGS::Initialize(CPLXMLNode *config, CPL_UNUSED char **papszOpenOptions)
{
    // Bounding box, if specified, has to be xyXY.
    m_bbox_order = CPLGetXMLValue(config, "BBoxOrder", "xyXY");
    if (m_bbox_order.size() < 4 || m_bbox_order.find("xyXY") != 0) {
        CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ArcGIS BBoxOrder value has to be xyXY");
        return CE_Failure;
    }

    m_base_url = CPLGetXMLValue(config, "ServerURL", CPLGetXMLValue(config, "ServerUrl", ""));
    if (m_base_url.empty()) {
        CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ArcGIS Server mini-driver: ServerURL missing.");
        return CE_Failure;
    }

    m_image_format = CPLGetXMLValue(config, "ImageFormat", "png");
    m_time_range = CPLGetXMLValue(config, "TimeRange", "");
    m_transparent = CPLGetXMLValue(config, "Transparent", "");
    m_transparent.tolower();
    m_layers = CPLGetXMLValue(config, "Layers", "");

    const char* irs = CPLGetXMLValue(config, "SRS", "102100");

    if( irs != nullptr )
    {
        if( STARTS_WITH_CI(irs, "EPSG:") ) // If we have EPSG code just convert it to WKT.
        {
            m_projection_wkt = ProjToWKT(irs);
            m_irs = irs + 5;
        }
        else // If we have AGS code - try if it's EPSG.
        {
            m_irs = irs;
            m_projection_wkt = ProjToWKT("EPSG:" + m_irs);
        }
        // TODO: If we have AGS JSON.
    }
    m_identification_tolerance = CPLGetXMLValue(config, "IdentificationTolerance", "2");

    return CE_None;
}
CPLErr GDALWMSMiniDriver_WorldWind::Initialize(CPLXMLNode *config) {
    CPLErr ret = CE_None;

    if (ret == CE_None) {
        const char *base_url = CPLGetXMLValue(config, "ServerURL", "");
        if (base_url[0] != '\0') {
            /* Try the old name */
            base_url = CPLGetXMLValue(config, "ServerUrl", "");
        }
        if (base_url[0] != '\0') {
            m_base_url = base_url;
        } else {
            CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WorldWind mini-driver: ServerURL missing.");
            ret = CE_Failure;
        }
    }

    m_dataset = CPLGetXMLValue(config, "Layer", "");
    m_projection_wkt = ProjToWKT("EPSG:4326");

    return ret;
}
CPLErr GDALWMSMiniDriver_AGS::Initialize(CPLXMLNode *config)
{
	CPLErr ret = CE_None;
	int i;

    if (ret == CE_None) 
    {
        const char *base_url = CPLGetXMLValue(config, "ServerURL", "");
        if (base_url[0] != '\0') 
        {
            /* Try the old name */
            base_url = CPLGetXMLValue(config, "ServerUrl", "");
        }
        
        if (base_url[0] != '\0') 
        {
            m_base_url = base_url;
        }
        else 
        {
            CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, ArcGIS Server mini-driver: ServerURL missing.");
            ret = CE_Failure;
        }
    }

	if (ret == CE_None) 
	{
        m_image_format = CPLGetXMLValue(config, "ImageFormat", "png");
        m_transparent = CPLGetXMLValue(config, "Transparent","");
		// the transparent flag needs to be "true" or "false" 
		// in lower case according to the ArcGIS Server REST API
        for(i = 0; i < (int)m_transparent.size(); i++)
        {
			m_transparent[i] = (char) tolower(m_transparent[i]);
        }
        
		m_layers = CPLGetXMLValue(config, "Layers", "");
    }
    
	if (ret == CE_None) 
	{
		const char* irs = CPLGetXMLValue(config, "SRS", "102100");
		
		if (irs != NULL)
		{
	        if(EQUALN(irs, "EPSG:", 5)) //if we have EPSG code just convert it to WKT
	        {
	            m_projection_wkt = ProjToWKT(irs);
	            m_irs = irs + 5;
	        }
	        else //if we have AGS code - try if it's EPSG
		    {
		        m_irs = irs;
		        m_projection_wkt = ProjToWKT("EPSG:" + m_irs);
		    }
		    // TODO: if we have AGS JSON    
		}
		m_identification_tolerance = CPLGetXMLValue(config, "IdentificationTolerance", "2");
	}

	if (ret == CE_None)
	{
        const char *bbox_order = CPLGetXMLValue(config, "BBoxOrder", "xyXY");
        if (bbox_order[0] != '\0') 
        {
            for (i = 0; i < 4; ++i) 
            {
                if ((bbox_order[i] != 'x') && (bbox_order[i] != 'y') && 
                    (bbox_order[i] != 'X') && (bbox_order[i] != 'Y')) 
                    break;
            }
            
            if (i == 4) 
            {
                m_bbox_order = bbox_order;
            } 
            else 
            {
                CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, ArcGIS Server mini-driver: Incorrect BBoxOrder.");
                ret = CE_Failure;
            }
        } 
        else
        {
            CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, ArcGIS Server mini-driver: BBoxOrder missing.");
            ret = CE_Failure;
        }
    }
	
    return ret;
}
示例#5
0
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_WMS::Initialize(CPLXMLNode *config) {
    CPLErr ret = CE_None;

    if (ret == CE_None) {
        const char *version = CPLGetXMLValue(config, "Version", "1.1.0");
        if (version[0] != '\0') {
            m_version = version;
            m_iversion = VersionStringToInt(version);
            if (m_iversion == -1) {
                CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: Invalid version.");
                ret = CE_Failure;
            }
        } else {
            CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: Version missing.");
            ret = CE_Failure;
        }
    }

    if (ret == CE_None) {
        const char *base_url = CPLGetXMLValue(config, "ServerURL", "");
        if (base_url[0] != '\0') {
            /* Try the old name */
            base_url = CPLGetXMLValue(config, "ServerUrl", "");
        }
        if (base_url[0] != '\0') {
            m_base_url = base_url;
        } else {
            CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: ServerURL missing.");
            ret = CE_Failure;
        }
    }

    if (ret == CE_None) {
/* SRS is WMS version 1.1 and earlier, if SRS is not set use default unless CRS is set
   CRS is WMS version 1.3, if CRS is not set use default unless SRS is set */
        const char *crs = CPLGetXMLValue(config, "CRS", "");
        const char *srs = CPLGetXMLValue(config, "SRS", "");
        if (m_iversion >= VersionStringToInt("1.3")) {
            /* Version 1.3 and above */
            if ((srs[0] != '\0') && (crs[0] == '\0')) {
                CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: WMS version 1.3 and above expects CRS however SRS was set instead.");
                ret = CE_Failure;
            } else if (crs[0] != '\0') {
                m_crs = crs;
            } else {
                m_crs = "EPSG:4326";
            }
        } else {
            /* Version 1.1.1 and below */
            if ((srs[0] == '\0') && (crs[0] != '\0')) {
                CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: WMS version 1.1.1 and below expects SRS however CRS was set instead.");
                ret = CE_Failure;
            } else if (srs[0] != '\0') {
                m_srs = srs;
            } else {
                m_srs = "EPSG:4326";
            }
        }
    }

    if (ret == CE_None) {
        if (m_srs.size()) {
            m_projection_wkt = ProjToWKT(m_srs);
        } else if (m_crs.size()) {
            m_projection_wkt = ProjToWKT(m_crs);
        }
    }

    if (ret == CE_None) {
        m_image_format = CPLGetXMLValue(config, "ImageFormat", "image/jpeg");
        m_layers = CPLGetXMLValue(config, "Layers", "");
        m_styles = CPLGetXMLValue(config, "Styles", "");
        m_transparent = CPLGetXMLValue(config, "Transparent","");
        // the transparent flag needs to be "TRUE" or "FALSE" in upper case according to the WMS spec so force upper case
        int i=0; 
        while (m_transparent[i] != '\0')
        {
            m_transparent[i] = toupper(m_transparent[i]);
            i ++;
        }
    }

    if (ret == CE_None) {
        const char *bbox_order = CPLGetXMLValue(config, "BBoxOrder", "xyXY");
        if (bbox_order[0] != '\0') {
            int i;
            for (i = 0; i < 4; ++i) {
                if ((bbox_order[i] != 'x') && (bbox_order[i] != 'y') && (bbox_order[i] != 'X') && (bbox_order[i] != 'Y')) break;
            }
            if (i == 4) {
                m_bbox_order = bbox_order;
            } else {
                CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: Incorrect BBoxOrder.");
                ret = CE_Failure;
            }
        } else {
            CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, WMS mini-driver: BBoxOrder missing.");
            ret = CE_Failure;
        }
    }

    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;
}
示例#8
0
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;
}