CPLErr GDALWMSRasterBand::ZeroBlock(int x, int y, int to_buffer_band, void *buffer) { CPLErr ret = CE_None; for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) { if (ret == CE_None) { void *p = NULL; GDALRasterBlock *b = NULL; if ((buffer != NULL) && (ib == to_buffer_band)) { p = buffer; } else { GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib)); if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview)); if (!band->IsBlockInCache(x, y)) { b = band->GetLockedBlockRef(x, y, true); if (b != NULL) { p = b->GetDataRef(); if (p == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: GetDataRef returned NULL."); ret = CE_Failure; } } } } if (p != NULL) { unsigned char *b = reinterpret_cast<unsigned char *>(p); int block_size = nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType) / 8); for (int i = 0; i < block_size; ++i) b[i] = 0; } if (b != NULL) { b->DropLock(); } } } return ret; }
CPLErr GDALWMSRasterBand::ReadBlocks(int x, int y, void *buffer, int bx0, int by0, int bx1, int by1, int advise_read) { CPLErr ret = CE_None; int i; int max_request_count = (bx1 - bx0 + 1) * (by1 - by0 + 1); int request_count = 0; CPLHTTPRequest *download_requests = NULL; GDALWMSCache *cache = m_parent_dataset->m_cache; struct BlockXY { int x, y; } *download_blocks = NULL; if (!m_parent_dataset->m_offline_mode) { download_requests = new CPLHTTPRequest[max_request_count]; download_blocks = new BlockXY[max_request_count]; } char **http_request_opts = NULL; if (m_parent_dataset->m_http_timeout != -1) { CPLString http_request_optstr; http_request_optstr.Printf("TIMEOUT=%d", m_parent_dataset->m_http_timeout); http_request_opts = CSLAddString(http_request_opts, http_request_optstr.c_str()); } for (int iy = by0; iy <= by1; ++iy) { for (int ix = bx0; ix <= bx1; ++ix) { bool need_this_block = false; if (!advise_read) { for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) { if ((ix == x) && (iy == y) && (ib == nBand)) { need_this_block = true; } else { GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib)); if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview)); if (!band->IsBlockInCache(ix, iy)) need_this_block = true; } } } else { need_this_block = true; } CPLString url; if (need_this_block) { CPLString file_name; AskMiniDriverForBlock(&url, ix, iy); if ((cache != NULL) && (cache->Read(url.c_str(), &file_name) == CE_None)) { if (advise_read) { need_this_block = false; } else { void *p = 0; if ((ix == x) && (iy == y)) p = buffer; if (ReadBlockFromFile(ix, iy, file_name.c_str(), nBand, p, 0) == CE_None) need_this_block = false; } } } if (need_this_block) { if (m_parent_dataset->m_offline_mode) { if (!advise_read) { void *p = 0; if ((ix == x) && (iy == y)) p = buffer; if (ZeroBlock(ix, iy, nBand, p) != CE_None) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ZeroBlock failed."); ret = CE_Failure; } } } else { CPLHTTPInitializeRequest(&download_requests[request_count], url.c_str(), http_request_opts); download_blocks[request_count].x = ix; download_blocks[request_count].y = iy; ++request_count; } } } } if (http_request_opts != NULL) { CSLDestroy(http_request_opts); } if (request_count > 0) { char **opts = NULL; CPLString optstr; if (m_parent_dataset->m_http_max_conn != -1) { optstr.Printf("MAXCONN=%d", m_parent_dataset->m_http_max_conn); opts = CSLAddString(opts, optstr.c_str()); } if (CPLHTTPFetchMulti(download_requests, request_count, opts) != CE_None) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: CPLHTTPFetchMulti failed."); ret = CE_Failure; } if (opts != NULL) { CSLDestroy(opts); } } for (i = 0; i < request_count; ++i) { if (ret == CE_None) { if ((download_requests[i].nStatus == 200) && (download_requests[i].pabyData != NULL) && (download_requests[i].nDataLen > 0)) { CPLString file_name(BufferToVSIFile(download_requests[i].pabyData, download_requests[i].nDataLen)); if (file_name.size() > 0) { /* check for error xml */ if (download_requests[i].nDataLen >= 20) { const char *download_data = reinterpret_cast<char *>(download_requests[i].pabyData); if (EQUALN(download_data, "<?xml ", 6) || EQUALN(download_data, "<!DOCTYPE ", 10) || EQUALN(download_data, "<ServiceException", 17)) { if (ReportWMSException(file_name.c_str()) != CE_None) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned unknown exception."); } ret = CE_Failure; } } if (ret == CE_None) { if (advise_read && !m_parent_dataset->m_verify_advise_read) { if (cache != NULL) { cache->Write(download_requests[i].pszURL, file_name); } } else { void *p = 0; if ((download_blocks[i].x == x) && (download_blocks[i].y == y)) p = buffer; if (ReadBlockFromFile(download_blocks[i].x, download_blocks[i].y, file_name.c_str(), nBand, p, advise_read) == CE_None) { if (cache != NULL) { cache->Write(download_requests[i].pszURL, file_name); } } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ReadBlockFromFile (%s) failed.", download_requests[i].pszURL); ret = CE_Failure; } } } VSIUnlink(file_name.c_str()); } } else if (download_requests[i].nStatus == 204) { if (!advise_read) { void *p = 0; if ((download_blocks[i].x == x) && (download_blocks[i].y == y)) p = buffer; if (ZeroBlock(download_blocks[i].x, download_blocks[i].y, nBand, p) != CE_None) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ZeroBlock failed."); ret = CE_Failure; } } } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Unable to download block %d, %d.\n URL: %s\n HTTP status code: %d, error: %s.", download_blocks[i].x, download_blocks[i].y, download_requests[i].pszURL, download_requests[i].nStatus, download_requests[i].pszError ? download_requests[i].pszError : "(null)"); ret = CE_Failure; } } CPLHTTPCleanupRequest(&download_requests[i]); } if (!m_parent_dataset->m_offline_mode) { delete[] download_blocks; delete[] download_requests; } return ret; }
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 GDALWMSRasterBand::ReadBlockFromFile(int x, int y, const char *file_name, int to_buffer_band, void *buffer, int advise_read) { CPLErr ret = CE_None; GDALDataset *ds = 0; GByte *color_table = NULL; int i; //CPLDebug("WMS", "ReadBlockFromFile: to_buffer_band=%d, (x,y)=(%d, %d)", to_buffer_band, x, y); /* expected size */ const int esx = MIN(MAX(0, (x + 1) * nBlockXSize), nRasterXSize) - MIN(MAX(0, x * nBlockXSize), nRasterXSize); const int esy = MIN(MAX(0, (y + 1) * nBlockYSize), nRasterYSize) - MIN(MAX(0, y * nBlockYSize), nRasterYSize); ds = reinterpret_cast<GDALDataset*>(GDALOpen(file_name, GA_ReadOnly)); if (ds != NULL) { int sx = ds->GetRasterXSize(); int sy = ds->GetRasterYSize(); bool accepted_as_no_alpha = false; // if the request is for 4 bands but the wms returns 3 /* Allow bigger than expected so pre-tiled constant size images work on corners */ if ((sx > nBlockXSize) || (sy > nBlockYSize) || (sx < esx) || (sy < esy)) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect size %d x %d of downloaded block, expected %d x %d, max %d x %d.", sx, sy, esx, esy, nBlockXSize, nBlockYSize); ret = CE_Failure; } if (ret == CE_None) { int nDSRasterCount = ds->GetRasterCount(); if (nDSRasterCount != m_parent_dataset->nBands) { /* Maybe its an image with color table */ bool accepted_as_ct = false; if ((eDataType == GDT_Byte) && (ds->GetRasterCount() == 1)) { GDALRasterBand *rb = ds->GetRasterBand(1); if (rb->GetRasterDataType() == GDT_Byte) { GDALColorTable *ct = rb->GetColorTable(); if (ct != NULL) { accepted_as_ct = true; if (!advise_read) { color_table = new GByte[256 * 4]; const int count = MIN(256, ct->GetColorEntryCount()); for (i = 0; i < count; ++i) { GDALColorEntry ce; ct->GetColorEntryAsRGB(i, &ce); color_table[i] = static_cast<GByte>(ce.c1); color_table[i + 256] = static_cast<GByte>(ce.c2); color_table[i + 512] = static_cast<GByte>(ce.c3); color_table[i + 768] = static_cast<GByte>(ce.c4); } for (i = count; i < 256; ++i) { color_table[i] = 0; color_table[i + 256] = 0; color_table[i + 512] = 0; color_table[i + 768] = 0; } } } } } if (nDSRasterCount == 4 && m_parent_dataset->nBands == 3) { /* metacarta TMS service sometimes return a 4 band PNG instead of the expected 3 band... */ } else if (!accepted_as_ct) { if (ds->GetRasterCount()==3 && m_parent_dataset->nBands == 4 && (eDataType == GDT_Byte)) { // WMS returned a file with no alpha so we will fill the alpha band with "opaque" accepted_as_no_alpha = true; } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect bands count %d in downloaded block, expected %d.", nDSRasterCount, m_parent_dataset->nBands); ret = CE_Failure; } } } } if (!advise_read) { for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) { if (ret == CE_None) { void *p = NULL; GDALRasterBlock *b = NULL; if ((buffer != NULL) && (ib == to_buffer_band)) { p = buffer; } else { GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib)); if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview)); if (!band->IsBlockInCache(x, y)) { b = band->GetLockedBlockRef(x, y, true); if (b != NULL) { p = b->GetDataRef(); if (p == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: GetDataRef returned NULL."); ret = CE_Failure; } } } else { //CPLDebug("WMS", "Band %d, block (x,y)=(%d, %d) already in cache", band->GetBand(), x, y); } } if (p != NULL) { int pixel_space = GDALGetDataTypeSize(eDataType) / 8; int line_space = pixel_space * nBlockXSize; if (color_table == NULL) { if( ib <= ds->GetRasterCount()) { if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, eDataType, 1, &ib, pixel_space, line_space, 0) != CE_None) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: RasterIO failed on downloaded block."); ret = CE_Failure; } } else { // parent expects 4 bands but file only has 3 so generate a all "opaque" 4th band if (accepted_as_no_alpha) { // the file had 3 bands and we are reading band 4 (Alpha) so fill with 255 (no alpha) GByte *byte_buffer = reinterpret_cast<GByte *>(p); for (int y = 0; y < sy; ++y) { for (int x = 0; x < sx; ++x) { const int offset = x + y * line_space; byte_buffer[offset] = 255; // fill with opaque } } } else { // we should never get here because this case was caught above CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect bands count %d in downloaded block, expected %d.", ds->GetRasterCount(), m_parent_dataset->nBands); ret = CE_Failure; } } } else if (ib <= 4) { if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, eDataType, 1, NULL, pixel_space, line_space, 0) != CE_None) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: RasterIO failed on downloaded block."); ret = CE_Failure; } if (ret == CE_None) { GByte *band_color_table = color_table + 256 * (ib - 1); GByte *byte_buffer = reinterpret_cast<GByte *>(p); for (int y = 0; y < sy; ++y) { for (int x = 0; x < sx; ++x) { const int offset = x + y * line_space; byte_buffer[offset] = band_color_table[byte_buffer[offset]]; } } } } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Color table supports at most 4 components."); ret = CE_Failure; } } if (b != NULL) { b->DropLock(); } } } } GDALClose(ds); } else { CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Unable to open downloaded block."); ret = CE_Failure; } if (color_table != NULL) { delete[] color_table; } 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; }