1 : /******************************************************************************
2 : * $Id: dataset.cpp 19089 2010-03-15 13:20:41Z nowakpl $
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 5 : GDALWMSDataset::GDALWMSDataset() {
34 5 : m_mini_driver = 0;
35 5 : m_cache = 0;
36 5 : m_hint.m_valid = false;
37 5 : m_data_type = GDT_Byte;
38 5 : m_clamp_requests = true;
39 5 : }
40 :
41 5 : GDALWMSDataset::~GDALWMSDataset() {
42 5 : if (m_mini_driver) delete m_mini_driver;
43 5 : if (m_cache) delete m_cache;
44 5 : }
45 5 : CPLErr GDALWMSDataset::Initialize(CPLXMLNode *config) {
46 5 : CPLErr ret = CE_None;
47 :
48 5 : const char *pszUserAgent = CPLGetXMLValue(config, "UserAgent", "");
49 5 : if (pszUserAgent[0] != '\0')
50 0 : m_osUserAgent = pszUserAgent;
51 :
52 5 : if (ret == CE_None) {
53 5 : const char *max_conn = CPLGetXMLValue(config, "MaxConnections", "");
54 5 : if (max_conn[0] != '\0') {
55 0 : m_http_max_conn = atoi(max_conn);
56 : } else {
57 5 : m_http_max_conn = 2;
58 : }
59 : }
60 5 : if (ret == CE_None) {
61 5 : const char *timeout = CPLGetXMLValue(config, "Timeout", "");
62 5 : if (timeout[0] != '\0') {
63 0 : m_http_timeout = atoi(timeout);
64 : } else {
65 5 : m_http_timeout = 300;
66 : }
67 : }
68 5 : if (ret == CE_None) {
69 5 : const char *offline_mode = CPLGetXMLValue(config, "OfflineMode", "");
70 5 : if (offline_mode[0] != '\0') {
71 0 : const int offline_mode_bool = StrToBool(offline_mode);
72 0 : if (offline_mode_bool == -1) {
73 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of OfflineMode, true / false expected.");
74 0 : ret = CE_Failure;
75 : } else {
76 0 : m_offline_mode = offline_mode_bool;
77 : }
78 : } else {
79 5 : m_offline_mode = 0;
80 : }
81 : }
82 5 : if (ret == CE_None) {
83 5 : const char *advise_read = CPLGetXMLValue(config, "AdviseRead", "");
84 5 : if (advise_read[0] != '\0') {
85 0 : const int advise_read_bool = StrToBool(advise_read);
86 0 : if (advise_read_bool == -1) {
87 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of AdviseRead, true / false expected.");
88 0 : ret = CE_Failure;
89 : } else {
90 0 : m_use_advise_read = advise_read_bool;
91 : }
92 : } else {
93 5 : m_use_advise_read = 0;
94 : }
95 : }
96 5 : if (ret == CE_None) {
97 5 : const char *verify_advise_read = CPLGetXMLValue(config, "VerifyAdviseRead", "");
98 5 : if (m_use_advise_read) {
99 0 : if (verify_advise_read[0] != '\0') {
100 0 : const int verify_advise_read_bool = StrToBool(verify_advise_read);
101 0 : if (verify_advise_read_bool == -1) {
102 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of VerifyAdviseRead, true / false expected.");
103 0 : ret = CE_Failure;
104 : } else {
105 0 : m_verify_advise_read = verify_advise_read_bool;
106 : }
107 : } else {
108 0 : m_verify_advise_read = 1;
109 : }
110 : }
111 : }
112 5 : if (ret == CE_None) {
113 5 : const char *block_size_x = CPLGetXMLValue(config, "BlockSizeX", "1024");
114 5 : const char *block_size_y = CPLGetXMLValue(config, "BlockSizeY", "1024");
115 5 : m_block_size_x = atoi(block_size_x);
116 5 : m_block_size_y = atoi(block_size_y);
117 5 : if (m_block_size_x <= 0 || m_block_size_y <= 0)
118 : {
119 : CPLError( CE_Failure, CPLE_AppDefined,
120 0 : "GDALWMS: Invalid value in BlockSizeX or BlockSizeY" );
121 0 : ret = CE_Failure;
122 : }
123 : }
124 5 : if (ret == CE_None)
125 : {
126 5 : const char *data_type = CPLGetXMLValue(config, "DataType", "Byte");
127 5 : m_data_type = GDALGetDataTypeByName( data_type );
128 5 : if ( m_data_type == GDT_Unknown || m_data_type >= GDT_TypeCount )
129 : {
130 : CPLError( CE_Failure, CPLE_AppDefined,
131 0 : "GDALWMS: Invalid value in DataType. Data type \"%s\" is not supported.", data_type );
132 0 : ret = CE_Failure;
133 : }
134 : }
135 5 : if (ret == CE_None) {
136 5 : const int clamp_requests_bool = StrToBool(CPLGetXMLValue(config, "ClampRequests", "true"));
137 5 : if (clamp_requests_bool == -1) {
138 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Invalid value of ClampRequests, true / false expected.");
139 0 : ret = CE_Failure;
140 : } else {
141 5 : m_clamp_requests = clamp_requests_bool;
142 : }
143 : }
144 5 : if (ret == CE_None) {
145 5 : CPLXMLNode *data_window_node = CPLGetXMLNode(config, "DataWindow");
146 5 : if (data_window_node == NULL) {
147 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: DataWindow missing.");
148 0 : ret = CE_Failure;
149 : } else {
150 5 : const char *overview_count = CPLGetXMLValue(config, "OverviewCount", "");
151 5 : const char *ulx = CPLGetXMLValue(data_window_node, "UpperLeftX", "-180.0");
152 5 : const char *uly = CPLGetXMLValue(data_window_node, "UpperLeftY", "90.0");
153 5 : const char *lrx = CPLGetXMLValue(data_window_node, "LowerRightX", "180.0");
154 5 : const char *lry = CPLGetXMLValue(data_window_node, "LowerRightY", "-90.0");
155 5 : const char *sx = CPLGetXMLValue(data_window_node, "SizeX", "");
156 5 : const char *sy = CPLGetXMLValue(data_window_node, "SizeY", "");
157 5 : const char *tx = CPLGetXMLValue(data_window_node, "TileX", "0");
158 5 : const char *ty = CPLGetXMLValue(data_window_node, "TileY", "0");
159 5 : const char *tlevel = CPLGetXMLValue(data_window_node, "TileLevel", "");
160 5 : const char *str_tile_count_x = CPLGetXMLValue(data_window_node, "TileCountX", "1");
161 5 : const char *str_tile_count_y = CPLGetXMLValue(data_window_node, "TileCountY", "1");
162 5 : const char *y_origin = CPLGetXMLValue(data_window_node, "YOrigin", "default");
163 :
164 5 : if (ret == CE_None) {
165 10 : if ((ulx[0] != '\0') && (uly[0] != '\0') && (lrx[0] != '\0') && (lry[0] != '\0')) {
166 5 : m_data_window.m_x0 = atof(ulx);
167 5 : m_data_window.m_y0 = atof(uly);
168 5 : m_data_window.m_x1 = atof(lrx);
169 5 : m_data_window.m_y1 = atof(lry);
170 : } else {
171 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Mandatory elements of DataWindow missing: UpperLeftX, UpperLeftY, LowerRightX, LowerRightY.");
172 0 : ret = CE_Failure;
173 : }
174 : }
175 5 : if (ret == CE_None) {
176 5 : if (tlevel[0] != '\0') {
177 3 : m_data_window.m_tlevel = atoi(tlevel);
178 : } else {
179 2 : m_data_window.m_tlevel = 0;
180 : }
181 : }
182 5 : if (ret == CE_None) {
183 8 : if ((sx[0] != '\0') && (sy[0] != '\0')) {
184 3 : m_data_window.m_sx = atoi(sx);
185 3 : m_data_window.m_sy = atoi(sy);
186 4 : } else if ((tlevel[0] != '\0') && (str_tile_count_x[0] != '\0') && (str_tile_count_y[0] != '\0')) {
187 2 : int tile_count_x = atoi(str_tile_count_x);
188 2 : int tile_count_y = atoi(str_tile_count_y);
189 2 : m_data_window.m_sx = tile_count_x * m_block_size_x * (1 << m_data_window.m_tlevel);
190 2 : m_data_window.m_sy = tile_count_y * m_block_size_y * (1 << m_data_window.m_tlevel);
191 : } else {
192 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Mandatory elements of DataWindow missing: SizeX, SizeY.");
193 0 : ret = CE_Failure;
194 : }
195 : }
196 5 : if (ret == CE_None) {
197 10 : if ((tx[0] != '\0') && (ty[0] != '\0')) {
198 5 : m_data_window.m_tx = atoi(tx);
199 5 : m_data_window.m_ty = atoi(ty);
200 : } else {
201 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Mandatory elements of DataWindow missing: TileX, TileY.");
202 0 : ret = CE_Failure;
203 : }
204 : }
205 5 : if (ret == CE_None) {
206 5 : if (overview_count[0] != '\0') {
207 1 : m_overview_count = atoi(overview_count);
208 4 : } else if (tlevel[0] != '\0') {
209 2 : m_overview_count = m_data_window.m_tlevel;
210 : } else {
211 2 : const int min_overview_size = MAX(32, MIN(m_block_size_x, m_block_size_y));
212 : double a = log(static_cast<double>(MIN(m_data_window.m_sx, m_data_window.m_sy))) / log(2.0)
213 2 : - log(static_cast<double>(min_overview_size)) / log(2.0);
214 2 : m_overview_count = MAX(0, MIN(static_cast<int>(ceil(a)), 32));
215 : }
216 : }
217 5 : if (ret == CE_None) {
218 5 : CPLString y_origin_str = y_origin;
219 5 : if (y_origin_str == "top") {
220 0 : m_data_window.m_y_origin = GDALWMSDataWindow::TOP;
221 5 : } else if (y_origin_str == "bottom") {
222 0 : m_data_window.m_y_origin = GDALWMSDataWindow::BOTTOM;
223 5 : } else if (y_origin_str == "default") {
224 5 : m_data_window.m_y_origin = GDALWMSDataWindow::DEFAULT;
225 : } else {
226 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: DataWindow YOrigin must be set to "
227 0 : "one of 'default', 'top', or 'bottom', not '%s'.", y_origin_str.c_str());
228 0 : ret = CE_Failure;
229 5 : }
230 : }
231 : }
232 : }
233 5 : if (ret == CE_None) {
234 5 : const char *proj = CPLGetXMLValue(config, "Projection", "");
235 5 : if (proj[0] != '\0') {
236 5 : m_projection = ProjToWKT(proj);
237 5 : if (m_projection.size() == 0) {
238 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Bad projection specified.");
239 0 : ret = CE_Failure;
240 : }
241 : }
242 : }
243 :
244 5 : const char *bands_count = CPLGetXMLValue(config, "BandsCount", "3");
245 5 : int nBandCount = atoi(bands_count);
246 :
247 5 : if (ret == CE_None) {
248 5 : CPLXMLNode *cache_node = CPLGetXMLNode(config, "Cache");
249 5 : if (cache_node != NULL) {
250 1 : m_cache = new GDALWMSCache();
251 1 : if (m_cache->Initialize(cache_node) != CE_None) {
252 0 : delete m_cache;
253 0 : m_cache = NULL;
254 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Failed to initialize cache.");
255 0 : ret = CE_Failure;
256 : }
257 : }
258 : }
259 5 : if (ret == CE_None) {
260 5 : CPLXMLNode *service_node = CPLGetXMLNode(config, "Service");
261 5 : if (service_node != NULL) {
262 5 : const char *service_name = CPLGetXMLValue(service_node, "name", "");
263 5 : if (service_name[0] != '\0') {
264 5 : GDALWMSMiniDriverManager *const mdm = GetGDALWMSMiniDriverManager();
265 5 : GDALWMSMiniDriverFactory *const mdf = mdm->Find(CPLString(service_name));
266 5 : if (mdf != NULL) {
267 5 : m_mini_driver = mdf->New();
268 5 : m_mini_driver->m_parent_dataset = this;
269 5 : if (m_mini_driver->Initialize(service_node) == CE_None) {
270 5 : m_mini_driver_caps.m_capabilities_version = -1;
271 5 : m_mini_driver->GetCapabilities(&m_mini_driver_caps);
272 5 : if (m_mini_driver_caps.m_capabilities_version == -1) {
273 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Internal error, mini-driver capabilities version not set.");
274 0 : ret = CE_Failure;
275 : }
276 : } else {
277 0 : delete m_mini_driver;
278 0 : m_mini_driver = NULL;
279 :
280 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Failed to initialize minidriver.");
281 0 : ret = CE_Failure;
282 : }
283 : } else {
284 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No mini-driver registered for '%s'.", service_name);
285 0 : ret = CE_Failure;
286 : }
287 : } else {
288 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No Service specified.");
289 0 : ret = CE_Failure;
290 : }
291 : } else {
292 0 : CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No Service specified.");
293 0 : ret = CE_Failure;
294 : }
295 : }
296 5 : if (ret == CE_None) {
297 5 : nRasterXSize = m_data_window.m_sx;
298 5 : nRasterYSize = m_data_window.m_sy;
299 :
300 5 : if (!GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize) ||
301 : !GDALCheckBandCount(nBandCount, TRUE))
302 : {
303 0 : return CE_Failure;
304 : }
305 :
306 : GDALColorInterp default_color_interp[4][4] = {
307 : { GCI_GrayIndex, GCI_Undefined, GCI_Undefined, GCI_Undefined },
308 : { GCI_GrayIndex, GCI_AlphaBand, GCI_Undefined, GCI_Undefined },
309 : { GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_Undefined },
310 : { GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_AlphaBand }
311 5 : };
312 20 : for (int i = 0; i < nBandCount; ++i) {
313 15 : GDALColorInterp color_interp = (nBandCount <= 4 && i <= 3 ? default_color_interp[nBandCount - 1][i] : GCI_Undefined);
314 15 : GDALWMSRasterBand *band = new GDALWMSRasterBand(this, i, 1.0);
315 15 : band->m_color_interp = color_interp;
316 15 : SetBand(i + 1, band);
317 15 : double scale = 0.5;
318 222 : for (int j = 0; j < m_overview_count; ++j) {
319 207 : band->AddOverview(scale);
320 207 : band->m_color_interp = color_interp;
321 207 : scale *= 0.5;
322 : }
323 : }
324 : }
325 :
326 5 : if (ret == CE_None) {
327 : /* If we dont have projection already set ask mini-driver. */
328 5 : if (!m_projection.size()) {
329 0 : const char *proj = m_mini_driver->GetProjectionInWKT();
330 0 : if (proj != NULL) {
331 0 : m_projection = proj;
332 : }
333 : }
334 : }
335 :
336 5 : return ret;
337 : }
338 :
339 0 : CPLErr GDALWMSDataset::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy, void *buffer, int bsx, int bsy, GDALDataType bdt, int band_count, int *band_map, int pixel_space, int line_space, int band_space) {
340 : CPLErr ret;
341 :
342 0 : if (rw != GF_Read) return CE_Failure;
343 0 : if (buffer == NULL) return CE_Failure;
344 0 : if ((sx == 0) || (sy == 0) || (bsx == 0) || (bsy == 0) || (band_count == 0)) return CE_None;
345 :
346 0 : m_hint.m_x0 = x0;
347 0 : m_hint.m_y0 = y0;
348 0 : m_hint.m_sx = sx;
349 0 : m_hint.m_sy = sy;
350 0 : m_hint.m_overview = -1;
351 0 : m_hint.m_valid = true;
352 : // printf("[%p] GDALWMSDataset::IRasterIO(x0: %d, y0: %d, sx: %d, sy: %d, bsx: %d, bsy: %d, band_count: %d, band_map: %p)\n", this, x0, y0, sx, sy, bsx, bsy, band_count, band_map);
353 0 : ret = GDALDataset::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt, band_count, band_map, pixel_space, line_space, band_space);
354 0 : m_hint.m_valid = false;
355 :
356 0 : return ret;
357 : }
358 :
359 1 : const char *GDALWMSDataset::GetProjectionRef() {
360 1 : return m_projection.c_str();
361 : }
362 :
363 0 : CPLErr GDALWMSDataset::SetProjection(const char *proj) {
364 0 : return CE_Failure;
365 : }
366 :
367 1 : CPLErr GDALWMSDataset::GetGeoTransform(double *gt) {
368 1 : gt[0] = m_data_window.m_x0;
369 1 : gt[1] = (m_data_window.m_x1 - m_data_window.m_x0) / static_cast<double>(m_data_window.m_sx);
370 1 : gt[2] = 0.0;
371 1 : gt[3] = m_data_window.m_y0;
372 1 : gt[4] = 0.0;
373 1 : gt[5] = (m_data_window.m_y1 - m_data_window.m_y0) / static_cast<double>(m_data_window.m_sy);
374 1 : return CE_None;
375 : }
376 :
377 0 : CPLErr GDALWMSDataset::SetGeoTransform(double *gt) {
378 0 : return CE_Failure;
379 : }
380 :
381 4 : const GDALWMSDataWindow *GDALWMSDataset::WMSGetDataWindow() const {
382 4 : return &m_data_window;
383 : }
384 :
385 0 : int GDALWMSDataset::WMSGetBlockSizeX() const {
386 0 : return m_block_size_x;
387 : }
388 :
389 0 : int GDALWMSDataset::WMSGetBlockSizeY() const {
390 0 : return m_block_size_y;
391 : }
392 :
393 0 : CPLErr GDALWMSDataset::AdviseRead(int x0, int y0, int sx, int sy, int bsx, int bsy, GDALDataType bdt, int band_count, int *band_map, char **options) {
394 : // printf("AdviseRead(%d, %d, %d, %d)\n", x0, y0, sx, sy);
395 0 : if (m_offline_mode || !m_use_advise_read) return CE_None;
396 0 : if (m_cache == NULL) return CE_Failure;
397 :
398 0 : GDALRasterBand *band = GetRasterBand(1);
399 0 : if (band == NULL) return CE_Failure;
400 0 : return band->AdviseRead(x0, y0, sx, sy, bsx, bsy, bdt, options);
401 : }
|