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 *paby = reinterpret_cast<unsigned char *>(p); int block_size = nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType) / 8); for (int i = 0; i < block_size; ++i) paby[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 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; }