1 : /******************************************************************************
2 : * $Id: rasterband.cpp 23192 2011-10-06 20:31:54Z rouault $
3 : *
4 : * Project: WMS Client Driver
5 : * Purpose: Implementation of Dataset and RasterBand classes for WMS
6 : * and other similar services.
7 : * Author: Adam Nowacki, nowak@xpam.de
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2007, Adam Nowacki
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "stdinc.h"
32 :
33 440 : GDALWMSRasterBand::GDALWMSRasterBand(GDALWMSDataset *parent_dataset, int band, double scale) {
34 : // printf("[%p] GDALWMSRasterBand::GDALWMSRasterBand(%p, %d, %f)\n", this, parent_dataset, band, scale);
35 440 : m_parent_dataset = parent_dataset;
36 440 : m_scale = scale;
37 440 : m_overview = -1;
38 440 : m_color_interp = GCI_Undefined;
39 :
40 440 : poDS = parent_dataset;
41 440 : nRasterXSize = static_cast<int>(m_parent_dataset->m_data_window.m_sx * scale + 0.5);
42 440 : nRasterYSize = static_cast<int>(m_parent_dataset->m_data_window.m_sy * scale + 0.5);
43 440 : nBand = band;
44 440 : eDataType = m_parent_dataset->m_data_type;
45 440 : nBlockXSize = m_parent_dataset->m_block_size_x;
46 440 : nBlockYSize = m_parent_dataset->m_block_size_y;
47 440 : }
48 :
49 440 : GDALWMSRasterBand::~GDALWMSRasterBand() {
50 855 : for (std::vector<GDALWMSRasterBand *>::iterator it = m_overviews.begin(); it != m_overviews.end(); ++it) {
51 415 : GDALWMSRasterBand *p = *it;
52 415 : delete p;
53 : }
54 440 : }
55 :
56 2 : CPLErr GDALWMSRasterBand::ReadBlocks(int x, int y, void *buffer, int bx0, int by0, int bx1, int by1, int advise_read) {
57 2 : CPLErr ret = CE_None;
58 : int i;
59 :
60 2 : int max_request_count = (bx1 - bx0 + 1) * (by1 - by0 + 1);
61 2 : int request_count = 0;
62 2 : CPLHTTPRequest *download_requests = NULL;
63 2 : GDALWMSCache *cache = m_parent_dataset->m_cache;
64 : struct BlockXY {
65 : int x, y;
66 2 : } *download_blocks = NULL;
67 2 : if (!m_parent_dataset->m_offline_mode) {
68 2 : download_requests = new CPLHTTPRequest[max_request_count];
69 2 : download_blocks = new BlockXY[max_request_count];
70 : }
71 :
72 2 : char **http_request_opts = NULL;
73 2 : if (m_parent_dataset->m_http_timeout != -1) {
74 2 : CPLString http_request_optstr;
75 2 : http_request_optstr.Printf("TIMEOUT=%d", m_parent_dataset->m_http_timeout);
76 2 : http_request_opts = CSLAddString(http_request_opts, http_request_optstr.c_str());
77 : }
78 :
79 2 : if (m_parent_dataset->m_osUserAgent.size() != 0)
80 : {
81 0 : CPLString osUserAgentOptStr("USERAGENT=");
82 0 : osUserAgentOptStr += m_parent_dataset->m_osUserAgent;
83 0 : http_request_opts = CSLAddString(http_request_opts, osUserAgentOptStr.c_str());
84 : }
85 2 : if (m_parent_dataset->m_osReferer.size() != 0)
86 : {
87 0 : CPLString osRefererOptStr("REFERER=");
88 0 : osRefererOptStr += m_parent_dataset->m_osReferer;
89 0 : http_request_opts = CSLAddString(http_request_opts, osRefererOptStr.c_str());
90 : }
91 2 : if (m_parent_dataset->m_unsafeSsl >= 1) {
92 0 : http_request_opts = CSLAddString(http_request_opts, "UNSAFESSL=1");
93 : }
94 :
95 4 : for (int iy = by0; iy <= by1; ++iy) {
96 5 : for (int ix = bx0; ix <= bx1; ++ix) {
97 3 : bool need_this_block = false;
98 3 : if (!advise_read) {
99 8 : for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) {
100 7 : if ((ix == x) && (iy == y) && (ib == nBand)) {
101 2 : need_this_block = true;
102 : } else {
103 3 : GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib));
104 3 : if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview));
105 3 : if (!band->IsBlockInCache(ix, iy)) need_this_block = true;
106 : }
107 : }
108 : } else {
109 0 : need_this_block = true;
110 : }
111 3 : CPLString url;
112 3 : if (need_this_block) {
113 3 : CPLString file_name;
114 3 : AskMiniDriverForBlock(&url, ix, iy);
115 3 : if ((cache != NULL) && (cache->Read(url.c_str(), &file_name) == CE_None)) {
116 0 : if (advise_read) {
117 0 : need_this_block = false;
118 : } else {
119 0 : void *p = 0;
120 0 : if ((ix == x) && (iy == y)) p = buffer;
121 0 : if (ReadBlockFromFile(ix, iy, file_name.c_str(), nBand, p, 0) == CE_None) need_this_block = false;
122 : }
123 3 : }
124 : }
125 3 : if (need_this_block) {
126 3 : if (m_parent_dataset->m_offline_mode) {
127 0 : if (!advise_read) {
128 0 : void *p = 0;
129 0 : if ((ix == x) && (iy == y)) p = buffer;
130 0 : if (ZeroBlock(ix, iy, nBand, p) != CE_None) {
131 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ZeroBlock failed.");
132 0 : ret = CE_Failure;
133 : }
134 : }
135 : } else {
136 3 : CPLHTTPInitializeRequest(&download_requests[request_count], url.c_str(), http_request_opts);
137 3 : download_blocks[request_count].x = ix;
138 3 : download_blocks[request_count].y = iy;
139 3 : ++request_count;
140 : }
141 : }
142 : }
143 : }
144 2 : if (http_request_opts != NULL) {
145 2 : CSLDestroy(http_request_opts);
146 : }
147 :
148 2 : if (request_count > 0) {
149 2 : char **opts = NULL;
150 2 : CPLString optstr;
151 2 : if (m_parent_dataset->m_http_max_conn != -1) {
152 2 : optstr.Printf("MAXCONN=%d", m_parent_dataset->m_http_max_conn);
153 2 : opts = CSLAddString(opts, optstr.c_str());
154 : }
155 2 : if (CPLHTTPFetchMulti(download_requests, request_count, opts) != CE_None) {
156 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: CPLHTTPFetchMulti failed.");
157 0 : ret = CE_Failure;
158 : }
159 2 : if (opts != NULL) {
160 2 : CSLDestroy(opts);
161 2 : }
162 : }
163 :
164 5 : for (i = 0; i < request_count; ++i) {
165 3 : if (ret == CE_None) {
166 6 : if ((download_requests[i].nStatus == 200) && (download_requests[i].pabyData != NULL) && (download_requests[i].nDataLen > 0)) {
167 3 : CPLString file_name(BufferToVSIFile(download_requests[i].pabyData, download_requests[i].nDataLen));
168 3 : if (file_name.size() > 0) {
169 3 : bool wms_exception = false;
170 : /* check for error xml */
171 3 : if (download_requests[i].nDataLen >= 20) {
172 3 : const char *download_data = reinterpret_cast<char *>(download_requests[i].pabyData);
173 3 : if (EQUALN(download_data, "<?xml ", 6)
174 : || EQUALN(download_data, "<!DOCTYPE ", 10)
175 : || EQUALN(download_data, "<ServiceException", 17)) {
176 0 : if (ReportWMSException(file_name.c_str()) != CE_None) {
177 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned unknown exception.");
178 : }
179 0 : wms_exception = true;
180 0 : ret = CE_Failure;
181 : }
182 : }
183 3 : if (ret == CE_None) {
184 3 : if (advise_read && !m_parent_dataset->m_verify_advise_read) {
185 0 : if (cache != NULL) {
186 0 : cache->Write(download_requests[i].pszURL, file_name);
187 : }
188 : } else {
189 3 : void *p = 0;
190 3 : if ((download_blocks[i].x == x) && (download_blocks[i].y == y)) p = buffer;
191 3 : if (ReadBlockFromFile(download_blocks[i].x, download_blocks[i].y, file_name.c_str(), nBand, p, advise_read) == CE_None) {
192 3 : if (cache != NULL) {
193 0 : cache->Write(download_requests[i].pszURL, file_name);
194 : }
195 : } else {
196 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ReadBlockFromFile (%s) failed.",
197 0 : download_requests[i].pszURL);
198 0 : ret = CE_Failure;
199 : }
200 : }
201 0 : } else if( wms_exception && m_parent_dataset->m_zeroblock_on_serverexceptions ) {
202 0 : void *p = 0;
203 0 : if ((download_blocks[i].x == x) && (download_blocks[i].y == y)) p = buffer;
204 0 : if (ZeroBlock(download_blocks[i].x, download_blocks[i].y, nBand, p) != CE_None) {
205 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ZeroBlock failed.");
206 : } else {
207 0 : ret = CE_None;
208 : }
209 :
210 : }
211 3 : VSIUnlink(file_name.c_str());
212 3 : }
213 : } else {
214 : std::vector<int>::iterator zero_it = std::find(
215 : m_parent_dataset->m_http_zeroblock_codes.begin(),
216 : m_parent_dataset->m_http_zeroblock_codes.end(),
217 0 : download_requests[i].nStatus);
218 0 : if ( zero_it != m_parent_dataset->m_http_zeroblock_codes.end() ) {
219 0 : if (!advise_read) {
220 0 : void *p = 0;
221 0 : if ((download_blocks[i].x == x) && (download_blocks[i].y == y)) p = buffer;
222 0 : if (ZeroBlock(download_blocks[i].x, download_blocks[i].y, nBand, p) != CE_None) {
223 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ZeroBlock failed.");
224 0 : ret = CE_Failure;
225 : }
226 : }
227 : } else {
228 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Unable to download block %d, %d.\n URL: %s\n HTTP status code: %d, error: %s.",
229 0 : download_blocks[i].x, download_blocks[i].y, download_requests[i].pszURL, download_requests[i].nStatus,
230 0 : download_requests[i].pszError ? download_requests[i].pszError : "(null)");
231 0 : ret = CE_Failure;
232 : }
233 : }
234 : }
235 3 : CPLHTTPCleanupRequest(&download_requests[i]);
236 : }
237 2 : if (!m_parent_dataset->m_offline_mode) {
238 2 : delete[] download_blocks;
239 2 : delete[] download_requests;
240 : }
241 :
242 2 : return ret;
243 : }
244 :
245 2 : CPLErr GDALWMSRasterBand::IReadBlock(int x, int y, void *buffer) {
246 2 : int bx0 = x;
247 2 : int by0 = y;
248 2 : int bx1 = x;
249 2 : int by1 = y;
250 :
251 2 : if ((m_parent_dataset->m_hint.m_valid) && (m_parent_dataset->m_hint.m_overview == m_overview)) {
252 2 : int tbx0 = m_parent_dataset->m_hint.m_x0 / nBlockXSize;
253 2 : int tby0 = m_parent_dataset->m_hint.m_y0 / nBlockYSize;
254 2 : int tbx1 = (m_parent_dataset->m_hint.m_x0 + m_parent_dataset->m_hint.m_sx - 1) / nBlockXSize;
255 2 : int tby1 = (m_parent_dataset->m_hint.m_y0 + m_parent_dataset->m_hint.m_sy - 1) / nBlockYSize;
256 2 : if ((tbx0 <= bx0) && (tby0 <= by0) && (tbx1 >= bx1) && (tby1 >= by1)) {
257 2 : bx0 = tbx0;
258 2 : by0 = tby0;
259 2 : bx1 = tbx1;
260 2 : by1 = tby1;
261 : }
262 : }
263 :
264 2 : CPLErr eErr = ReadBlocks(x, y, buffer, bx0, by0, bx1, by1, 0);
265 :
266 2 : if ((m_parent_dataset->m_hint.m_valid) && (m_parent_dataset->m_hint.m_overview == m_overview))
267 : {
268 2 : m_parent_dataset->m_hint.m_valid = false;
269 : }
270 :
271 2 : return eErr;
272 : }
273 :
274 217 : CPLErr GDALWMSRasterBand::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy, void *buffer, int bsx, int bsy, GDALDataType bdt, int pixel_space, int line_space) {
275 : CPLErr ret;
276 :
277 217 : if (rw != GF_Read) return CE_Failure;
278 217 : if (buffer == NULL) return CE_Failure;
279 217 : if ((sx == 0) || (sy == 0) || (bsx == 0) || (bsy == 0)) return CE_None;
280 :
281 217 : m_parent_dataset->m_hint.m_x0 = x0;
282 217 : m_parent_dataset->m_hint.m_y0 = y0;
283 217 : m_parent_dataset->m_hint.m_sx = sx;
284 217 : m_parent_dataset->m_hint.m_sy = sy;
285 217 : m_parent_dataset->m_hint.m_overview = m_overview;
286 217 : m_parent_dataset->m_hint.m_valid = true;
287 217 : ret = GDALRasterBand::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt, pixel_space, line_space);
288 217 : m_parent_dataset->m_hint.m_valid = false;
289 :
290 217 : return ret;
291 : }
292 :
293 0 : int GDALWMSRasterBand::HasArbitraryOverviews() {
294 : // return m_parent_dataset->m_mini_driver_caps.m_has_arb_overviews;
295 0 : return 0; // not implemented yet
296 : }
297 :
298 8 : int GDALWMSRasterBand::GetOverviewCount() {
299 8 : return m_overviews.size();
300 : }
301 :
302 70 : GDALRasterBand *GDALWMSRasterBand::GetOverview(int n) {
303 70 : if ((m_overviews.size() > 0) && (static_cast<size_t>(n) < m_overviews.size())) return m_overviews[n];
304 0 : else return NULL;
305 : }
306 :
307 415 : void GDALWMSRasterBand::AddOverview(double scale) {
308 415 : GDALWMSRasterBand *overview = new GDALWMSRasterBand(m_parent_dataset, nBand, scale);
309 415 : std::vector<GDALWMSRasterBand *>::iterator it = m_overviews.begin();
310 3808 : for (; it != m_overviews.end(); ++it) {
311 3393 : GDALWMSRasterBand *p = *it;
312 3393 : if (p->m_scale < scale) break;
313 : }
314 415 : m_overviews.insert(it, overview);
315 415 : it = m_overviews.begin();
316 4223 : for (int i = 0; it != m_overviews.end(); ++it, ++i) {
317 3808 : GDALWMSRasterBand *p = *it;
318 3808 : p->m_overview = i;
319 : }
320 415 : }
321 :
322 6 : bool GDALWMSRasterBand::IsBlockInCache(int x, int y) {
323 6 : bool ret = false;
324 6 : GDALRasterBlock *b = TryGetLockedBlockRef(x, y);
325 6 : if (b != NULL) {
326 0 : ret = true;
327 0 : b->DropLock();
328 : }
329 6 : return ret;
330 : }
331 :
332 :
333 : // This is the function that calculates the block coordinates for the fetch
334 3 : void GDALWMSRasterBand::AskMiniDriverForBlock(CPLString *url, int x, int y) {
335 : GDALWMSImageRequestInfo iri;
336 : GDALWMSTiledImageRequestInfo tiri;
337 :
338 3 : int x0 = MAX(0, x * nBlockXSize);
339 3 : int y0 = MAX(0, y * nBlockYSize);
340 3 : int x1 = MAX(0, (x + 1) * nBlockXSize);
341 3 : int y1 = MAX(0, (y + 1) * nBlockYSize);
342 3 : if (m_parent_dataset->m_clamp_requests) {
343 1 : x0 = MIN(x0, nRasterXSize);
344 1 : y0 = MIN(y0, nRasterYSize);
345 1 : x1 = MIN(x1, nRasterXSize);
346 1 : y1 = MIN(y1, nRasterYSize);
347 : }
348 :
349 3 : const double rx = (m_parent_dataset->m_data_window.m_x1 - m_parent_dataset->m_data_window.m_x0) / static_cast<double>(nRasterXSize);
350 3 : const double ry = (m_parent_dataset->m_data_window.m_y1 - m_parent_dataset->m_data_window.m_y0) / static_cast<double>(nRasterYSize);
351 : /* Use different method for x0,y0 and x1,y1 to make sure calculated values are exact for corner requests */
352 3 : iri.m_x0 = x0 * rx + m_parent_dataset->m_data_window.m_x0;
353 3 : iri.m_y0 = y0 * ry + m_parent_dataset->m_data_window.m_y0;
354 3 : iri.m_x1 = m_parent_dataset->m_data_window.m_x1 - (nRasterXSize - x1) * rx;
355 3 : iri.m_y1 = m_parent_dataset->m_data_window.m_y1 - (nRasterYSize - y1) * ry;
356 3 : iri.m_sx = x1 - x0;
357 3 : iri.m_sy = y1 - y0;
358 :
359 3 : int level = m_overview + 1;
360 3 : tiri.m_x = (m_parent_dataset->m_data_window.m_tx >> level) + x;
361 3 : tiri.m_y = (m_parent_dataset->m_data_window.m_ty >> level) + y;
362 3 : tiri.m_level = m_parent_dataset->m_data_window.m_tlevel - level;
363 :
364 3 : m_parent_dataset->m_mini_driver->TiledImageRequest(url, iri, tiri);
365 3 : }
366 :
367 3 : CPLErr GDALWMSRasterBand::ReadBlockFromFile(int x, int y, const char *file_name, int to_buffer_band, void *buffer, int advise_read) {
368 3 : CPLErr ret = CE_None;
369 3 : GDALDataset *ds = 0;
370 3 : GByte *color_table = NULL;
371 : int i;
372 :
373 : //CPLDebug("WMS", "ReadBlockFromFile: to_buffer_band=%d, (x,y)=(%d, %d)", to_buffer_band, x, y);
374 :
375 : /* expected size */
376 3 : const int esx = MIN(MAX(0, (x + 1) * nBlockXSize), nRasterXSize) - MIN(MAX(0, x * nBlockXSize), nRasterXSize);
377 3 : const int esy = MIN(MAX(0, (y + 1) * nBlockYSize), nRasterYSize) - MIN(MAX(0, y * nBlockYSize), nRasterYSize);
378 3 : ds = reinterpret_cast<GDALDataset*>(GDALOpen(file_name, GA_ReadOnly));
379 3 : if (ds != NULL) {
380 3 : int sx = ds->GetRasterXSize();
381 3 : int sy = ds->GetRasterYSize();
382 3 : bool accepted_as_no_alpha = false; // if the request is for 4 bands but the wms returns 3
383 : /* Allow bigger than expected so pre-tiled constant size images work on corners */
384 3 : if ((sx > nBlockXSize) || (sy > nBlockYSize) || (sx < esx) || (sy < esy)) {
385 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect size %d x %d of downloaded block, expected %d x %d, max %d x %d.",
386 0 : sx, sy, esx, esy, nBlockXSize, nBlockYSize);
387 0 : ret = CE_Failure;
388 : }
389 3 : if (ret == CE_None) {
390 3 : int nDSRasterCount = ds->GetRasterCount();
391 3 : if (nDSRasterCount != m_parent_dataset->nBands) {
392 : /* Maybe its an image with color table */
393 0 : bool accepted_as_ct = false;
394 0 : if ((eDataType == GDT_Byte) && (ds->GetRasterCount() == 1)) {
395 0 : GDALRasterBand *rb = ds->GetRasterBand(1);
396 0 : if (rb->GetRasterDataType() == GDT_Byte) {
397 0 : GDALColorTable *ct = rb->GetColorTable();
398 0 : if (ct != NULL) {
399 0 : accepted_as_ct = true;
400 0 : if (!advise_read) {
401 0 : color_table = new GByte[256 * 4];
402 0 : const int count = MIN(256, ct->GetColorEntryCount());
403 0 : for (i = 0; i < count; ++i) {
404 : GDALColorEntry ce;
405 0 : ct->GetColorEntryAsRGB(i, &ce);
406 0 : color_table[i] = static_cast<GByte>(ce.c1);
407 0 : color_table[i + 256] = static_cast<GByte>(ce.c2);
408 0 : color_table[i + 512] = static_cast<GByte>(ce.c3);
409 0 : color_table[i + 768] = static_cast<GByte>(ce.c4);
410 : }
411 0 : for (i = count; i < 256; ++i) {
412 0 : color_table[i] = 0;
413 0 : color_table[i + 256] = 0;
414 0 : color_table[i + 512] = 0;
415 0 : color_table[i + 768] = 0;
416 : }
417 : }
418 : }
419 : }
420 : }
421 :
422 0 : if (nDSRasterCount == 4 && m_parent_dataset->nBands == 3)
423 : {
424 : /* metacarta TMS service sometimes return a 4 band PNG instead of the expected 3 band... */
425 : }
426 0 : else if (!accepted_as_ct) {
427 0 : if (ds->GetRasterCount()==3 && m_parent_dataset->nBands == 4 && (eDataType == GDT_Byte))
428 : { // WMS returned a file with no alpha so we will fill the alpha band with "opaque"
429 0 : accepted_as_no_alpha = true;
430 : }
431 : else
432 : {
433 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect bands count %d in downloaded block, expected %d.",
434 0 : nDSRasterCount, m_parent_dataset->nBands);
435 0 : ret = CE_Failure;
436 : }
437 : }
438 : }
439 : }
440 3 : if (!advise_read) {
441 8 : for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) {
442 5 : if (ret == CE_None) {
443 5 : void *p = NULL;
444 5 : GDALRasterBlock *b = NULL;
445 7 : if ((buffer != NULL) && (ib == to_buffer_band)) {
446 2 : p = buffer;
447 : } else {
448 3 : GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib));
449 3 : if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview));
450 3 : if (!band->IsBlockInCache(x, y)) {
451 3 : b = band->GetLockedBlockRef(x, y, true);
452 3 : if (b != NULL) {
453 3 : p = b->GetDataRef();
454 3 : if (p == NULL) {
455 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: GetDataRef returned NULL.");
456 0 : ret = CE_Failure;
457 : }
458 : }
459 : }
460 : else
461 : {
462 : //CPLDebug("WMS", "Band %d, block (x,y)=(%d, %d) already in cache", band->GetBand(), x, y);
463 : }
464 : }
465 5 : if (p != NULL) {
466 5 : int pixel_space = GDALGetDataTypeSize(eDataType) / 8;
467 5 : int line_space = pixel_space * nBlockXSize;
468 5 : if (color_table == NULL) {
469 5 : if( ib <= ds->GetRasterCount()) {
470 5 : GDALDataType dt=eDataType;
471 : // Get the data from the PNG as stored instead of converting, if the server asks for that
472 : // TODO: This hack is from #3493 - not sure it really belongs here.
473 5 : if ((GDT_Int16==dt)&&(GDT_UInt16==ds->GetRasterBand(ib)->GetRasterDataType()))
474 2 : dt=GDT_UInt16;
475 5 : if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, dt, 1, &ib, pixel_space, line_space, 0) != CE_None) {
476 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: RasterIO failed on downloaded block.");
477 0 : ret = CE_Failure;
478 : }
479 : }
480 : else
481 : { // parent expects 4 bands but file only has 3 so generate a all "opaque" 4th band
482 0 : if (accepted_as_no_alpha)
483 : {
484 : // the file had 3 bands and we are reading band 4 (Alpha) so fill with 255 (no alpha)
485 0 : GByte *byte_buffer = reinterpret_cast<GByte *>(p);
486 0 : for (int y = 0; y < sy; ++y) {
487 0 : for (int x = 0; x < sx; ++x) {
488 0 : const int offset = x + y * line_space;
489 0 : byte_buffer[offset] = 255; // fill with opaque
490 : }
491 : }
492 : }
493 : else
494 : { // we should never get here because this case was caught above
495 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect bands count %d in downloaded block, expected %d.",
496 0 : ds->GetRasterCount(), m_parent_dataset->nBands);
497 0 : ret = CE_Failure;
498 : }
499 : }
500 0 : } else if (ib <= 4) {
501 0 : if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, eDataType, 1, NULL, pixel_space, line_space, 0) != CE_None) {
502 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: RasterIO failed on downloaded block.");
503 0 : ret = CE_Failure;
504 : }
505 0 : if (ret == CE_None) {
506 0 : GByte *band_color_table = color_table + 256 * (ib - 1);
507 0 : GByte *byte_buffer = reinterpret_cast<GByte *>(p);
508 0 : for (int y = 0; y < sy; ++y) {
509 0 : for (int x = 0; x < sx; ++x) {
510 0 : const int offset = x + y * line_space;
511 0 : byte_buffer[offset] = band_color_table[byte_buffer[offset]];
512 : }
513 : }
514 : }
515 : } else {
516 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Color table supports at most 4 components.");
517 0 : ret = CE_Failure;
518 : }
519 : }
520 5 : if (b != NULL) {
521 3 : b->DropLock();
522 : }
523 : }
524 : }
525 : }
526 3 : GDALClose(ds);
527 : } else {
528 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Unable to open downloaded block.");
529 0 : ret = CE_Failure;
530 : }
531 :
532 3 : if (color_table != NULL) {
533 0 : delete[] color_table;
534 : }
535 :
536 3 : return ret;
537 : }
538 :
539 0 : CPLErr GDALWMSRasterBand::ZeroBlock(int x, int y, int to_buffer_band, void *buffer) {
540 0 : CPLErr ret = CE_None;
541 :
542 0 : for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) {
543 0 : if (ret == CE_None) {
544 0 : void *p = NULL;
545 0 : GDALRasterBlock *b = NULL;
546 0 : if ((buffer != NULL) && (ib == to_buffer_band)) {
547 0 : p = buffer;
548 : } else {
549 0 : GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib));
550 0 : if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview));
551 0 : if (!band->IsBlockInCache(x, y)) {
552 0 : b = band->GetLockedBlockRef(x, y, true);
553 0 : if (b != NULL) {
554 0 : p = b->GetDataRef();
555 0 : if (p == NULL) {
556 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: GetDataRef returned NULL.");
557 0 : ret = CE_Failure;
558 : }
559 : }
560 : }
561 : }
562 0 : if (p != NULL) {
563 0 : unsigned char *b = reinterpret_cast<unsigned char *>(p);
564 0 : int block_size = nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType) / 8);
565 0 : for (int i = 0; i < block_size; ++i) b[i] = 0;
566 : }
567 0 : if (b != NULL) {
568 0 : b->DropLock();
569 : }
570 : }
571 : }
572 :
573 0 : return ret;
574 : }
575 :
576 0 : CPLErr GDALWMSRasterBand::ReportWMSException(const char *file_name) {
577 0 : CPLErr ret = CE_None;
578 0 : int reported_errors_count = 0;
579 :
580 0 : CPLXMLNode *orig_root = CPLParseXMLFile(file_name);
581 0 : CPLXMLNode *root = orig_root;
582 0 : if (root != NULL) {
583 0 : root = CPLGetXMLNode(root, "=ServiceExceptionReport");
584 : }
585 0 : if (root != NULL) {
586 0 : CPLXMLNode *n = CPLGetXMLNode(root, "ServiceException");
587 0 : while (n != NULL) {
588 0 : const char *exception = CPLGetXMLValue(n, "=ServiceException", "");
589 0 : const char *exception_code = CPLGetXMLValue(n, "=ServiceException.code", "");
590 0 : if (exception[0] != '\0') {
591 0 : if (exception_code[0] != '\0') {
592 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned exception code '%s': %s", exception_code, exception);
593 0 : ++reported_errors_count;
594 : } else {
595 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned exception: %s", exception);
596 0 : ++reported_errors_count;
597 : }
598 0 : } else if (exception_code[0] != '\0') {
599 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned exception code '%s'.", exception_code);
600 0 : ++reported_errors_count;
601 : }
602 :
603 0 : n = n->psNext;
604 0 : if (n != NULL) {
605 0 : n = CPLGetXMLNode(n, "=ServiceException");
606 : }
607 : }
608 : } else {
609 0 : ret = CE_Failure;
610 : }
611 0 : if (orig_root != NULL) {
612 0 : CPLDestroyXMLNode(orig_root);
613 : }
614 :
615 0 : if (reported_errors_count == 0) {
616 0 : ret = CE_Failure;
617 : }
618 :
619 0 : return ret;
620 : }
621 :
622 :
623 0 : CPLErr GDALWMSRasterBand::AdviseRead(int x0, int y0, int sx, int sy, int bsx, int bsy, GDALDataType bdt, char **options) {
624 : // printf("AdviseRead(%d, %d, %d, %d)\n", x0, y0, sx, sy);
625 0 : if (m_parent_dataset->m_offline_mode || !m_parent_dataset->m_use_advise_read) return CE_None;
626 0 : if (m_parent_dataset->m_cache == NULL) return CE_Failure;
627 :
628 0 : int bx0 = x0 / nBlockXSize;
629 0 : int by0 = y0 / nBlockYSize;
630 0 : int bx1 = (x0 + sx - 1) / nBlockXSize;
631 0 : int by1 = (y0 + sy - 1) / nBlockYSize;
632 :
633 0 : return ReadBlocks(0, 0, NULL, bx0, by0, bx1, by1, 1);
634 : }
635 :
636 0 : GDALColorInterp GDALWMSRasterBand::GetColorInterpretation() {
637 0 : return m_color_interp;
638 : }
639 :
640 4 : CPLErr GDALWMSRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
641 : {
642 4 : m_color_interp = eNewInterp;
643 4 : return CE_None;
644 : }
645 :
|