/src/MapServer/src/maplayer.c
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * $Id$ |
3 | | * |
4 | | * Project: MapServer |
5 | | * Purpose: Implementation of most layerObj functions. |
6 | | * Author: Steve Lime and the MapServer team. |
7 | | * |
8 | | ****************************************************************************** |
9 | | * Copyright (c) 1996-2005 Regents of the University of Minnesota. |
10 | | * |
11 | | * Permission is hereby granted, free of charge, to any person obtaining a |
12 | | * copy of this software and associated documentation files (the "Software"), |
13 | | * to deal in the Software without restriction, including without limitation |
14 | | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
15 | | * and/or sell copies of the Software, and to permit persons to whom the |
16 | | * Software is furnished to do so, subject to the following conditions: |
17 | | * |
18 | | * The above copyright notice and this permission notice shall be included in |
19 | | * all copies of this Software or works derived from this Software. |
20 | | * |
21 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
22 | | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
23 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
24 | | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
25 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
26 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
27 | | * DEALINGS IN THE SOFTWARE. |
28 | | ****************************************************************************/ |
29 | | |
30 | | #include "mapserver.h" |
31 | | #include "maptime.h" |
32 | | #include "mapogcfilter.h" |
33 | | #include "mapthread.h" |
34 | | #include "mapfile.h" |
35 | | #include "mapows.h" |
36 | | #include "mapparser.h" |
37 | | #include "mapogcsld.h" |
38 | | |
39 | | #include "cpl_string.h" |
40 | | |
41 | | #include <assert.h> |
42 | | |
43 | | #ifndef cppcheck_assert |
44 | | #define cppcheck_assert(x) \ |
45 | 0 | do { \ |
46 | 0 | } while (0) |
47 | | #endif |
48 | | |
49 | | static int populateVirtualTable(layerVTableObj *vtable); |
50 | | |
51 | | /* |
52 | | ** Iteminfo is a layer parameter that holds information necessary to retrieve an |
53 | | *individual item for |
54 | | ** a particular source. It is an array built from a list of items. The type of |
55 | | *iteminfo will vary by |
56 | | ** source. For shapefiles and OGR it is simply an array of integers where each |
57 | | *value is an index for |
58 | | ** the item. For SDE it's a ESRI specific type that contains index and column |
59 | | *type information. Two |
60 | | ** helper functions below initialize and free that structure member which is |
61 | | *used locally by layer |
62 | | ** specific functions. |
63 | | */ |
64 | 0 | int msLayerInitItemInfo(layerObj *layer) { |
65 | 0 | if (!layer->vtable) { |
66 | 0 | int rv = msInitializeVirtualTable(layer); |
67 | 0 | if (rv != MS_SUCCESS) |
68 | 0 | return rv; |
69 | 0 | } |
70 | 0 | cppcheck_assert(layer->vtable); |
71 | 0 | return layer->vtable->LayerInitItemInfo(layer); |
72 | 0 | } |
73 | | |
74 | 0 | void msLayerFreeItemInfo(layerObj *layer) { |
75 | 0 | if (!layer->vtable) { |
76 | 0 | int rv = msInitializeVirtualTable(layer); |
77 | 0 | if (rv != MS_SUCCESS) |
78 | 0 | return; |
79 | 0 | } |
80 | 0 | cppcheck_assert(layer->vtable); |
81 | 0 | layer->vtable->LayerFreeItemInfo(layer); |
82 | | |
83 | | /* |
84 | | * Layer expressions with attribute binding hold a numeric index pointing |
85 | | * to an iteminfo (node->tokenval.bindval.index). If iteminfo changes, |
86 | | * an expression may be no longer valid. (#5161) |
87 | | */ |
88 | 0 | msLayerFreeExpressions(layer); |
89 | 0 | } |
90 | | |
91 | 0 | int msLayerRestoreFromScaletokens(layerObj *layer) { |
92 | 0 | if (!layer->scaletokens || !layer->orig_st) { |
93 | 0 | return MS_SUCCESS; |
94 | 0 | } |
95 | 0 | if (layer->orig_st->data) { |
96 | 0 | msFree(layer->data); |
97 | 0 | layer->data = layer->orig_st->data; |
98 | 0 | } |
99 | 0 | if (layer->orig_st->tileindex) { |
100 | 0 | msFree(layer->tileindex); |
101 | 0 | layer->tileindex = layer->orig_st->tileindex; |
102 | 0 | } |
103 | 0 | if (layer->orig_st->tileitem) { |
104 | 0 | msFree(layer->tileitem); |
105 | 0 | layer->tileitem = layer->orig_st->tileitem; |
106 | 0 | } |
107 | 0 | if (layer->orig_st->filter) { |
108 | 0 | if (layer->filter.type == MS_EXPRESSION) { |
109 | 0 | const size_t tmpval_size = strlen(layer->filter.string) + 3; |
110 | 0 | char *tmpval = (char *)msSmallMalloc(tmpval_size); |
111 | 0 | snprintf(tmpval, tmpval_size, "(%s)", layer->filter.string); |
112 | 0 | msLoadExpressionString(&(layer->filter), tmpval); |
113 | 0 | msFree(tmpval); |
114 | 0 | } else { |
115 | 0 | msLoadExpressionString(&(layer->filter), layer->orig_st->filter); |
116 | 0 | } |
117 | 0 | msFree(layer->orig_st->filter); |
118 | 0 | } |
119 | 0 | if (layer->orig_st->filteritem) { |
120 | 0 | msFree(layer->filteritem); |
121 | 0 | layer->filteritem = layer->orig_st->filteritem; |
122 | 0 | } |
123 | 0 | if (layer->orig_st->processing) { |
124 | 0 | CSLDestroy(layer->processing); |
125 | 0 | layer->processing = layer->orig_st->processing; |
126 | 0 | layer->orig_st->processing = NULL; |
127 | 0 | } |
128 | 0 | msFree(layer->orig_st); |
129 | 0 | layer->orig_st = NULL; |
130 | 0 | return MS_SUCCESS; |
131 | 0 | } |
132 | | |
133 | | #define check_st_alloc(l) \ |
134 | 0 | if (!l->orig_st) \ |
135 | 0 | l->orig_st = msSmallCalloc(1, sizeof(originalScaleTokenStrings)); |
136 | 0 | int msLayerApplyScaletokens(layerObj *layer, double scale) { |
137 | 0 | int i, p; |
138 | 0 | if (!layer->scaletokens) { |
139 | 0 | return MS_SUCCESS; |
140 | 0 | } |
141 | 0 | msLayerRestoreFromScaletokens(layer); |
142 | 0 | for (i = 0; i < layer->numscaletokens; i++) { |
143 | 0 | scaleTokenObj *st = &layer->scaletokens[i]; |
144 | 0 | scaleTokenEntryObj *ste = NULL; |
145 | 0 | if (scale <= 0) { |
146 | 0 | ste = &(st->tokens[0]); |
147 | | /* no scale defined, use first entry */ |
148 | 0 | } else { |
149 | 0 | int tokenindex = 0; |
150 | 0 | while (tokenindex < st->n_entries) { |
151 | 0 | ste = &(st->tokens[tokenindex]); |
152 | 0 | if (scale < ste->maxscale && scale >= ste->minscale) |
153 | 0 | break; /* current token is the correct one */ |
154 | 0 | tokenindex++; |
155 | 0 | ste = NULL; |
156 | 0 | } |
157 | 0 | } |
158 | 0 | assert(ste); |
159 | 0 | if (layer->data && strstr(layer->data, st->name)) { |
160 | 0 | if (layer->debug >= MS_DEBUGLEVEL_DEBUG) { |
161 | 0 | msDebug("replacing scaletoken (%s) with (%s) in layer->data (%s) for " |
162 | 0 | "scale=%f\n", |
163 | 0 | st->name, ste->value, layer->name, scale); |
164 | 0 | } |
165 | 0 | check_st_alloc(layer); |
166 | 0 | layer->orig_st->data = layer->data; |
167 | 0 | layer->data = msStrdup(layer->data); |
168 | 0 | layer->data = msReplaceSubstring(layer->data, st->name, ste->value); |
169 | 0 | } |
170 | 0 | if (layer->tileindex && strstr(layer->tileindex, st->name)) { |
171 | 0 | if (layer->debug >= MS_DEBUGLEVEL_DEBUG) { |
172 | 0 | msDebug("replacing scaletoken (%s) with (%s) in layer->tileindex (%s) " |
173 | 0 | "for scale=%f\n", |
174 | 0 | st->name, ste->value, layer->name, scale); |
175 | 0 | } |
176 | 0 | check_st_alloc(layer); |
177 | 0 | layer->orig_st->tileindex = layer->tileindex; |
178 | 0 | layer->tileindex = msStrdup(layer->tileindex); |
179 | 0 | layer->tileindex = |
180 | 0 | msReplaceSubstring(layer->tileindex, st->name, ste->value); |
181 | 0 | } |
182 | 0 | if (layer->tileitem && strstr(layer->tileitem, st->name)) { |
183 | 0 | if (layer->debug >= MS_DEBUGLEVEL_DEBUG) { |
184 | 0 | msDebug("replacing scaletoken (%s) with (%s) in layer->tileitem (%s) " |
185 | 0 | "for scale=%f\n", |
186 | 0 | st->name, ste->value, layer->name, scale); |
187 | 0 | } |
188 | 0 | check_st_alloc(layer); |
189 | 0 | layer->orig_st->tileitem = layer->tileitem; |
190 | 0 | layer->tileitem = msStrdup(layer->tileitem); |
191 | 0 | layer->tileitem = |
192 | 0 | msReplaceSubstring(layer->tileitem, st->name, ste->value); |
193 | 0 | } |
194 | 0 | if (layer->filteritem && strstr(layer->filteritem, st->name)) { |
195 | 0 | if (layer->debug >= MS_DEBUGLEVEL_DEBUG) { |
196 | 0 | msDebug("replacing scaletoken (%s) with (%s) in layer->filteritem (%s) " |
197 | 0 | "for scale=%f\n", |
198 | 0 | st->name, ste->value, layer->name, scale); |
199 | 0 | } |
200 | 0 | check_st_alloc(layer); |
201 | 0 | layer->orig_st->filteritem = layer->filteritem; |
202 | 0 | layer->filteritem = msStrdup(layer->filteritem); |
203 | 0 | layer->filteritem = |
204 | 0 | msReplaceSubstring(layer->filteritem, st->name, ste->value); |
205 | 0 | } |
206 | 0 | if (layer->filter.string && strstr(layer->filter.string, st->name)) { |
207 | 0 | if (layer->debug >= MS_DEBUGLEVEL_DEBUG) { |
208 | 0 | msDebug("replacing scaletoken (%s) with (%s) in layer->filter (%s) for " |
209 | 0 | "scale=%f\n", |
210 | 0 | st->name, ste->value, layer->name, scale); |
211 | 0 | } |
212 | 0 | check_st_alloc(layer); |
213 | 0 | layer->orig_st->filter = msStrdup(layer->filter.string); |
214 | |
|
215 | 0 | char *tmpval = NULL; |
216 | 0 | if (layer->filter.type == MS_EXPRESSION) { |
217 | 0 | const size_t tmpval_size = strlen(layer->filter.string) + 3; |
218 | 0 | tmpval = (char *)msSmallMalloc(tmpval_size); |
219 | 0 | snprintf(tmpval, tmpval_size, "(%s)", layer->filter.string); |
220 | 0 | } else { |
221 | 0 | tmpval = msStrdup(layer->filter.string); |
222 | 0 | } |
223 | |
|
224 | 0 | tmpval = msReplaceSubstring(tmpval, st->name, ste->value); |
225 | |
|
226 | 0 | if (msLoadExpressionString(&(layer->filter), tmpval) == -1) { |
227 | 0 | msFree(tmpval); |
228 | 0 | return (MS_FAILURE); /* msLoadExpressionString() cleans up previously |
229 | | allocated expression */ |
230 | 0 | } |
231 | 0 | msFree(tmpval); |
232 | 0 | } |
233 | | |
234 | 0 | for (p = 0; layer->processing && layer->processing[p]; p++) { |
235 | 0 | if (strstr(layer->processing[p], st->name)) { |
236 | 0 | check_st_alloc(layer); |
237 | 0 | if (!layer->orig_st->processing) { |
238 | 0 | layer->orig_st->processing = CSLDuplicate(layer->processing); |
239 | 0 | } |
240 | 0 | char *newVal = msStrdup(layer->processing[p]); |
241 | 0 | newVal = msReplaceSubstring(newVal, st->name, ste->value); |
242 | 0 | CPLFree(layer->processing[p]); |
243 | 0 | layer->processing[p] = CPLStrdup(newVal); |
244 | 0 | msFree(newVal); |
245 | 0 | } |
246 | 0 | } |
247 | 0 | } |
248 | 0 | return MS_SUCCESS; |
249 | 0 | } |
250 | | |
251 | | /* |
252 | | ** Does exactly what it implies, readies a layer for processing. |
253 | | */ |
254 | 0 | int msLayerOpen(layerObj *layer) { |
255 | 0 | int rv; |
256 | | |
257 | | /* RFC-86 Scale dependent token replacements*/ |
258 | 0 | rv = msLayerApplyScaletokens(layer, |
259 | 0 | (layer->map) ? layer->map->scaledenom : -1); |
260 | 0 | if (rv != MS_SUCCESS) |
261 | 0 | return rv; |
262 | | |
263 | | /* RFC-69 clustering support */ |
264 | 0 | if (layer->cluster.region) |
265 | 0 | return msClusterLayerOpen(layer); |
266 | | |
267 | 0 | if (layer->features && layer->connectiontype != MS_GRATICULE) |
268 | 0 | layer->connectiontype = MS_INLINE; |
269 | |
|
270 | 0 | if (layer->tileindex && layer->connectiontype == MS_SHAPEFILE) |
271 | 0 | layer->connectiontype = MS_TILED_SHAPEFILE; |
272 | |
|
273 | 0 | if (layer->type == MS_LAYER_RASTER && layer->connectiontype != MS_WMS && |
274 | 0 | layer->connectiontype != MS_KERNELDENSITY) |
275 | 0 | layer->connectiontype = MS_RASTER; |
276 | |
|
277 | 0 | if (!layer->vtable) { |
278 | 0 | rv = msInitializeVirtualTable(layer); |
279 | 0 | if (rv != MS_SUCCESS) |
280 | 0 | return rv; |
281 | 0 | } |
282 | 0 | cppcheck_assert(layer->vtable); |
283 | 0 | return layer->vtable->LayerOpen(layer); |
284 | 0 | } |
285 | | |
286 | | /* |
287 | | ** Returns MS_TRUE if layer has been opened using msLayerOpen(), MS_FALSE |
288 | | *otherwise |
289 | | */ |
290 | 0 | int msLayerIsOpen(layerObj *layer) { |
291 | 0 | if (!layer->vtable) { |
292 | 0 | int rv = msInitializeVirtualTable(layer); |
293 | 0 | if (rv != MS_SUCCESS) |
294 | 0 | return rv; |
295 | 0 | } |
296 | 0 | cppcheck_assert(layer->vtable); |
297 | 0 | return layer->vtable->LayerIsOpen(layer); |
298 | 0 | } |
299 | | |
300 | | /* |
301 | | ** msLayerPropertyIsCharacter() |
302 | | ** |
303 | | ** Check if a field in a layer is a Character type |
304 | | */ |
305 | 0 | bool msLayerPropertyIsCharacter(layerObj *layer, const char *property) { |
306 | 0 | if (!property) { |
307 | 0 | return false; |
308 | 0 | } |
309 | | |
310 | 0 | char md_item_name[256]; |
311 | 0 | snprintf(md_item_name, sizeof(md_item_name), "gml_%s_type", property); |
312 | |
|
313 | 0 | const char *type = msLookupHashTable(&(layer->metadata), md_item_name); |
314 | |
|
315 | 0 | return (type != NULL && (EQUAL(type, "Character"))); |
316 | 0 | } |
317 | | |
318 | | /* |
319 | | ** msLayerPropertyIsNumeric() |
320 | | ** |
321 | | ** Check if a field in a layer is numeric - an Integer, Long, or Real |
322 | | */ |
323 | 0 | bool msLayerPropertyIsNumeric(layerObj *layer, const char *property) { |
324 | 0 | if (!property) { |
325 | 0 | return false; |
326 | 0 | } |
327 | | |
328 | 0 | char md_item_name[256]; |
329 | 0 | snprintf(md_item_name, sizeof(md_item_name), "gml_%s_type", property); |
330 | |
|
331 | 0 | const char *type = msLookupHashTable(&(layer->metadata), md_item_name); |
332 | |
|
333 | 0 | return (type != NULL && (EQUAL(type, "Integer") || EQUAL(type, "Long") || |
334 | 0 | EQUAL(type, "Real"))); |
335 | 0 | } |
336 | | |
337 | | /* |
338 | | ** Returns MS_TRUE is a layer supports the common expression/filter syntax (RFC |
339 | | *64) and MS_FALSE otherwise. |
340 | | */ |
341 | 0 | int msLayerSupportsCommonFilters(layerObj *layer) { |
342 | 0 | if (!layer->vtable) { |
343 | 0 | int rv = msInitializeVirtualTable(layer); |
344 | 0 | if (rv != MS_SUCCESS) |
345 | 0 | return rv; |
346 | 0 | } |
347 | 0 | cppcheck_assert(layer->vtable); |
348 | 0 | return layer->vtable->LayerSupportsCommonFilters(layer); |
349 | 0 | } |
350 | | |
351 | | int msLayerTranslateFilter(layerObj *layer, expressionObj *filter, |
352 | 0 | char *filteritem) { |
353 | 0 | if (!layer->vtable) { |
354 | 0 | int rv = msInitializeVirtualTable(layer); |
355 | 0 | if (rv != MS_SUCCESS) |
356 | 0 | return rv; |
357 | 0 | } |
358 | 0 | cppcheck_assert(layer->vtable); |
359 | 0 | return layer->vtable->LayerTranslateFilter(layer, filter, filteritem); |
360 | 0 | } |
361 | | |
362 | | /* |
363 | | ** Performs a spatial, and optionally an attribute based feature search. The |
364 | | *function basically |
365 | | ** prepares things so that candidate features can be accessed by query or |
366 | | *drawing functions. For |
367 | | ** OGR and shapefiles this sets an internal bit vector that indicates whether a |
368 | | *particular feature |
369 | | ** is to processed. For SDE it executes an SQL statement on the SDE server. Once |
370 | | *run the msLayerNextShape |
371 | | ** function should be called to actually access the shapes. |
372 | | ** |
373 | | ** Note that for shapefiles we apply any maxfeatures constraint at this point. |
374 | | *That may be the only |
375 | | ** connection type where this is feasible. |
376 | | */ |
377 | 0 | int msLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { |
378 | 0 | if (!msLayerSupportsCommonFilters(layer)) |
379 | 0 | msLayerTranslateFilter(layer, &layer->filter, layer->filteritem); |
380 | |
|
381 | 0 | if (!layer->vtable) { |
382 | 0 | int rv = msInitializeVirtualTable(layer); |
383 | 0 | if (rv != MS_SUCCESS) |
384 | 0 | return rv; |
385 | 0 | } |
386 | 0 | cppcheck_assert(layer->vtable); |
387 | 0 | return layer->vtable->LayerWhichShapes(layer, rect, isQuery); |
388 | 0 | } |
389 | | |
390 | | /* |
391 | | ** Called after msWhichShapes has been called to actually retrieve shapes within |
392 | | *a given area |
393 | | ** and matching a vendor specific filter (i.e. layer FILTER attribute). |
394 | | ** |
395 | | ** Shapefiles: NULL shapes (shapes with attributes but NO vertices are skipped) |
396 | | */ |
397 | 0 | int msLayerNextShape(layerObj *layer, shapeObj *shape) { |
398 | 0 | int rv, filter_passed; |
399 | |
|
400 | 0 | if (!layer->vtable) { |
401 | 0 | rv = msInitializeVirtualTable(layer); |
402 | 0 | if (rv != MS_SUCCESS) |
403 | 0 | return rv; |
404 | 0 | } |
405 | 0 | cppcheck_assert(layer->vtable); |
406 | |
|
407 | | #ifdef USE_V8_MAPSCRIPT |
408 | | /* we need to force the GetItems for the geomtransform attributes */ |
409 | | if (!layer->items && |
410 | | layer->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION && |
411 | | strstr(layer->_geomtransform.string, "javascript")) |
412 | | msLayerGetItems(layer); |
413 | | #endif |
414 | | |
415 | | /* At the end of switch case (default -> break; -> return MS_FAILURE), |
416 | | * was following TODO ITEM: |
417 | | * |
418 | | * TO DO! This is where dynamic joins will happen. Joined attributes will be |
419 | | * tagged on to the main attributes with the naming scheme [join name].[item |
420 | | * name]. We need to leverage the iteminfo (I think) at this point |
421 | | */ |
422 | | |
423 | | /* RFC 91: MapServer-based filtering is done at a more general level. */ |
424 | 0 | do { |
425 | 0 | rv = layer->vtable->LayerNextShape(layer, shape); |
426 | 0 | if (rv != MS_SUCCESS) |
427 | 0 | return rv; |
428 | | |
429 | | /* attributes need to be iconv'd to UTF-8 before any filter logic is applied |
430 | | */ |
431 | 0 | if (layer->encoding) { |
432 | 0 | rv = msLayerEncodeShapeAttributes(layer, shape); |
433 | 0 | if (rv != MS_SUCCESS) |
434 | 0 | return rv; |
435 | 0 | } |
436 | | |
437 | 0 | filter_passed = msEvalExpression(layer, shape, &(layer->filter), |
438 | 0 | layer->filteritemindex); |
439 | |
|
440 | 0 | if (!filter_passed) |
441 | 0 | msFreeShape(shape); |
442 | 0 | } while (!filter_passed); |
443 | | |
444 | | /* RFC89 Apply Layer GeomTransform */ |
445 | 0 | if (layer->_geomtransform.type != MS_GEOMTRANSFORM_NONE && rv == MS_SUCCESS) { |
446 | 0 | rv = msGeomTransformShape(layer->map, layer, shape); |
447 | 0 | if (rv != MS_SUCCESS) |
448 | 0 | return rv; |
449 | 0 | } |
450 | | |
451 | 0 | return rv; |
452 | 0 | } |
453 | | |
454 | | /* |
455 | | ** Used to retrieve a shape from a result set by index. Result sets are created |
456 | | *by the various |
457 | | ** msQueryBy...() functions. The index is assigned by the data source. |
458 | | */ |
459 | | /* int msLayerResultsGetShape(layerObj *layer, shapeObj *shape, int tile, long |
460 | | record) |
461 | | { |
462 | | if ( ! layer->vtable) { |
463 | | int rv = msInitializeVirtualTable(layer); |
464 | | if (rv != MS_SUCCESS) |
465 | | return rv; |
466 | | } |
467 | | |
468 | | return layer->vtable->LayerResultsGetShape(layer, shape, tile, record); |
469 | | } */ |
470 | | |
471 | | /* |
472 | | ** Used to retrieve a shape by index. All data sources must be capable of random |
473 | | *access using |
474 | | ** a record number(s) of some sort. |
475 | | */ |
476 | 0 | int msLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record) { |
477 | 0 | int rv; |
478 | |
|
479 | 0 | if (!layer->vtable) { |
480 | 0 | rv = msInitializeVirtualTable(layer); |
481 | 0 | if (rv != MS_SUCCESS) |
482 | 0 | return rv; |
483 | 0 | } |
484 | 0 | cppcheck_assert(layer->vtable); |
485 | | |
486 | | /* |
487 | | ** TODO: This is where dynamic joins could happen. Joined attributes would be |
488 | | ** tagged on to the main attributes with the naming scheme [join name].[item |
489 | | *name]. |
490 | | */ |
491 | |
|
492 | 0 | rv = layer->vtable->LayerGetShape(layer, shape, record); |
493 | 0 | if (rv != MS_SUCCESS) |
494 | 0 | return rv; |
495 | | |
496 | | /* RFC89 Apply Layer GeomTransform */ |
497 | 0 | if (layer->_geomtransform.type != MS_GEOMTRANSFORM_NONE) { |
498 | 0 | rv = msGeomTransformShape(layer->map, layer, shape); |
499 | 0 | if (rv != MS_SUCCESS) |
500 | 0 | return rv; |
501 | 0 | } |
502 | | |
503 | 0 | if (layer->encoding) { |
504 | 0 | rv = msLayerEncodeShapeAttributes(layer, shape); |
505 | 0 | if (rv != MS_SUCCESS) |
506 | 0 | return rv; |
507 | 0 | } |
508 | | |
509 | 0 | return rv; |
510 | 0 | } |
511 | | |
512 | | /* |
513 | | ** Returns the number of shapes that match the potential filter and extent. |
514 | | * rectProjection is the projection in which rect is expressed, or can be NULL if |
515 | | * rect should be considered in the layer projection. |
516 | | * This should be equivalent to calling msLayerWhichShapes() and counting the |
517 | | * number of shapes returned by msLayerNextShape(), honouring layer->maxfeatures |
518 | | * limitation if layer->maxfeatures>=0, and honouring layer->startindex if |
519 | | * layer->startindex >= 1 and paging is enabled. |
520 | | * Returns -1 in case of failure. |
521 | | */ |
522 | | int msLayerGetShapeCount(layerObj *layer, rectObj rect, |
523 | 0 | projectionObj *rectProjection) { |
524 | 0 | int rv; |
525 | |
|
526 | 0 | if (!layer->vtable) { |
527 | 0 | rv = msInitializeVirtualTable(layer); |
528 | 0 | if (rv != MS_SUCCESS) |
529 | 0 | return -1; |
530 | 0 | } |
531 | 0 | cppcheck_assert(layer->vtable); |
532 | |
|
533 | 0 | return layer->vtable->LayerGetShapeCount(layer, rect, rectProjection); |
534 | 0 | } |
535 | | |
536 | | /* |
537 | | ** Closes resources used by a particular layer. |
538 | | */ |
539 | 0 | void msLayerClose(layerObj *layer) { |
540 | | /* no need for items once the layer is closed */ |
541 | 0 | msLayerFreeItemInfo(layer); |
542 | 0 | if (layer->items) { |
543 | 0 | msFreeCharArray(layer->items, layer->numitems); |
544 | 0 | layer->items = NULL; |
545 | 0 | layer->numitems = 0; |
546 | 0 | } |
547 | | |
548 | | /* clear out items used as part of expressions (bug #2702) -- what about the |
549 | | * layer filter? */ |
550 | 0 | msLayerFreeExpressions(layer); |
551 | |
|
552 | 0 | if (layer->vtable) { |
553 | 0 | layer->vtable->LayerClose(layer); |
554 | 0 | } |
555 | 0 | msLayerRestoreFromScaletokens(layer); |
556 | 0 | } |
557 | | |
558 | | /* |
559 | | ** Clear out items used as part of expressions. |
560 | | */ |
561 | 0 | void msLayerFreeExpressions(layerObj *layer) { |
562 | 0 | int i, j, k; |
563 | |
|
564 | 0 | msFreeExpressionTokens(&(layer->filter)); |
565 | 0 | msFreeExpressionTokens(&(layer->cluster.group)); |
566 | 0 | msFreeExpressionTokens(&(layer->cluster.filter)); |
567 | 0 | for (i = 0; i < layer->numclasses; i++) { |
568 | 0 | msFreeExpressionTokens(&(layer->class[i] -> expression)); |
569 | 0 | msFreeExpressionTokens(&(layer->class[i] -> text)); |
570 | 0 | for (j = 0; j < layer->class[i] -> numstyles; j++) |
571 | 0 | msFreeExpressionTokens(&(layer->class[i] -> styles[j] -> _geomtransform)); |
572 | 0 | for (k = 0; k < layer->class[i] -> numlabels; k++) { |
573 | 0 | msFreeExpressionTokens(&(layer->class[i] -> labels[k] -> expression)); |
574 | 0 | msFreeExpressionTokens(&(layer->class[i] -> labels[k] -> text)); |
575 | 0 | } |
576 | 0 | } |
577 | 0 | } |
578 | | |
579 | | /* |
580 | | ** Retrieves a list of attributes available for this layer. Most sources also |
581 | | *set the iteminfo array |
582 | | ** at this point. This function is used when processing query results to expose |
583 | | *attributes to query |
584 | | ** templates. At that point all attributes are fair game. |
585 | | */ |
586 | 0 | int msLayerGetItems(layerObj *layer) { |
587 | 0 | const char *itemNames; |
588 | | /* clean up any previously allocated instances */ |
589 | 0 | msLayerFreeItemInfo(layer); |
590 | 0 | if (layer->items) { |
591 | 0 | msFreeCharArray(layer->items, layer->numitems); |
592 | 0 | layer->items = NULL; |
593 | 0 | layer->numitems = 0; |
594 | 0 | } |
595 | |
|
596 | 0 | if (!layer->vtable) { |
597 | 0 | int rv = msInitializeVirtualTable(layer); |
598 | 0 | if (rv != MS_SUCCESS) |
599 | 0 | return rv; |
600 | 0 | } |
601 | 0 | cppcheck_assert(layer->vtable); |
602 | | |
603 | | /* At the end of switch case (default -> break; -> return MS_FAILURE), |
604 | | * was following TODO ITEM: |
605 | | */ |
606 | | /* TO DO! Need to add any joined itemd on to the core layer items, one long |
607 | | * list! */ |
608 | 0 | itemNames = msLayerGetProcessingKey(layer, "ITEMS"); |
609 | 0 | if (itemNames) { |
610 | 0 | layer->items = msStringSplit(itemNames, ',', &layer->numitems); |
611 | | /* populate the iteminfo array */ |
612 | 0 | return (msLayerInitItemInfo(layer)); |
613 | 0 | } else |
614 | 0 | return layer->vtable->LayerGetItems(layer); |
615 | 0 | } |
616 | | |
617 | | /* |
618 | | ** Returns extent of spatial coverage for a layer. |
619 | | ** |
620 | | ** If layer->extent is set then this value is used, otherwise the |
621 | | ** driver-specific implementation is called (this can be expensive). |
622 | | ** |
623 | | ** If layer is not already opened then it is opened and closed (so this |
624 | | ** function can be called on both opened or closed layers). |
625 | | ** |
626 | | ** Returns MS_SUCCESS/MS_FAILURE. |
627 | | */ |
628 | 0 | int msLayerGetExtent(layerObj *layer, rectObj *extent) { |
629 | 0 | int need_to_close = MS_FALSE, status = MS_SUCCESS; |
630 | |
|
631 | 0 | if (MS_VALID_EXTENT(layer->extent)) { |
632 | 0 | *extent = layer->extent; |
633 | 0 | return MS_SUCCESS; |
634 | 0 | } |
635 | | |
636 | 0 | if (!msLayerIsOpen(layer)) { |
637 | 0 | if (msLayerOpen(layer) != MS_SUCCESS) |
638 | 0 | return MS_FAILURE; |
639 | 0 | need_to_close = MS_TRUE; |
640 | 0 | } |
641 | | |
642 | 0 | if (!layer->vtable) { |
643 | 0 | int rv = msInitializeVirtualTable(layer); |
644 | 0 | if (rv != MS_SUCCESS) { |
645 | 0 | if (need_to_close) |
646 | 0 | msLayerClose(layer); |
647 | 0 | return rv; |
648 | 0 | } |
649 | 0 | } |
650 | 0 | cppcheck_assert(layer->vtable); |
651 | 0 | status = layer->vtable->LayerGetExtent(layer, extent); |
652 | |
|
653 | 0 | if (status == MS_SUCCESS) { |
654 | 0 | layer->extent = *extent; |
655 | 0 | } |
656 | |
|
657 | 0 | if (need_to_close) |
658 | 0 | msLayerClose(layer); |
659 | |
|
660 | 0 | return (status); |
661 | 0 | } |
662 | | |
663 | 0 | int msLayerGetItemIndex(layerObj *layer, char *item) { |
664 | 0 | int i; |
665 | |
|
666 | 0 | for (i = 0; i < layer->numitems; i++) { |
667 | 0 | if (strcasecmp(layer->items[i], item) == 0) |
668 | 0 | return (i); |
669 | 0 | } |
670 | | |
671 | 0 | return -1; /* item not found */ |
672 | 0 | } |
673 | | |
674 | 0 | static int string2list(char **list, int *listsize, char *string) { |
675 | 0 | int i; |
676 | |
|
677 | 0 | for (i = 0; i < (*listsize); i++) { |
678 | 0 | if (strcasecmp(list[i], string) == 0) { |
679 | | /* printf("string2list (duplicate): %s %d\n", string, i); */ |
680 | 0 | return (i); |
681 | 0 | } |
682 | 0 | } |
683 | | |
684 | 0 | list[i] = msStrdup(string); |
685 | 0 | (*listsize)++; |
686 | | |
687 | | /* printf("string2list: %s %d\n", string, i); */ |
688 | |
|
689 | 0 | return (i); |
690 | 0 | } |
691 | | |
692 | | extern int msyylex(void); |
693 | | extern int msyylex_destroy(void); |
694 | | |
695 | | extern int msyystate; |
696 | | extern char *msyystring; /* string to tokenize */ |
697 | | |
698 | | extern double msyynumber; /* token containers */ |
699 | | extern char *msyystring_buffer; |
700 | | |
701 | 0 | const char *msExpressionTokenToString(int token) { |
702 | 0 | switch (token) { |
703 | 0 | case '(': |
704 | 0 | return "("; |
705 | 0 | case ')': |
706 | 0 | return ")"; |
707 | 0 | case ',': |
708 | 0 | return ","; |
709 | 0 | case '+': |
710 | 0 | return "+"; |
711 | 0 | case '-': |
712 | 0 | return "-"; |
713 | 0 | case '/': |
714 | 0 | return "/"; |
715 | 0 | case '*': |
716 | 0 | return "*"; |
717 | 0 | case '%': |
718 | 0 | return "%"; |
719 | | |
720 | 0 | case MS_TOKEN_LOGICAL_AND: |
721 | 0 | return " and "; |
722 | 0 | case MS_TOKEN_LOGICAL_OR: |
723 | 0 | return " or "; |
724 | 0 | case MS_TOKEN_LOGICAL_NOT: |
725 | 0 | return " not "; |
726 | | |
727 | 0 | case MS_TOKEN_COMPARISON_EQ: |
728 | 0 | return " = "; |
729 | 0 | case MS_TOKEN_COMPARISON_NE: |
730 | 0 | return " != "; |
731 | 0 | case MS_TOKEN_COMPARISON_GT: |
732 | 0 | return " > "; |
733 | 0 | case MS_TOKEN_COMPARISON_GE: |
734 | 0 | return " >= "; |
735 | 0 | case MS_TOKEN_COMPARISON_LT: |
736 | 0 | return " < "; |
737 | 0 | case MS_TOKEN_COMPARISON_LE: |
738 | 0 | return " <= "; |
739 | 0 | case MS_TOKEN_COMPARISON_IEQ: |
740 | 0 | return ""; |
741 | 0 | case MS_TOKEN_COMPARISON_RE: |
742 | 0 | return " ~ "; |
743 | 0 | case MS_TOKEN_COMPARISON_IRE: |
744 | 0 | return " ~* "; |
745 | 0 | case MS_TOKEN_COMPARISON_IN: |
746 | 0 | return " in "; |
747 | | |
748 | 0 | case MS_TOKEN_COMPARISON_INTERSECTS: |
749 | 0 | return "intersects"; |
750 | 0 | case MS_TOKEN_COMPARISON_DISJOINT: |
751 | 0 | return "disjoint"; |
752 | 0 | case MS_TOKEN_COMPARISON_TOUCHES: |
753 | 0 | return "touches"; |
754 | 0 | case MS_TOKEN_COMPARISON_OVERLAPS: |
755 | 0 | return "overlaps"; |
756 | 0 | case MS_TOKEN_COMPARISON_CROSSES: |
757 | 0 | return "crosses"; |
758 | 0 | case MS_TOKEN_COMPARISON_WITHIN: |
759 | 0 | return "within"; |
760 | 0 | case MS_TOKEN_COMPARISON_CONTAINS: |
761 | 0 | return "contains"; |
762 | 0 | case MS_TOKEN_COMPARISON_EQUALS: |
763 | 0 | return "equals"; |
764 | 0 | case MS_TOKEN_COMPARISON_BEYOND: |
765 | 0 | return "beyond"; |
766 | 0 | case MS_TOKEN_COMPARISON_DWITHIN: |
767 | 0 | return "dwithin"; |
768 | | |
769 | 0 | case MS_TOKEN_FUNCTION_LENGTH: |
770 | 0 | return "length"; |
771 | 0 | case MS_TOKEN_FUNCTION_TOSTRING: |
772 | 0 | return "tostring"; |
773 | 0 | case MS_TOKEN_FUNCTION_COMMIFY: |
774 | 0 | return "commify"; |
775 | 0 | case MS_TOKEN_FUNCTION_AREA: |
776 | 0 | return "area"; |
777 | 0 | case MS_TOKEN_FUNCTION_ROUND: |
778 | 0 | return "round"; |
779 | 0 | case MS_TOKEN_FUNCTION_BUFFER: |
780 | 0 | return "buffer"; |
781 | 0 | case MS_TOKEN_FUNCTION_DIFFERENCE: |
782 | 0 | return "difference"; |
783 | 0 | case MS_TOKEN_FUNCTION_SIMPLIFY: |
784 | 0 | return "simplify"; |
785 | | // case MS_TOKEN_FUNCTION_SIMPLIFYPT: |
786 | 0 | case MS_TOKEN_FUNCTION_GENERALIZE: |
787 | 0 | return "generalize"; |
788 | 0 | default: |
789 | 0 | return NULL; |
790 | 0 | } |
791 | 0 | } |
792 | | |
793 | | int msTokenizeExpression(expressionObj *expression, char **list, |
794 | 0 | int *listsize) { |
795 | 0 | tokenListNodeObjPtr node; |
796 | 0 | int token; |
797 | | |
798 | | /* TODO: make sure the constants can't somehow reference invalid expression |
799 | | * types */ |
800 | | /* if(expression->type != MS_EXPRESSION && expression->type != |
801 | | * MS_GEOMTRANSFORM_EXPRESSION) return MS_SUCCESS; */ |
802 | |
|
803 | 0 | msAcquireLock(TLOCK_PARSER); |
804 | 0 | msyystate = MS_TOKENIZE_EXPRESSION; |
805 | 0 | msyystring = expression->string; /* the thing we're tokenizing */ |
806 | |
|
807 | 0 | while ((token = msyylex()) != |
808 | 0 | 0) { /* keep processing tokens until the end of the string (\0) */ |
809 | |
|
810 | 0 | if ((node = (tokenListNodeObjPtr)malloc(sizeof(tokenListNodeObj))) == |
811 | 0 | NULL) { |
812 | 0 | msSetError(MS_MEMERR, NULL, "msTokenizeExpression()"); |
813 | 0 | goto parse_error; |
814 | 0 | } |
815 | | |
816 | 0 | node->tokensrc = NULL; |
817 | |
|
818 | 0 | node->tailifhead = NULL; |
819 | 0 | node->next = NULL; |
820 | |
|
821 | 0 | switch (token) { |
822 | 0 | case MS_TOKEN_LITERAL_BOOLEAN: |
823 | 0 | case MS_TOKEN_LITERAL_NUMBER: |
824 | 0 | node->token = token; |
825 | 0 | node->tokenval.dblval = msyynumber; |
826 | 0 | break; |
827 | 0 | case MS_TOKEN_LITERAL_STRING: |
828 | 0 | node->token = token; |
829 | 0 | node->tokenval.strval = msStrdup(msyystring_buffer); |
830 | 0 | break; |
831 | 0 | case MS_TOKEN_LITERAL_TIME: |
832 | 0 | node->tokensrc = msStrdup(msyystring_buffer); |
833 | 0 | node->token = token; |
834 | 0 | msTimeInit(&(node->tokenval.tmval)); |
835 | 0 | if (msParseTime(msyystring_buffer, &(node->tokenval.tmval)) != MS_TRUE) { |
836 | 0 | msSetError(MS_PARSEERR, "Parsing time value failed.", |
837 | 0 | "msTokenizeExpression()"); |
838 | 0 | free(node); |
839 | 0 | goto parse_error; |
840 | 0 | } |
841 | 0 | break; |
842 | 0 | case MS_TOKEN_BINDING_DOUBLE: /* we've encountered an attribute (binding) |
843 | | reference */ |
844 | 0 | case MS_TOKEN_BINDING_INTEGER: |
845 | 0 | case MS_TOKEN_BINDING_STRING: |
846 | 0 | case MS_TOKEN_BINDING_TIME: |
847 | 0 | node->token = token; /* binding type */ |
848 | 0 | node->tokenval.bindval.item = msStrdup(msyystring_buffer); |
849 | 0 | if (list) |
850 | 0 | node->tokenval.bindval.index = |
851 | 0 | string2list(list, listsize, msyystring_buffer); |
852 | 0 | break; |
853 | 0 | case MS_TOKEN_BINDING_SHAPE: |
854 | 0 | node->token = token; |
855 | 0 | break; |
856 | 0 | case MS_TOKEN_BINDING_MAP_CELLSIZE: |
857 | 0 | node->token = token; |
858 | 0 | break; |
859 | 0 | case MS_TOKEN_BINDING_DATA_CELLSIZE: |
860 | 0 | node->token = token; |
861 | 0 | break; |
862 | 0 | case MS_TOKEN_FUNCTION_FROMTEXT: /* we want to process a shape from WKT once |
863 | | and not for every feature being |
864 | | evaluated */ |
865 | 0 | if ((token = msyylex()) != 40) { /* ( */ |
866 | 0 | msSetError(MS_PARSEERR, "Parsing fromText function failed.", |
867 | 0 | "msTokenizeExpression()"); |
868 | 0 | free(node); |
869 | 0 | goto parse_error; |
870 | 0 | } |
871 | | |
872 | 0 | if ((token = msyylex()) != MS_TOKEN_LITERAL_STRING) { |
873 | 0 | msSetError(MS_PARSEERR, "Parsing fromText function failed.", |
874 | 0 | "msTokenizeExpression()"); |
875 | 0 | free(node); |
876 | 0 | goto parse_error; |
877 | 0 | } |
878 | | |
879 | 0 | node->token = MS_TOKEN_LITERAL_SHAPE; |
880 | 0 | node->tokenval.shpval = msShapeFromWKT(msyystring_buffer); |
881 | |
|
882 | 0 | if (!node->tokenval.shpval) { |
883 | 0 | msSetError(MS_PARSEERR, |
884 | 0 | "Parsing fromText function failed, WKT processing failed.", |
885 | 0 | "msTokenizeExpression()"); |
886 | 0 | free(node); |
887 | 0 | goto parse_error; |
888 | 0 | } |
889 | | |
890 | | /* todo: perhaps process optional args (e.g. projection) */ |
891 | | |
892 | 0 | if ((token = msyylex()) != 41) { /* ) */ |
893 | 0 | msSetError(MS_PARSEERR, "Parsing fromText function failed.", |
894 | 0 | "msTokenizeExpression()"); |
895 | 0 | msFreeShape(node->tokenval.shpval); |
896 | 0 | free(node->tokenval.shpval); |
897 | 0 | free(node); |
898 | 0 | goto parse_error; |
899 | 0 | } |
900 | 0 | break; |
901 | 0 | default: |
902 | 0 | node->token = token; /* for everything else */ |
903 | 0 | break; |
904 | 0 | } |
905 | | |
906 | | /* add node to token list */ |
907 | 0 | if (expression->tokens == NULL) { |
908 | 0 | expression->tokens = node; |
909 | 0 | } else { |
910 | 0 | if (expression->tokens->tailifhead != |
911 | 0 | NULL) /* this should never be NULL, but just in case */ |
912 | 0 | expression->tokens->tailifhead->next = |
913 | 0 | node; /* put the node at the end of the list */ |
914 | 0 | } |
915 | | |
916 | | /* repoint the head of the list to the end - our new element |
917 | | this causes a loop if we are at the head, be careful not to |
918 | | walk in a loop */ |
919 | 0 | expression->tokens->tailifhead = node; |
920 | 0 | } |
921 | | |
922 | 0 | expression->curtoken = expression->tokens; /* point at the first token */ |
923 | |
|
924 | 0 | msReleaseLock(TLOCK_PARSER); |
925 | 0 | return MS_SUCCESS; |
926 | | |
927 | 0 | parse_error: |
928 | 0 | msReleaseLock(TLOCK_PARSER); |
929 | 0 | return MS_FAILURE; |
930 | 0 | } |
931 | | |
932 | 0 | static void buildLayerItemList(layerObj *layer) { |
933 | 0 | int i, j, k, l; |
934 | | /* |
935 | | ** build layer item list, compute item indexes for explicitly item references |
936 | | *(e.g. classitem) or item bindings |
937 | | */ |
938 | | |
939 | | /* layer items */ |
940 | 0 | if (layer->classitem) |
941 | 0 | layer->classitemindex = |
942 | 0 | string2list(layer->items, &(layer->numitems), layer->classitem); |
943 | 0 | if (layer->filteritem) |
944 | 0 | layer->filteritemindex = |
945 | 0 | string2list(layer->items, &(layer->numitems), layer->filteritem); |
946 | 0 | if (layer->styleitem && (strcasecmp(layer->styleitem, "AUTO") != 0) && |
947 | 0 | !STARTS_WITH_CI(layer->styleitem, "javascript://") && |
948 | 0 | !STARTS_WITH_CI(layer->styleitem, "sld://")) |
949 | 0 | layer->styleitemindex = |
950 | 0 | string2list(layer->items, &(layer->numitems), layer->styleitem); |
951 | 0 | if (layer->labelitem) |
952 | 0 | layer->labelitemindex = |
953 | 0 | string2list(layer->items, &(layer->numitems), layer->labelitem); |
954 | 0 | if (layer->utfitem) |
955 | 0 | layer->utfitemindex = |
956 | 0 | string2list(layer->items, &(layer->numitems), layer->utfitem); |
957 | | |
958 | | /* layer classes */ |
959 | 0 | for (i = 0; i < layer->numclasses; i++) { |
960 | | |
961 | | // if classgroup has been set we can ignore any fields required |
962 | | // for rendering unused classes |
963 | 0 | if (layer->class[i] -> group && layer -> classgroup &&strcasecmp( |
964 | 0 | layer->class[i] -> group, |
965 | 0 | layer -> classgroup) != 0) |
966 | 0 | continue; |
967 | | |
968 | 0 | if (layer->class[i] -> expression.type == |
969 | 0 | MS_EXPRESSION) /* class expression */ |
970 | 0 | msTokenizeExpression(&(layer->class[i] -> expression), layer->items, |
971 | 0 | &(layer->numitems)); |
972 | | |
973 | | /* class styles (items, bindings, geomtransform) */ |
974 | 0 | for (j = 0; j < layer->class[i] -> numstyles; j++) { |
975 | 0 | if (layer->class[i] -> styles[j] -> rangeitem) |
976 | 0 | layer->class[i]->styles[j]->rangeitemindex = |
977 | 0 | string2list(layer->items, &(layer->numitems), |
978 | 0 | layer->class[i] -> styles[j] -> rangeitem); |
979 | 0 | for (k = 0; k < MS_STYLE_BINDING_LENGTH; k++) { |
980 | 0 | if (layer->class[i] -> styles[j] -> bindings[k].item) |
981 | 0 | layer->class[i]->styles[j]->bindings[k].index = |
982 | 0 | string2list(layer->items, &(layer->numitems), |
983 | 0 | layer->class[i] -> styles[j] -> bindings[k].item); |
984 | 0 | if (layer->class[i] -> styles[j] -> exprBindings[k].type == |
985 | 0 | MS_EXPRESSION) { |
986 | 0 | msTokenizeExpression( |
987 | 0 | &(layer->class[i] -> styles[j] -> exprBindings[k]), layer->items, |
988 | 0 | &(layer->numitems)); |
989 | 0 | } |
990 | 0 | } |
991 | 0 | if (layer->class[i] -> styles[j] -> _geomtransform.type == |
992 | 0 | MS_GEOMTRANSFORM_EXPRESSION) |
993 | 0 | msTokenizeExpression(&(layer->class[i] -> styles[j] -> _geomtransform), |
994 | 0 | layer->items, &(layer->numitems)); |
995 | 0 | } |
996 | | |
997 | | /* class labels and label styles (items, bindings, geomtransform) */ |
998 | 0 | for (l = 0; l < layer->class[i] -> numlabels; l++) { |
999 | 0 | for (j = 0; j < layer->class[i] -> labels[l] -> numstyles; j++) { |
1000 | 0 | if (layer->class[i] -> labels[l] -> styles[j] -> rangeitem) |
1001 | 0 | layer->class[i]->labels[l]->styles[j]->rangeitemindex = string2list( |
1002 | 0 | layer->items, &(layer->numitems), |
1003 | 0 | layer->class[i] -> labels[l] -> styles[j] -> rangeitem); |
1004 | 0 | for (k = 0; k < MS_STYLE_BINDING_LENGTH; k++) { |
1005 | 0 | if (layer->class[i] -> labels[l] -> styles[j] -> bindings[k].item) |
1006 | 0 | layer->class[i]->labels[l]->styles[j]->bindings[k].index = |
1007 | 0 | string2list(layer->items, &(layer->numitems), |
1008 | 0 | layer->class[i] -> labels[l] -> styles[j] |
1009 | 0 | -> bindings[k].item); |
1010 | 0 | if (layer->class[i] -> labels[l] -> styles[j] |
1011 | 0 | -> _geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) |
1012 | 0 | msTokenizeExpression( |
1013 | 0 | &(layer->class[i] -> labels[l] -> styles[j] -> _geomtransform), |
1014 | 0 | layer->items, &(layer->numitems)); |
1015 | 0 | } |
1016 | 0 | } |
1017 | 0 | for (k = 0; k < MS_LABEL_BINDING_LENGTH; k++) { |
1018 | 0 | if (layer->class[i] -> labels[l] -> bindings[k].item) |
1019 | 0 | layer->class[i]->labels[l]->bindings[k].index = |
1020 | 0 | string2list(layer->items, &(layer->numitems), |
1021 | 0 | layer->class[i] -> labels[l] -> bindings[k].item); |
1022 | 0 | if (layer->class[i] -> labels[l] -> exprBindings[k].type == |
1023 | 0 | MS_EXPRESSION) { |
1024 | 0 | msTokenizeExpression( |
1025 | 0 | &(layer->class[i] -> labels[l] -> exprBindings[k]), layer->items, |
1026 | 0 | &(layer->numitems)); |
1027 | 0 | } |
1028 | 0 | } |
1029 | | |
1030 | | /* label expression */ |
1031 | 0 | if (layer->class[i] -> labels[l] -> expression.type == MS_EXPRESSION) |
1032 | 0 | msTokenizeExpression(&(layer->class[i] -> labels[l] -> expression), |
1033 | 0 | layer->items, &(layer->numitems)); |
1034 | | |
1035 | | /* label text */ |
1036 | 0 | if (layer->class[i] -> labels[l] |
1037 | 0 | -> text.type == MS_EXPRESSION || |
1038 | 0 | (layer->class[i] -> labels[l] |
1039 | 0 | -> text.string &&strchr( |
1040 | 0 | layer->class[i] -> labels[l] -> text.string, '[') != |
1041 | 0 | NULL && |
1042 | 0 | strchr(layer->class[i] -> labels[l] -> text.string, |
1043 | 0 | ']') != NULL)) |
1044 | 0 | msTokenizeExpression(&(layer->class[i] -> labels[l] -> text), |
1045 | 0 | layer->items, &(layer->numitems)); |
1046 | 0 | } |
1047 | | |
1048 | | /* class text */ |
1049 | 0 | if (layer->class[i] |
1050 | 0 | -> text.type == MS_EXPRESSION || |
1051 | 0 | (layer->class[i] |
1052 | 0 | -> text.string &&strchr(layer->class[i] -> text.string, '[') != |
1053 | 0 | NULL && |
1054 | 0 | strchr(layer->class[i] -> text.string, ']') != NULL)) |
1055 | 0 | msTokenizeExpression(&(layer->class[i] -> text), layer->items, |
1056 | 0 | &(layer->numitems)); |
1057 | 0 | } |
1058 | | |
1059 | | /* layer filter */ |
1060 | 0 | if (layer->filter.type == MS_EXPRESSION) |
1061 | 0 | msTokenizeExpression(&(layer->filter), layer->items, &(layer->numitems)); |
1062 | | |
1063 | | /* cluster expressions */ |
1064 | 0 | if (layer->cluster.group.type == MS_EXPRESSION) |
1065 | 0 | msTokenizeExpression(&(layer->cluster.group), layer->items, |
1066 | 0 | &(layer->numitems)); |
1067 | 0 | if (layer->cluster.filter.type == MS_EXPRESSION) |
1068 | 0 | msTokenizeExpression(&(layer->cluster.filter), layer->items, |
1069 | 0 | &(layer->numitems)); |
1070 | | |
1071 | | /* utfdata */ |
1072 | 0 | if (layer->utfdata.type == MS_EXPRESSION || |
1073 | 0 | (layer->utfdata.string && strchr(layer->utfdata.string, '[') != NULL && |
1074 | 0 | strchr(layer->utfdata.string, ']') != NULL)) { |
1075 | 0 | msTokenizeExpression(&(layer->utfdata), layer->items, &(layer->numitems)); |
1076 | 0 | } |
1077 | 0 | } |
1078 | | |
1079 | | /* |
1080 | | ** This function builds a list of items necessary to draw or query a particular |
1081 | | *layer by |
1082 | | ** examining the contents of the various xxxxitem parameters and expressions. |
1083 | | *That list is |
1084 | | ** then used to set the iteminfo variable. |
1085 | | */ |
1086 | 0 | int msLayerWhichItems(layerObj *layer, int get_all, const char *metadata) { |
1087 | 0 | int i, j, k, l, rv; |
1088 | 0 | int nt = 0; |
1089 | |
|
1090 | 0 | if (!layer->vtable) { |
1091 | 0 | rv = msInitializeVirtualTable(layer); |
1092 | 0 | if (rv != MS_SUCCESS) |
1093 | 0 | return rv; |
1094 | 0 | } |
1095 | 0 | cppcheck_assert(layer->vtable); |
1096 | | |
1097 | | /* Cleanup any previous item selection */ |
1098 | 0 | msLayerFreeItemInfo(layer); |
1099 | 0 | if (layer->items) { |
1100 | 0 | msFreeCharArray(layer->items, layer->numitems); |
1101 | 0 | layer->items = NULL; |
1102 | 0 | layer->numitems = 0; |
1103 | 0 | } |
1104 | | |
1105 | | /* |
1106 | | ** need a count of potential items/attributes needed |
1107 | | */ |
1108 | | |
1109 | | /* layer level counts */ |
1110 | 0 | layer->classitemindex = -1; |
1111 | 0 | layer->filteritemindex = -1; |
1112 | 0 | layer->styleitemindex = -1; |
1113 | 0 | layer->labelitemindex = -1; |
1114 | 0 | layer->utfitemindex = -1; |
1115 | |
|
1116 | 0 | if (layer->classitem) |
1117 | 0 | nt++; |
1118 | 0 | if (layer->filteritem) |
1119 | 0 | nt++; |
1120 | 0 | if (layer->styleitem && (strcasecmp(layer->styleitem, "AUTO") != 0) && |
1121 | 0 | !STARTS_WITH_CI(layer->styleitem, "javascript://") && |
1122 | 0 | !STARTS_WITH_CI(layer->styleitem, "sld://")) |
1123 | 0 | nt++; |
1124 | |
|
1125 | 0 | if (layer->filter.type == MS_EXPRESSION) |
1126 | 0 | nt += msCountChars(layer->filter.string, '['); |
1127 | |
|
1128 | 0 | if (layer->cluster.group.type == MS_EXPRESSION) |
1129 | 0 | nt += msCountChars(layer->cluster.group.string, '['); |
1130 | |
|
1131 | 0 | if (layer->cluster.filter.type == MS_EXPRESSION) |
1132 | 0 | nt += msCountChars(layer->cluster.filter.string, '['); |
1133 | |
|
1134 | 0 | if (layer->labelitem) |
1135 | 0 | nt++; |
1136 | 0 | if (layer->utfitem) |
1137 | 0 | nt++; |
1138 | |
|
1139 | 0 | if (layer->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) |
1140 | 0 | msTokenizeExpression(&layer->_geomtransform, layer->items, |
1141 | 0 | &(layer->numitems)); |
1142 | | |
1143 | | /* class level counts */ |
1144 | 0 | for (i = 0; i < layer->numclasses; i++) { |
1145 | |
|
1146 | 0 | for (j = 0; j < layer->class[i] -> numstyles; j++) { |
1147 | 0 | if (layer->class[i] -> styles[j] -> rangeitem) |
1148 | 0 | nt++; |
1149 | 0 | nt += layer->class[i]->styles[j]->numbindings; |
1150 | 0 | if (layer->class[i] -> styles[j] -> _geomtransform.type == |
1151 | 0 | MS_GEOMTRANSFORM_EXPRESSION) |
1152 | 0 | nt += msCountChars( |
1153 | 0 | layer->class[i] -> styles[j] -> _geomtransform.string, '['); |
1154 | 0 | for (k = 0; k < MS_STYLE_BINDING_LENGTH; k++) { |
1155 | 0 | if (layer->class[i] -> styles[j] -> exprBindings[k].type == |
1156 | 0 | MS_EXPRESSION) { |
1157 | 0 | nt += msCountChars( |
1158 | 0 | layer->class[i] -> styles[j] -> exprBindings[k].string, '['); |
1159 | 0 | } |
1160 | 0 | } |
1161 | 0 | } |
1162 | |
|
1163 | 0 | if (layer->class[i] -> expression.type == MS_EXPRESSION) |
1164 | 0 | nt += msCountChars(layer->class[i] -> expression.string, '['); |
1165 | |
|
1166 | 0 | for (l = 0; l < layer->class[i] -> numlabels; l++) { |
1167 | 0 | nt += layer->class[i]->labels[l]->numbindings; |
1168 | 0 | for (j = 0; j < layer->class[i] -> labels[l] -> numstyles; j++) { |
1169 | 0 | if (layer->class[i] -> labels[l] -> styles[j] -> rangeitem) |
1170 | 0 | nt++; |
1171 | 0 | nt += layer->class[i]->labels[l]->styles[j]->numbindings; |
1172 | 0 | if (layer->class[i] -> labels[l] -> styles[j] |
1173 | 0 | -> _geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) |
1174 | 0 | nt += msCountChars(layer->class[i] -> labels[l] -> styles[j] |
1175 | 0 | -> _geomtransform.string, |
1176 | 0 | '['); |
1177 | 0 | } |
1178 | 0 | for (k = 0; k < MS_LABEL_BINDING_LENGTH; k++) { |
1179 | 0 | if (layer->class[i] -> labels[l] -> exprBindings[k].type == |
1180 | 0 | MS_EXPRESSION) { |
1181 | 0 | nt += msCountChars( |
1182 | 0 | layer->class[i] -> labels[l] -> exprBindings[k].string, '['); |
1183 | 0 | } |
1184 | 0 | } |
1185 | |
|
1186 | 0 | if (layer->class[i] -> labels[l] -> expression.type == MS_EXPRESSION) |
1187 | 0 | nt += msCountChars(layer->class[i] -> labels[l] -> expression.string, |
1188 | 0 | '['); |
1189 | 0 | if (layer->class[i] -> labels[l] |
1190 | 0 | -> text.type == MS_EXPRESSION || |
1191 | 0 | (layer->class[i] -> labels[l] |
1192 | 0 | -> text.string &&strchr( |
1193 | 0 | layer->class[i] -> labels[l] -> text.string, '[') != |
1194 | 0 | NULL && |
1195 | 0 | strchr(layer->class[i] -> labels[l] -> text.string, |
1196 | 0 | ']') != NULL)) |
1197 | 0 | nt += msCountChars(layer->class[i] -> labels[l] -> text.string, '['); |
1198 | 0 | } |
1199 | |
|
1200 | 0 | if (layer->class[i] |
1201 | 0 | -> text.type == MS_EXPRESSION || |
1202 | 0 | (layer->class[i] |
1203 | 0 | -> text.string &&strchr(layer->class[i] -> text.string, '[') != |
1204 | 0 | NULL && |
1205 | 0 | strchr(layer->class[i] -> text.string, ']') != NULL)) |
1206 | 0 | nt += msCountChars(layer->class[i] -> text.string, '['); |
1207 | 0 | } |
1208 | | |
1209 | | /* utfgrid count */ |
1210 | 0 | if (layer->utfdata.type == MS_EXPRESSION || |
1211 | 0 | (layer->utfdata.string && strchr(layer->utfdata.string, '[') != NULL && |
1212 | 0 | strchr(layer->utfdata.string, ']') != NULL)) |
1213 | 0 | nt += msCountChars(layer->utfdata.string, '['); |
1214 | | |
1215 | | // if we are using a GetMap request with a WMS filter we don't need to return |
1216 | | // all items |
1217 | 0 | if (msOWSLookupMetadata(&(layer->metadata), "G", "wmsfilter_flag") != NULL) { |
1218 | 0 | get_all = MS_FALSE; |
1219 | 0 | } |
1220 | |
|
1221 | 0 | if (metadata == NULL) { |
1222 | | // check item set by mapwfs.cpp to restrict the number of columns selected |
1223 | 0 | metadata = msOWSLookupMetadata(&(layer->metadata), "G", "select_items"); |
1224 | 0 | if (metadata) { |
1225 | | /* get only selected items */ |
1226 | 0 | get_all = MS_FALSE; |
1227 | 0 | } |
1228 | 0 | } |
1229 | | |
1230 | | /* always retrieve all items in some cases */ |
1231 | 0 | if (layer->connectiontype == MS_INLINE || |
1232 | 0 | (layer->map->outputformat && |
1233 | 0 | layer->map->outputformat->renderer == MS_RENDER_WITH_KML)) { |
1234 | 0 | get_all = MS_TRUE; |
1235 | 0 | } |
1236 | | |
1237 | | /* |
1238 | | ** allocate space for the item list (worse case size) |
1239 | | */ |
1240 | 0 | if (get_all) { |
1241 | 0 | rv = msLayerGetItems(layer); |
1242 | 0 | if (nt > 0) /* need to realloc the array to accept the possible new items*/ |
1243 | 0 | layer->items = (char **)msSmallRealloc( |
1244 | 0 | layer->items, sizeof(char *) * (layer->numitems + nt)); |
1245 | 0 | } else { |
1246 | 0 | rv = layer->vtable->LayerCreateItems(layer, nt); |
1247 | 0 | } |
1248 | 0 | if (rv != MS_SUCCESS) |
1249 | 0 | return rv; |
1250 | | |
1251 | 0 | buildLayerItemList(layer); |
1252 | |
|
1253 | 0 | if (metadata) { |
1254 | 0 | char **tokens; |
1255 | 0 | int n = 0; |
1256 | 0 | int j; |
1257 | |
|
1258 | 0 | tokens = msStringSplit(metadata, ',', &n); |
1259 | 0 | if (tokens) { |
1260 | 0 | for (i = 0; i < n; i++) { |
1261 | 0 | int bFound = 0; |
1262 | 0 | for (j = 0; j < layer->numitems; j++) { |
1263 | 0 | if (strcasecmp(tokens[i], layer->items[j]) == 0) { |
1264 | 0 | bFound = 1; |
1265 | 0 | break; |
1266 | 0 | } |
1267 | 0 | } |
1268 | |
|
1269 | 0 | if (!bFound) { |
1270 | 0 | layer->numitems++; |
1271 | 0 | layer->items = (char **)msSmallRealloc( |
1272 | 0 | layer->items, sizeof(char *) * (layer->numitems)); |
1273 | 0 | layer->items[layer->numitems - 1] = msStrdup(tokens[i]); |
1274 | 0 | } |
1275 | 0 | } |
1276 | 0 | msFreeCharArray(tokens, n); |
1277 | 0 | } |
1278 | | |
1279 | | /* If we didn't retrieve all items of the layer, then do it, so that the */ |
1280 | | /* order of the layer->items array is consistent with it. This is */ |
1281 | | /* important so that WFS DescribeFeatureType and GetFeature requests */ |
1282 | | /* return items in the same order */ |
1283 | 0 | if (!get_all && layer->numitems) { |
1284 | 0 | char **unsorted_items = layer->items; |
1285 | 0 | int numitems = layer->numitems; |
1286 | | |
1287 | | /* Retrieve all items */ |
1288 | 0 | layer->items = NULL; |
1289 | 0 | layer->numitems = 0; |
1290 | 0 | rv = msLayerGetItems(layer); |
1291 | 0 | if (rv != MS_SUCCESS) { |
1292 | 0 | msFreeCharArray(unsorted_items, numitems); |
1293 | 0 | return rv; |
1294 | 0 | } |
1295 | | |
1296 | | /* Sort unsorted_items in the order of layer->items */ |
1297 | 0 | char **sorted_items = (char **)msSmallMalloc(sizeof(char *) * numitems); |
1298 | 0 | int num_sorted_items = 0; |
1299 | 0 | for (i = 0; i < layer->numitems; i++) { |
1300 | 0 | if (layer->items[i]) { |
1301 | 0 | for (j = 0; j < numitems; j++) { |
1302 | 0 | if (unsorted_items[j] && |
1303 | 0 | strcasecmp(layer->items[i], unsorted_items[j]) == 0) { |
1304 | 0 | sorted_items[num_sorted_items] = layer->items[i]; |
1305 | 0 | num_sorted_items++; |
1306 | |
|
1307 | 0 | layer->items[i] = NULL; |
1308 | 0 | msFree(unsorted_items[j]); |
1309 | 0 | unsorted_items[j] = NULL; |
1310 | 0 | break; |
1311 | 0 | } |
1312 | 0 | } |
1313 | 0 | } |
1314 | 0 | } |
1315 | | |
1316 | | /* Add items that are not returned by msLayerGetItems() (not sure if that |
1317 | | * can happen) */ |
1318 | 0 | for (j = 0; j < numitems; j++) { |
1319 | 0 | if (unsorted_items[j]) { |
1320 | 0 | sorted_items[num_sorted_items] = unsorted_items[j]; |
1321 | 0 | num_sorted_items++; |
1322 | 0 | } |
1323 | 0 | } |
1324 | |
|
1325 | 0 | if (layer->numitems > 0) { |
1326 | 0 | msFreeCharArray(layer->items, layer->numitems); |
1327 | 0 | } |
1328 | 0 | msFreeCharArray(unsorted_items, numitems); |
1329 | |
|
1330 | 0 | layer->items = sorted_items; |
1331 | 0 | layer->numitems = numitems; |
1332 | | |
1333 | | /* Re-run buildLayerItemList() with the now correctly sorted items */ |
1334 | 0 | buildLayerItemList(layer); |
1335 | 0 | } |
1336 | 0 | } |
1337 | | |
1338 | | /* populate the iteminfo array */ |
1339 | 0 | if (layer->numitems == 0) |
1340 | 0 | return (MS_SUCCESS); |
1341 | | |
1342 | 0 | return (msLayerInitItemInfo(layer)); |
1343 | 0 | } |
1344 | | |
1345 | | /* |
1346 | | ** A helper function to set the items to be retrieved with a particular shape. |
1347 | | *Unused at the moment but will be used |
1348 | | ** from within MapScript. Should not need modification. |
1349 | | */ |
1350 | 0 | int msLayerSetItems(layerObj *layer, char **items, int numitems) { |
1351 | 0 | int i; |
1352 | | /* Cleanup any previous item selection */ |
1353 | 0 | msLayerFreeItemInfo(layer); |
1354 | 0 | if (layer->items) { |
1355 | 0 | msFreeCharArray(layer->items, layer->numitems); |
1356 | 0 | layer->items = NULL; |
1357 | 0 | layer->numitems = 0; |
1358 | 0 | } |
1359 | | |
1360 | | /* now allocate and set the layer item parameters */ |
1361 | 0 | layer->items = (char **)malloc(sizeof(char *) * numitems); |
1362 | 0 | MS_CHECK_ALLOC(layer->items, sizeof(char *) * numitems, MS_FAILURE); |
1363 | |
|
1364 | 0 | for (i = 0; i < numitems; i++) |
1365 | 0 | layer->items[i] = msStrdup(items[i]); |
1366 | 0 | layer->numitems = numitems; |
1367 | | |
1368 | | /* populate the iteminfo array */ |
1369 | 0 | return (msLayerInitItemInfo(layer)); |
1370 | 0 | } |
1371 | | |
1372 | | /* |
1373 | | ** Fills a classObj with style info from the specified shape. This is used |
1374 | | ** with STYLEITEM AUTO when rendering shapes. |
1375 | | ** For optimal results, this should be called immediately after |
1376 | | ** GetNextShape() or GetShape() so that the shape doesn't have to be read |
1377 | | ** twice. |
1378 | | ** |
1379 | | */ |
1380 | | int msLayerGetAutoStyle(mapObj *map, layerObj *layer, classObj *c, |
1381 | 0 | shapeObj *shape) { |
1382 | 0 | if (!layer->vtable) { |
1383 | 0 | int rv = msInitializeVirtualTable(layer); |
1384 | 0 | if (rv != MS_SUCCESS) |
1385 | 0 | return rv; |
1386 | 0 | } |
1387 | 0 | cppcheck_assert(layer->vtable); |
1388 | 0 | return layer->vtable->LayerGetAutoStyle(map, layer, c, shape); |
1389 | 0 | } |
1390 | | |
1391 | | /* |
1392 | | ** Fills a classObj with style info from the specified attribute. This is used |
1393 | | ** with STYLEITEM "attribute" when rendering shapes. |
1394 | | ** |
1395 | | */ |
1396 | | int msLayerGetFeatureStyle(mapObj *map, layerObj *layer, classObj *c, |
1397 | 0 | shapeObj *shape) { |
1398 | 0 | char *stylestring = NULL; |
1399 | 0 | if (layer->styleitem && layer->styleitemindex >= 0) { |
1400 | 0 | stylestring = msStrdup(shape->values[layer->styleitemindex]); |
1401 | 0 | } else if (layer->styleitem && |
1402 | 0 | strncasecmp(layer->styleitem, "javascript://", 13) == 0) { |
1403 | | #ifdef USE_V8_MAPSCRIPT |
1404 | | char *filename = layer->styleitem + 13; |
1405 | | |
1406 | | if (!map->v8context) { |
1407 | | msV8CreateContext(map); |
1408 | | if (!map->v8context) { |
1409 | | msSetError(MS_V8ERR, "Unable to create v8 context.", |
1410 | | "msLayerGetFeatureStyle()"); |
1411 | | return MS_FAILURE; |
1412 | | } |
1413 | | } |
1414 | | |
1415 | | if (*filename == '\0') { |
1416 | | msSetError(MS_V8ERR, "Invalid javascript filename: \"%s\".", |
1417 | | "msLayerGetFeatureStyle()", layer->styleitem); |
1418 | | return MS_FAILURE; |
1419 | | } |
1420 | | |
1421 | | stylestring = msV8GetFeatureStyle(map, filename, layer, shape); |
1422 | | #else |
1423 | 0 | msSetError(MS_V8ERR, "V8 Javascript support is not available.", |
1424 | 0 | "msLayerGetFeatureStyle()"); |
1425 | 0 | return MS_FAILURE; |
1426 | 0 | #endif |
1427 | 0 | } else if (layer->styleitem && STARTS_WITH_CI(layer->styleitem, "sld://")) { |
1428 | | // ignore the SLD styleitem |
1429 | 0 | return MS_SUCCESS; |
1430 | 0 | } else { /* unknown styleitem */ |
1431 | 0 | return MS_FAILURE; |
1432 | 0 | } |
1433 | | |
1434 | | /* try to find out the current style format */ |
1435 | 0 | if (!stylestring) |
1436 | 0 | return MS_FAILURE; |
1437 | | |
1438 | 0 | if (strncasecmp(stylestring, "style", 5) == 0) { |
1439 | 0 | resetClassStyle(c); |
1440 | 0 | c->layer = layer; |
1441 | 0 | if (msMaybeAllocateClassStyle(c, 0)) { |
1442 | 0 | free(stylestring); |
1443 | 0 | return (MS_FAILURE); |
1444 | 0 | } |
1445 | | |
1446 | 0 | msUpdateStyleFromString(c->styles[0], stylestring); |
1447 | 0 | double geo_cellsize = msGetGeoCellSize(map); |
1448 | 0 | msUpdateClassScaleFactor(geo_cellsize, map, layer, c); |
1449 | |
|
1450 | 0 | if (c->styles[0]->symbolname) { |
1451 | 0 | if ((c->styles[0]->symbol = msGetSymbolIndex( |
1452 | 0 | &(map->symbolset), c->styles[0]->symbolname, MS_TRUE)) == -1) { |
1453 | 0 | msSetError(MS_MISCERR, "Undefined symbol \"%s\" in class of layer %s.", |
1454 | 0 | "msLayerGetFeatureStyle()", c->styles[0]->symbolname, |
1455 | 0 | layer->name); |
1456 | 0 | free(stylestring); |
1457 | 0 | return MS_FAILURE; |
1458 | 0 | } |
1459 | 0 | } |
1460 | 0 | } else if (strncasecmp(stylestring, "class", 5) == 0) { |
1461 | 0 | if (strcasestr(stylestring, " style ") != NULL) { |
1462 | | /* reset style if stylestring contains style definitions */ |
1463 | 0 | resetClassStyle(c); |
1464 | 0 | c->layer = layer; |
1465 | 0 | } |
1466 | 0 | msUpdateClassFromString(c, stylestring); |
1467 | 0 | double geo_cellsize = msGetGeoCellSize(map); |
1468 | 0 | msUpdateClassScaleFactor(geo_cellsize, map, layer, c); |
1469 | 0 | } else if (strncasecmp(stylestring, "pen", 3) == 0 || |
1470 | 0 | strncasecmp(stylestring, "brush", 5) == 0 || |
1471 | 0 | strncasecmp(stylestring, "symbol", 6) == 0 || |
1472 | 0 | strncasecmp(stylestring, "label", 5) == 0) { |
1473 | 0 | msOGRUpdateStyleFromString(map, layer, c, stylestring); |
1474 | 0 | } else if (strcasestr(stylestring, "StyledLayerDescriptor>") != NULL) { |
1475 | | // check for the closing tag of an SLD document </StyledLayerDescriptor> or |
1476 | | // with a namespace e.g. </sld:StyledLayerDescriptor> |
1477 | 0 | msSLDApplySLD(map, stylestring, layer->index, NULL, NULL); |
1478 | 0 | } else { |
1479 | 0 | resetClassStyle(c); |
1480 | 0 | } |
1481 | | |
1482 | 0 | free(stylestring); |
1483 | 0 | return MS_SUCCESS; |
1484 | 0 | } |
1485 | | |
1486 | | /* |
1487 | | Returns the number of inline feature of a layer |
1488 | | */ |
1489 | 0 | int msLayerGetNumFeatures(layerObj *layer) { |
1490 | 0 | int need_to_close = MS_FALSE, result = -1; |
1491 | |
|
1492 | 0 | if (!msLayerIsOpen(layer)) { |
1493 | 0 | if (msLayerOpen(layer) != MS_SUCCESS) |
1494 | 0 | return result; |
1495 | 0 | need_to_close = MS_TRUE; |
1496 | 0 | } |
1497 | | |
1498 | 0 | if (!layer->vtable) { |
1499 | 0 | int rv = msInitializeVirtualTable(layer); |
1500 | 0 | if (rv != MS_SUCCESS) |
1501 | 0 | return result; |
1502 | 0 | } |
1503 | 0 | cppcheck_assert(layer->vtable); |
1504 | |
|
1505 | 0 | result = layer->vtable->LayerGetNumFeatures(layer); |
1506 | |
|
1507 | 0 | if (need_to_close) |
1508 | 0 | msLayerClose(layer); |
1509 | |
|
1510 | 0 | return (result); |
1511 | 0 | } |
1512 | | |
1513 | | void msLayerSetProcessingKey(layerObj *layer, const char *key, |
1514 | | const char *value) |
1515 | | |
1516 | 0 | { |
1517 | 0 | layer->processing = CSLSetNameValue(layer->processing, key, value); |
1518 | 0 | } |
1519 | | |
1520 | | void msLayerSubstituteProcessing(layerObj *layer, const char *from, |
1521 | 0 | const char *to) { |
1522 | 0 | int i; |
1523 | 0 | for (i = 0; layer->processing && layer->processing[i]; i++) { |
1524 | 0 | char *newVal = |
1525 | 0 | msCaseReplaceSubstring(msStrdup(layer->processing[i]), from, to); |
1526 | 0 | CPLFree(layer->processing[i]); |
1527 | 0 | layer->processing[i] = CPLStrdup(newVal); |
1528 | 0 | msFree(newVal); |
1529 | 0 | } |
1530 | 0 | } |
1531 | | |
1532 | | void msLayerAddProcessing(layerObj *layer, const char *directive) |
1533 | | |
1534 | 0 | { |
1535 | 0 | layer->processing = CSLAddString(layer->processing, directive); |
1536 | 0 | } |
1537 | | |
1538 | 0 | int msLayerGetNumProcessing(const layerObj *layer) { |
1539 | 0 | return CSLCount(layer->processing); |
1540 | 0 | } |
1541 | | |
1542 | 0 | const char *msLayerGetProcessing(const layerObj *layer, int proc_index) { |
1543 | 0 | if (proc_index < 0 || proc_index >= msLayerGetNumProcessing(layer)) { |
1544 | 0 | msSetError(MS_CHILDERR, "Invalid processing index.", |
1545 | 0 | "msLayerGetProcessing()"); |
1546 | 0 | return NULL; |
1547 | 0 | } else { |
1548 | 0 | return layer->processing[proc_index]; |
1549 | 0 | } |
1550 | 0 | } |
1551 | | |
1552 | 0 | const char *msLayerGetProcessingKey(const layerObj *layer, const char *key) { |
1553 | 0 | return CSLFetchNameValue(layer->processing, key); |
1554 | 0 | } |
1555 | | |
1556 | | /************************************************************************/ |
1557 | | /* msLayerGetMaxFeaturesToDraw */ |
1558 | | /* */ |
1559 | | /* Check to see if maxfeaturestodraw is set as a metadata or an */ |
1560 | | /* output format option. Used for vector layers to limit the */ |
1561 | | /* number of fatures rendered. */ |
1562 | | /************************************************************************/ |
1563 | 0 | int msLayerGetMaxFeaturesToDraw(layerObj *layer, outputFormatObj *format) { |
1564 | 0 | int nMaxFeatures = -1; |
1565 | 0 | const char *pszTmp = NULL; |
1566 | 0 | if (layer) { |
1567 | 0 | nMaxFeatures = layer->maxfeatures; |
1568 | 0 | pszTmp = msLookupHashTable(&layer->metadata, "maxfeaturestodraw"); |
1569 | 0 | if (pszTmp) |
1570 | 0 | nMaxFeatures = atoi(pszTmp); |
1571 | 0 | else { |
1572 | 0 | pszTmp = |
1573 | 0 | msLookupHashTable(&layer->map->web.metadata, "maxfeaturestodraw"); |
1574 | 0 | if (pszTmp) |
1575 | 0 | nMaxFeatures = atoi(pszTmp); |
1576 | 0 | } |
1577 | 0 | } |
1578 | 0 | if (format) { |
1579 | 0 | if (nMaxFeatures < 0) |
1580 | 0 | nMaxFeatures = |
1581 | 0 | atoi(msGetOutputFormatOption(format, "maxfeaturestodraw", "-1")); |
1582 | 0 | } |
1583 | |
|
1584 | 0 | return nMaxFeatures; |
1585 | 0 | } |
1586 | | |
1587 | 0 | int msLayerClearProcessing(layerObj *layer) { |
1588 | 0 | CSLDestroy(layer->processing); |
1589 | 0 | layer->processing = 0; |
1590 | 0 | return 0; |
1591 | 0 | } |
1592 | | |
1593 | | int makeTimeFilter(layerObj *lp, const char *timestring, const char *timefield, |
1594 | 0 | const int addtimebacktics) { |
1595 | |
|
1596 | 0 | char **atimes, **tokens = NULL; |
1597 | 0 | int numtimes, i, ntmp = 0; |
1598 | 0 | char *pszBuffer = NULL; |
1599 | 0 | int bOnlyExistingFilter = 0; |
1600 | |
|
1601 | 0 | if (!lp || !timestring || !timefield) |
1602 | 0 | return MS_FALSE; |
1603 | | |
1604 | | /* parse the time string. We support discrete times (eg 2004-09-21), */ |
1605 | | /* multiple times (2004-09-21, 2004-09-22, ...) */ |
1606 | | /* and range(s) (2004-09-21/2004-09-25, 2004-09-27/2004-09-29) */ |
1607 | | |
1608 | 0 | if (strstr(timestring, ",") == NULL && |
1609 | 0 | strstr(timestring, "/") == NULL) { /* discrete time */ |
1610 | | /* |
1611 | | if(lp->filteritem) free(lp->filteritem); |
1612 | | lp->filteritem = msStrdup(timefield); |
1613 | | if (&lp->filter) |
1614 | | msFreeExpression(&lp->filter); |
1615 | | */ |
1616 | | |
1617 | | /* if the filter is set and it's a sting type, concatenate it with |
1618 | | the time. If not just free it */ |
1619 | 0 | if (lp->filter.string && lp->filter.type == MS_STRING) { |
1620 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "(("); |
1621 | 0 | pszBuffer = msStringConcatenate(pszBuffer, lp->filter.string); |
1622 | 0 | pszBuffer = msStringConcatenate(pszBuffer, ") and "); |
1623 | 0 | } else if (lp->filter.string && lp->filter.type == MS_EXPRESSION) { |
1624 | 0 | char *pszExpressionString = msGetExpressionString(&(lp->filter)); |
1625 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "("); |
1626 | 0 | pszBuffer = msStringConcatenate(pszBuffer, pszExpressionString); |
1627 | 0 | pszBuffer = msStringConcatenate(pszBuffer, " and "); |
1628 | 0 | msFree(pszExpressionString); |
1629 | 0 | } else { |
1630 | 0 | msFreeExpression(&lp->filter); |
1631 | 0 | } |
1632 | |
|
1633 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "("); |
1634 | 0 | if (addtimebacktics) |
1635 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1636 | |
|
1637 | 0 | if (addtimebacktics) |
1638 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "["); |
1639 | 0 | pszBuffer = msStringConcatenate(pszBuffer, (char *)timefield); |
1640 | 0 | if (addtimebacktics) |
1641 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "]"); |
1642 | 0 | if (addtimebacktics) |
1643 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1644 | |
|
1645 | 0 | pszBuffer = msStringConcatenate(pszBuffer, " = "); |
1646 | 0 | if (addtimebacktics) |
1647 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1648 | 0 | else |
1649 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "'"); |
1650 | |
|
1651 | 0 | pszBuffer = msStringConcatenate(pszBuffer, (char *)timestring); |
1652 | 0 | if (addtimebacktics) |
1653 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1654 | 0 | else |
1655 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "'"); |
1656 | |
|
1657 | 0 | pszBuffer = msStringConcatenate(pszBuffer, ")"); |
1658 | | |
1659 | | /* if there was a filter, It was concatenate with an And ans should be |
1660 | | * closed*/ |
1661 | 0 | if (lp->filter.string && |
1662 | 0 | (lp->filter.type == MS_STRING || lp->filter.type == MS_EXPRESSION)) |
1663 | 0 | pszBuffer = msStringConcatenate(pszBuffer, ")"); |
1664 | |
|
1665 | 0 | msLoadExpressionString(&lp->filter, pszBuffer); |
1666 | |
|
1667 | 0 | if (pszBuffer) |
1668 | 0 | msFree(pszBuffer); |
1669 | 0 | return MS_TRUE; |
1670 | 0 | } |
1671 | | |
1672 | 0 | atimes = msStringSplit(timestring, ',', &numtimes); |
1673 | 0 | if (atimes == NULL || numtimes < 1) { |
1674 | 0 | msFreeCharArray(atimes, numtimes); |
1675 | 0 | return MS_FALSE; |
1676 | 0 | } |
1677 | | |
1678 | 0 | if (lp->filter.string && lp->filter.type == MS_STRING) { |
1679 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "(("); |
1680 | 0 | pszBuffer = msStringConcatenate(pszBuffer, lp->filter.string); |
1681 | 0 | pszBuffer = msStringConcatenate(pszBuffer, ") and "); |
1682 | | /*this flag is used to indicate that the buffer contains only the |
1683 | | existing filter. It is set to 0 when time filter parts are |
1684 | | added to the buffer */ |
1685 | 0 | bOnlyExistingFilter = 1; |
1686 | 0 | } else if (lp->filter.string && lp->filter.type == MS_EXPRESSION) { |
1687 | 0 | char *pszExpressionString = msGetExpressionString(&(lp->filter)); |
1688 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "("); |
1689 | 0 | pszBuffer = msStringConcatenate(pszBuffer, pszExpressionString); |
1690 | 0 | pszBuffer = msStringConcatenate(pszBuffer, " and "); |
1691 | 0 | msFree(pszExpressionString); |
1692 | 0 | bOnlyExistingFilter = 1; |
1693 | 0 | } else |
1694 | 0 | msFreeExpression(&lp->filter); |
1695 | | |
1696 | | /* check to see if we have ranges by parsing the first entry */ |
1697 | 0 | tokens = msStringSplit(atimes[0], '/', &ntmp); |
1698 | 0 | if (ntmp == 2) { /* ranges */ |
1699 | 0 | msFreeCharArray(tokens, ntmp); |
1700 | 0 | for (i = 0; i < numtimes; i++) { |
1701 | 0 | tokens = msStringSplit(atimes[i], '/', &ntmp); |
1702 | 0 | if (ntmp == 2) { |
1703 | 0 | if (pszBuffer && strlen(pszBuffer) > 0 && bOnlyExistingFilter == 0) |
1704 | 0 | pszBuffer = msStringConcatenate(pszBuffer, " OR "); |
1705 | 0 | else |
1706 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "("); |
1707 | |
|
1708 | 0 | bOnlyExistingFilter = 0; |
1709 | |
|
1710 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "("); |
1711 | 0 | if (addtimebacktics) |
1712 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1713 | |
|
1714 | 0 | if (addtimebacktics) |
1715 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "["); |
1716 | 0 | pszBuffer = msStringConcatenate(pszBuffer, (char *)timefield); |
1717 | 0 | if (addtimebacktics) |
1718 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "]"); |
1719 | |
|
1720 | 0 | if (addtimebacktics) |
1721 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1722 | |
|
1723 | 0 | pszBuffer = msStringConcatenate(pszBuffer, " >= "); |
1724 | 0 | if (addtimebacktics) |
1725 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1726 | 0 | else |
1727 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "'"); |
1728 | |
|
1729 | 0 | pszBuffer = msStringConcatenate(pszBuffer, tokens[0]); |
1730 | 0 | if (addtimebacktics) |
1731 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1732 | 0 | else |
1733 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "'"); |
1734 | 0 | pszBuffer = msStringConcatenate(pszBuffer, " AND "); |
1735 | |
|
1736 | 0 | if (addtimebacktics) |
1737 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1738 | |
|
1739 | 0 | if (addtimebacktics) |
1740 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "["); |
1741 | 0 | pszBuffer = msStringConcatenate(pszBuffer, (char *)timefield); |
1742 | 0 | if (addtimebacktics) |
1743 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "]"); |
1744 | 0 | if (addtimebacktics) |
1745 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1746 | |
|
1747 | 0 | pszBuffer = msStringConcatenate(pszBuffer, " <= "); |
1748 | |
|
1749 | 0 | if (addtimebacktics) |
1750 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1751 | 0 | else |
1752 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "'"); |
1753 | 0 | pszBuffer = msStringConcatenate(pszBuffer, tokens[1]); |
1754 | 0 | if (addtimebacktics) |
1755 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1756 | 0 | else |
1757 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "'"); |
1758 | 0 | pszBuffer = msStringConcatenate(pszBuffer, ")"); |
1759 | 0 | } |
1760 | |
|
1761 | 0 | msFreeCharArray(tokens, ntmp); |
1762 | 0 | } |
1763 | 0 | if (pszBuffer && strlen(pszBuffer) > 0 && bOnlyExistingFilter == 0) |
1764 | 0 | pszBuffer = msStringConcatenate(pszBuffer, ")"); |
1765 | 0 | } else if (ntmp == 1) { /* multiple times */ |
1766 | 0 | msFreeCharArray(tokens, ntmp); |
1767 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "("); |
1768 | 0 | for (i = 0; i < numtimes; i++) { |
1769 | 0 | if (i > 0) |
1770 | 0 | pszBuffer = msStringConcatenate(pszBuffer, " OR "); |
1771 | |
|
1772 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "("); |
1773 | 0 | if (addtimebacktics) |
1774 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1775 | |
|
1776 | 0 | if (addtimebacktics) |
1777 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "["); |
1778 | 0 | pszBuffer = msStringConcatenate(pszBuffer, (char *)timefield); |
1779 | 0 | if (addtimebacktics) |
1780 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "]"); |
1781 | |
|
1782 | 0 | if (addtimebacktics) |
1783 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1784 | |
|
1785 | 0 | pszBuffer = msStringConcatenate(pszBuffer, " = "); |
1786 | |
|
1787 | 0 | if (addtimebacktics) |
1788 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1789 | 0 | else |
1790 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "'"); |
1791 | 0 | pszBuffer = msStringConcatenate(pszBuffer, atimes[i]); |
1792 | 0 | if (addtimebacktics) |
1793 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "`"); |
1794 | 0 | else |
1795 | 0 | pszBuffer = msStringConcatenate(pszBuffer, "'"); |
1796 | 0 | pszBuffer = msStringConcatenate(pszBuffer, ")"); |
1797 | 0 | } |
1798 | 0 | pszBuffer = msStringConcatenate(pszBuffer, ")"); |
1799 | 0 | } else { |
1800 | 0 | msFreeCharArray(tokens, ntmp); |
1801 | 0 | msFreeCharArray(atimes, numtimes); |
1802 | 0 | msFree(pszBuffer); |
1803 | 0 | return MS_FALSE; |
1804 | 0 | } |
1805 | | |
1806 | 0 | msFreeCharArray(atimes, numtimes); |
1807 | | |
1808 | | /* load the string to the filter */ |
1809 | 0 | if (pszBuffer && strlen(pszBuffer) > 0) { |
1810 | 0 | if (lp->filter.string && |
1811 | 0 | (lp->filter.type == MS_STRING || lp->filter.type == MS_EXPRESSION)) |
1812 | 0 | pszBuffer = msStringConcatenate(pszBuffer, ")"); |
1813 | | /* |
1814 | | if(lp->filteritem) |
1815 | | free(lp->filteritem); |
1816 | | lp->filteritem = msStrdup(timefield); |
1817 | | */ |
1818 | |
|
1819 | 0 | msLoadExpressionString(&lp->filter, pszBuffer); |
1820 | 0 | } |
1821 | 0 | msFree(pszBuffer); |
1822 | 0 | return MS_TRUE; |
1823 | 0 | } |
1824 | | |
1825 | | /** |
1826 | | set the filter parameter for a time filter |
1827 | | **/ |
1828 | | |
1829 | | int msLayerSetTimeFilter(layerObj *layer, const char *timestring, |
1830 | 0 | const char *timefield) { |
1831 | 0 | if (!layer->vtable) { |
1832 | 0 | int rv = msInitializeVirtualTable(layer); |
1833 | 0 | if (rv != MS_SUCCESS) |
1834 | 0 | return rv; |
1835 | 0 | } |
1836 | 0 | cppcheck_assert(layer->vtable); |
1837 | 0 | return layer->vtable->LayerSetTimeFilter(layer, timestring, timefield); |
1838 | 0 | } |
1839 | | |
1840 | | int msLayerMakeBackticsTimeFilter(layerObj *lp, const char *timestring, |
1841 | 0 | const char *timefield) { |
1842 | 0 | return makeTimeFilter(lp, timestring, timefield, MS_TRUE); |
1843 | 0 | } |
1844 | | |
1845 | | int msLayerMakePlainTimeFilter(layerObj *lp, const char *timestring, |
1846 | 0 | const char *timefield) { |
1847 | 0 | return makeTimeFilter(lp, timestring, timefield, MS_FALSE); |
1848 | 0 | } |
1849 | | |
1850 | | /* |
1851 | | * Dummies / default actions for layers |
1852 | | */ |
1853 | 0 | int LayerDefaultInitItemInfo(layerObj *layer) { |
1854 | 0 | (void)layer; |
1855 | 0 | return MS_SUCCESS; |
1856 | 0 | } |
1857 | | |
1858 | 0 | void LayerDefaultFreeItemInfo(layerObj *layer) { (void)layer; } |
1859 | | |
1860 | 0 | int LayerDefaultOpen(layerObj *layer) { |
1861 | 0 | (void)layer; |
1862 | 0 | return MS_FAILURE; |
1863 | 0 | } |
1864 | | |
1865 | 0 | int LayerDefaultIsOpen(layerObj *layer) { |
1866 | 0 | (void)layer; |
1867 | 0 | return MS_FALSE; |
1868 | 0 | } |
1869 | | |
1870 | 0 | int LayerDefaultWhichShapes(layerObj *layer, rectObj rect, int isQuery) { |
1871 | 0 | (void)layer; |
1872 | 0 | (void)rect; |
1873 | 0 | (void)isQuery; |
1874 | 0 | return MS_SUCCESS; |
1875 | 0 | } |
1876 | | |
1877 | 0 | int LayerDefaultNextShape(layerObj *layer, shapeObj *shape) { |
1878 | 0 | (void)layer; |
1879 | 0 | (void)shape; |
1880 | 0 | return MS_FAILURE; |
1881 | 0 | } |
1882 | | |
1883 | 0 | int LayerDefaultGetShape(layerObj *layer, shapeObj *shape, resultObj *record) { |
1884 | 0 | (void)layer; |
1885 | 0 | (void)shape; |
1886 | 0 | (void)record; |
1887 | 0 | return MS_FAILURE; |
1888 | 0 | } |
1889 | | |
1890 | | int LayerDefaultGetShapeCount(layerObj *layer, rectObj rect, |
1891 | 0 | projectionObj *rectProjection) { |
1892 | 0 | int status; |
1893 | 0 | shapeObj shape, searchshape; |
1894 | 0 | int nShapeCount = 0; |
1895 | 0 | rectObj searchrect = rect; |
1896 | 0 | reprojectionObj *reprojector = NULL; |
1897 | |
|
1898 | 0 | msInitShape(&searchshape); |
1899 | 0 | msRectToPolygon(searchrect, &searchshape); |
1900 | |
|
1901 | 0 | if (rectProjection != NULL) { |
1902 | 0 | if (layer->project && |
1903 | 0 | msProjectionsDiffer(&(layer->projection), rectProjection)) |
1904 | 0 | msProjectRect(rectProjection, &(layer->projection), |
1905 | 0 | &searchrect); /* project the searchrect to source coords */ |
1906 | 0 | else |
1907 | 0 | layer->project = MS_FALSE; |
1908 | 0 | } |
1909 | |
|
1910 | 0 | status = msLayerWhichShapes(layer, searchrect, MS_TRUE); |
1911 | 0 | if (status == MS_FAILURE) { |
1912 | 0 | msFreeShape(&searchshape); |
1913 | 0 | return -1; |
1914 | 0 | } else if (status == MS_DONE) { |
1915 | 0 | msFreeShape(&searchshape); |
1916 | 0 | return 0; |
1917 | 0 | } |
1918 | | |
1919 | 0 | msInitShape(&shape); |
1920 | 0 | while ((status = msLayerNextShape(layer, &shape)) == MS_SUCCESS) { |
1921 | 0 | if (rectProjection != NULL) { |
1922 | 0 | if (layer->project && |
1923 | 0 | msProjectionsDiffer(&(layer->projection), rectProjection)) { |
1924 | 0 | if (reprojector == NULL) |
1925 | 0 | reprojector = |
1926 | 0 | msProjectCreateReprojector(&(layer->projection), rectProjection); |
1927 | 0 | if (reprojector) |
1928 | 0 | msProjectShapeEx(reprojector, &shape); |
1929 | 0 | } else |
1930 | 0 | layer->project = MS_FALSE; |
1931 | |
|
1932 | 0 | if (msRectContained(&shape.bounds, &rect) == |
1933 | 0 | MS_TRUE) { /* if the whole shape is in, don't intersect */ |
1934 | 0 | status = MS_TRUE; |
1935 | 0 | } else { |
1936 | 0 | switch (shape.type) { /* make sure shape actually intersects the qrect |
1937 | | (ADD FUNCTIONS SPECIFIC TO RECTOBJ) */ |
1938 | 0 | case MS_SHAPE_POINT: |
1939 | 0 | status = msIntersectMultipointPolygon(&shape, &searchshape); |
1940 | 0 | break; |
1941 | 0 | case MS_SHAPE_LINE: |
1942 | 0 | status = msIntersectPolylinePolygon(&shape, &searchshape); |
1943 | 0 | break; |
1944 | 0 | case MS_SHAPE_POLYGON: |
1945 | 0 | status = msIntersectPolygons(&shape, &searchshape); |
1946 | 0 | break; |
1947 | 0 | default: |
1948 | 0 | break; |
1949 | 0 | } |
1950 | 0 | } |
1951 | 0 | } else |
1952 | 0 | status = MS_TRUE; |
1953 | | |
1954 | 0 | if (status == MS_TRUE) |
1955 | 0 | nShapeCount++; |
1956 | 0 | msFreeShape(&shape); |
1957 | 0 | if (layer->maxfeatures > 0 && layer->maxfeatures == nShapeCount) |
1958 | 0 | break; |
1959 | 0 | } |
1960 | | |
1961 | 0 | msFreeShape(&searchshape); |
1962 | 0 | msProjectDestroyReprojector(reprojector); |
1963 | |
|
1964 | 0 | return nShapeCount; |
1965 | 0 | } |
1966 | | |
1967 | 0 | int LayerDefaultClose(layerObj *layer) { |
1968 | 0 | (void)layer; |
1969 | 0 | return MS_SUCCESS; |
1970 | 0 | } |
1971 | | |
1972 | 0 | int LayerDefaultGetItems(layerObj *layer) { |
1973 | 0 | (void)layer; |
1974 | 0 | return MS_SUCCESS; /* returning no items is legit */ |
1975 | 0 | } |
1976 | | |
1977 | | int msLayerApplyCondSQLFilterToLayer(FilterEncodingNode *psNode, mapObj *map, |
1978 | 0 | int iLayerIndex) { |
1979 | 0 | return FLTLayerApplyCondSQLFilterToLayer(psNode, map, iLayerIndex); |
1980 | 0 | } |
1981 | | |
1982 | 0 | int msLayerSupportsPaging(layerObj *layer) { |
1983 | 0 | if (layer && ((layer->connectiontype == MS_ORACLESPATIAL) || |
1984 | 0 | (layer->connectiontype == MS_POSTGIS))) |
1985 | 0 | return MS_TRUE; |
1986 | | |
1987 | 0 | return MS_FALSE; |
1988 | 0 | } |
1989 | | |
1990 | | int msLayerApplyPlainFilterToLayer(FilterEncodingNode *psNode, mapObj *map, |
1991 | | int iLayerIndex); |
1992 | | |
1993 | | /* |
1994 | | * msLayerSupportsSorting() |
1995 | | * |
1996 | | * Returns MS_TRUE if the layer supports sorting/ordering. |
1997 | | */ |
1998 | 0 | int msLayerSupportsSorting(layerObj *layer) { |
1999 | 0 | if (layer && |
2000 | 0 | ((layer->connectiontype == MS_OGR) || |
2001 | 0 | (layer->connectiontype == MS_POSTGIS) || |
2002 | 0 | (layer->connectiontype == MS_ORACLESPATIAL) || |
2003 | 0 | ((layer->connectiontype == MS_PLUGIN) && |
2004 | 0 | (strstr(layer->plugin_library, "msplugin_oracle") != NULL)) || |
2005 | 0 | ((layer->connectiontype == MS_PLUGIN) && |
2006 | 0 | (strstr(layer->plugin_library, "msplugin_mssql2008") != NULL)))) |
2007 | 0 | return MS_TRUE; |
2008 | | |
2009 | 0 | return MS_FALSE; |
2010 | 0 | } |
2011 | | |
2012 | 0 | static void msLayerFreeSortBy(layerObj *layer) { |
2013 | 0 | for (int i = 0; i < layer->sortBy.nProperties; i++) |
2014 | 0 | msFree(layer->sortBy.properties[i].item); |
2015 | 0 | msFree(layer->sortBy.properties); |
2016 | 0 | layer->sortBy.properties = NULL; |
2017 | 0 | layer->sortBy.nProperties = 0; |
2018 | 0 | } |
2019 | | |
2020 | | /* |
2021 | | * msLayerSetSort() |
2022 | | * |
2023 | | * Copy the sortBy clause passed as an argument into the layer sortBy member. |
2024 | | */ |
2025 | 0 | void msLayerSetSort(layerObj *layer, const sortByClause *sortBy) { |
2026 | |
|
2027 | 0 | sortByProperties *newProperties = (sortByProperties *)msSmallMalloc( |
2028 | 0 | sortBy->nProperties * sizeof(sortByProperties)); |
2029 | 0 | for (int i = 0; i < sortBy->nProperties; i++) { |
2030 | 0 | newProperties[i].item = msStrdup(sortBy->properties[i].item); |
2031 | 0 | newProperties[i].sortOrder = sortBy->properties[i].sortOrder; |
2032 | 0 | } |
2033 | |
|
2034 | 0 | msLayerFreeSortBy(layer); |
2035 | 0 | layer->sortBy.nProperties = sortBy->nProperties; |
2036 | 0 | layer->sortBy.properties = newProperties; |
2037 | 0 | } |
2038 | | |
2039 | | /* |
2040 | | * msLayerBuildSQLOrderBy() |
2041 | | * |
2042 | | * Returns the content of a SQL ORDER BY clause from the sortBy member of |
2043 | | * the layer. The string does not contain the "ORDER BY" keywords itself. |
2044 | | */ |
2045 | 0 | char *msLayerBuildSQLOrderBy(layerObj *layer) { |
2046 | 0 | char *strOrderBy = NULL; |
2047 | 0 | if (layer->sortBy.nProperties > 0) { |
2048 | 0 | int i; |
2049 | 0 | for (i = 0; i < layer->sortBy.nProperties; i++) { |
2050 | 0 | char *escaped = |
2051 | 0 | msLayerEscapePropertyName(layer, layer->sortBy.properties[i].item); |
2052 | 0 | if (i > 0) |
2053 | 0 | strOrderBy = msStringConcatenate(strOrderBy, ", "); |
2054 | 0 | strOrderBy = msStringConcatenate(strOrderBy, escaped); |
2055 | 0 | if (layer->sortBy.properties[i].sortOrder == SORT_DESC) |
2056 | 0 | strOrderBy = msStringConcatenate(strOrderBy, " DESC"); |
2057 | 0 | msFree(escaped); |
2058 | 0 | } |
2059 | 0 | } |
2060 | 0 | return strOrderBy; |
2061 | 0 | } |
2062 | | |
2063 | | int msLayerApplyPlainFilterToLayer(FilterEncodingNode *psNode, mapObj *map, |
2064 | 0 | int iLayerIndex) { |
2065 | 0 | return FLTLayerApplyPlainFilterToLayer(psNode, map, iLayerIndex); |
2066 | 0 | } |
2067 | | |
2068 | 0 | int msLayerGetPaging(layerObj *layer) { |
2069 | 0 | if (!layer->vtable) { |
2070 | 0 | int rv = msInitializeVirtualTable(layer); |
2071 | 0 | if (rv != MS_SUCCESS) { |
2072 | 0 | msSetError(MS_MISCERR, "Unable to initialize virtual table", |
2073 | 0 | "msLayerGetPaging()"); |
2074 | 0 | return MS_FAILURE; |
2075 | 0 | } |
2076 | 0 | } |
2077 | 0 | cppcheck_assert(layer->vtable); |
2078 | 0 | return layer->vtable->LayerGetPaging(layer); |
2079 | 0 | } |
2080 | | |
2081 | 0 | void msLayerEnablePaging(layerObj *layer, int value) { |
2082 | 0 | if (!layer->vtable) { |
2083 | 0 | int rv = msInitializeVirtualTable(layer); |
2084 | 0 | if (rv != MS_SUCCESS) { |
2085 | 0 | msSetError(MS_MISCERR, "Unable to initialize virtual table", |
2086 | 0 | "msLayerEnablePaging()"); |
2087 | 0 | return; |
2088 | 0 | } |
2089 | 0 | } |
2090 | 0 | cppcheck_assert(layer->vtable); |
2091 | 0 | layer->vtable->LayerEnablePaging(layer, value); |
2092 | 0 | } |
2093 | | |
2094 | | /** Returns a cached reprojector from the layer projection to the map projection |
2095 | | */ |
2096 | 0 | reprojectionObj *msLayerGetReprojectorToMap(layerObj *layer, mapObj *map) { |
2097 | 0 | if (layer->reprojectorLayerToMap != NULL && |
2098 | 0 | !msProjectIsReprojectorStillValid(layer->reprojectorLayerToMap)) { |
2099 | 0 | msProjectDestroyReprojector(layer->reprojectorLayerToMap); |
2100 | 0 | layer->reprojectorLayerToMap = NULL; |
2101 | 0 | } |
2102 | |
|
2103 | 0 | if (layer->reprojectorLayerToMap == NULL) { |
2104 | 0 | layer->reprojectorLayerToMap = |
2105 | 0 | msProjectCreateReprojector(&layer->projection, &map->projection); |
2106 | 0 | } |
2107 | 0 | return layer->reprojectorLayerToMap; |
2108 | 0 | } |
2109 | | |
2110 | 0 | int LayerDefaultGetExtent(layerObj *layer, rectObj *extent) { |
2111 | 0 | (void)layer; |
2112 | 0 | (void)extent; |
2113 | 0 | return MS_FAILURE; |
2114 | 0 | } |
2115 | | |
2116 | | int LayerDefaultGetAutoStyle(mapObj *map, layerObj *layer, classObj *c, |
2117 | 0 | shapeObj *shape) { |
2118 | 0 | (void)map; |
2119 | 0 | (void)layer; |
2120 | 0 | (void)c; |
2121 | 0 | (void)shape; |
2122 | 0 | msSetError(MS_MISCERR, "'STYLEITEM AUTO' not supported for this data source.", |
2123 | 0 | "msLayerGetAutoStyle()"); |
2124 | 0 | return MS_FAILURE; |
2125 | 0 | } |
2126 | | |
2127 | 0 | int LayerDefaultCloseConnection(layerObj *layer) { |
2128 | 0 | (void)layer; |
2129 | 0 | return MS_SUCCESS; |
2130 | 0 | } |
2131 | | |
2132 | 0 | int LayerDefaultCreateItems(layerObj *layer, const int nt) { |
2133 | 0 | if (nt > 0) { |
2134 | 0 | layer->items = (char **)calloc( |
2135 | 0 | nt, sizeof(char *)); /* should be more than enough space */ |
2136 | 0 | MS_CHECK_ALLOC(layer->items, sizeof(char *), MS_FAILURE); |
2137 | |
|
2138 | 0 | layer->numitems = 0; |
2139 | 0 | } |
2140 | 0 | return MS_SUCCESS; |
2141 | 0 | } |
2142 | | |
2143 | 0 | int LayerDefaultGetNumFeatures(layerObj *layer) { |
2144 | 0 | rectObj extent; |
2145 | 0 | int status; |
2146 | 0 | int result; |
2147 | 0 | shapeObj shape; |
2148 | | |
2149 | | /* calculate layer extent */ |
2150 | 0 | if (!MS_VALID_EXTENT(layer->extent)) { |
2151 | 0 | if (msLayerGetExtent(layer, &extent) != MS_SUCCESS) { |
2152 | 0 | msSetError(MS_MISCERR, "Unable to get layer extent", |
2153 | 0 | "LayerDefaultGetNumFeatures()"); |
2154 | 0 | return -1; |
2155 | 0 | } |
2156 | 0 | } else |
2157 | 0 | extent = layer->extent; |
2158 | | |
2159 | | /* Cleanup any previous item selection */ |
2160 | 0 | msLayerFreeItemInfo(layer); |
2161 | 0 | if (layer->items) { |
2162 | 0 | msFreeCharArray(layer->items, layer->numitems); |
2163 | 0 | layer->items = NULL; |
2164 | 0 | layer->numitems = 0; |
2165 | 0 | } |
2166 | |
|
2167 | 0 | status = msLayerWhichShapes(layer, extent, MS_FALSE); |
2168 | 0 | if (status == MS_DONE) { /* no overlap */ |
2169 | 0 | return 0; |
2170 | 0 | } else if (status != MS_SUCCESS) { |
2171 | 0 | return -1; |
2172 | 0 | } |
2173 | | |
2174 | 0 | result = 0; |
2175 | 0 | while ((status = msLayerNextShape(layer, &shape)) == MS_SUCCESS) { |
2176 | 0 | ++result; |
2177 | 0 | msFreeShape(&shape); |
2178 | 0 | } |
2179 | |
|
2180 | 0 | return result; |
2181 | 0 | } |
2182 | | |
2183 | 0 | int LayerDefaultAutoProjection(layerObj *layer, projectionObj *projection) { |
2184 | 0 | (void)layer; |
2185 | 0 | (void)projection; |
2186 | 0 | msSetError(MS_MISCERR, |
2187 | 0 | "This data driver does not implement AUTO projection support", |
2188 | 0 | "LayerDefaultAutoProjection()"); |
2189 | 0 | return MS_FAILURE; |
2190 | 0 | } |
2191 | | |
2192 | 0 | int LayerDefaultSupportsCommonFilters(layerObj *layer) { |
2193 | 0 | (void)layer; |
2194 | 0 | return MS_FALSE; |
2195 | 0 | } |
2196 | | |
2197 | | int LayerDefaultTranslateFilter(layerObj *layer, expressionObj *filter, |
2198 | 0 | char *filteritem) { |
2199 | 0 | (void)layer; |
2200 | 0 | (void)filteritem; |
2201 | 0 | if (!filter->string) |
2202 | 0 | return MS_SUCCESS; /* nothing to do, not an error */ |
2203 | | |
2204 | 0 | msSetError(MS_MISCERR, |
2205 | 0 | "This data driver does not implement filter translation support", |
2206 | 0 | "LayerDefaultTranslateFilter()"); |
2207 | 0 | return MS_FAILURE; |
2208 | 0 | } |
2209 | | |
2210 | 0 | int msLayerDefaultGetPaging(layerObj *layer) { |
2211 | 0 | (void)layer; |
2212 | 0 | return MS_FALSE; |
2213 | 0 | } |
2214 | | |
2215 | 0 | void msLayerDefaultEnablePaging(layerObj *layer, int value) { |
2216 | 0 | (void)layer; |
2217 | 0 | (void)value; |
2218 | 0 | } |
2219 | | |
2220 | | /************************************************************************/ |
2221 | | /* LayerDefaultEscapeSQLParam */ |
2222 | | /* */ |
2223 | | /* Default function used to escape strings and avoid sql */ |
2224 | | /* injection. Specific drivers should redefine if an escaping */ |
2225 | | /* function is available in the driver. */ |
2226 | | /************************************************************************/ |
2227 | 0 | char *LayerDefaultEscapeSQLParam(layerObj *layer, const char *pszString) { |
2228 | 0 | (void)layer; |
2229 | 0 | char *pszEscapedStr = NULL; |
2230 | 0 | if (pszString) { |
2231 | 0 | int nSrcLen; |
2232 | 0 | char c; |
2233 | 0 | int i = 0, j = 0; |
2234 | 0 | nSrcLen = (int)strlen(pszString); |
2235 | 0 | pszEscapedStr = (char *)msSmallMalloc(2 * nSrcLen + 1); |
2236 | 0 | for (i = 0, j = 0; i < nSrcLen; i++) { |
2237 | 0 | c = pszString[i]; |
2238 | 0 | if (c == '\'') { |
2239 | 0 | pszEscapedStr[j++] = '\''; |
2240 | 0 | pszEscapedStr[j++] = '\''; |
2241 | 0 | } else if (c == '\\') { |
2242 | 0 | pszEscapedStr[j++] = '\\'; |
2243 | 0 | pszEscapedStr[j++] = '\\'; |
2244 | 0 | } else |
2245 | 0 | pszEscapedStr[j++] = c; |
2246 | 0 | } |
2247 | 0 | pszEscapedStr[j] = 0; |
2248 | 0 | } |
2249 | 0 | return pszEscapedStr; |
2250 | 0 | } |
2251 | | |
2252 | | /************************************************************************/ |
2253 | | /* LayerDefaultEscapePropertyName */ |
2254 | | /* */ |
2255 | | /* Return the property name in a properly escaped and quoted form. */ |
2256 | | /************************************************************************/ |
2257 | 0 | char *LayerDefaultEscapePropertyName(layerObj *layer, const char *pszString) { |
2258 | 0 | char *pszEscapedStr = NULL; |
2259 | 0 | int i, j = 0; |
2260 | |
|
2261 | 0 | if (layer && pszString && strlen(pszString) > 0) { |
2262 | 0 | int nLength = strlen(pszString); |
2263 | |
|
2264 | 0 | pszEscapedStr = (char *)msSmallMalloc(1 + 2 * nLength + 1 + 1); |
2265 | 0 | pszEscapedStr[j++] = '"'; |
2266 | |
|
2267 | 0 | for (i = 0; i < nLength; i++) { |
2268 | 0 | char c = pszString[i]; |
2269 | 0 | if (c == '"') { |
2270 | 0 | pszEscapedStr[j++] = '"'; |
2271 | 0 | pszEscapedStr[j++] = '"'; |
2272 | 0 | } else if (c == '\\') { |
2273 | 0 | pszEscapedStr[j++] = '\\'; |
2274 | 0 | pszEscapedStr[j++] = '\\'; |
2275 | 0 | } else |
2276 | 0 | pszEscapedStr[j++] = c; |
2277 | 0 | } |
2278 | 0 | pszEscapedStr[j++] = '"'; |
2279 | 0 | pszEscapedStr[j++] = 0; |
2280 | 0 | } |
2281 | 0 | return pszEscapedStr; |
2282 | 0 | } |
2283 | | |
2284 | | /* |
2285 | | * msConnectLayer |
2286 | | * |
2287 | | * This will connect layer object to the new layer type. |
2288 | | * Caller is responsible to close previous layer correctly. |
2289 | | * For Internal types the library_str is ignored, for PLUGIN it's |
2290 | | * define what plugin to use. Returns MS_FAILURE or MS_SUCCESS. |
2291 | | */ |
2292 | | int msConnectLayer(layerObj *layer, const int connectiontype, |
2293 | 0 | const char *library_str) { |
2294 | 0 | layer->connectiontype = connectiontype; |
2295 | | /* For internal types, library_str is ignored */ |
2296 | 0 | if (connectiontype == MS_PLUGIN) { |
2297 | 0 | int rv; |
2298 | |
|
2299 | 0 | msFree(layer->plugin_library_original); |
2300 | 0 | layer->plugin_library_original = msStrdup(library_str); |
2301 | |
|
2302 | 0 | rv = msBuildPluginLibraryPath(&layer->plugin_library, |
2303 | 0 | layer->plugin_library_original, layer->map); |
2304 | 0 | if (rv != MS_SUCCESS) { |
2305 | 0 | return rv; |
2306 | 0 | } |
2307 | 0 | } |
2308 | 0 | return msInitializeVirtualTable(layer); |
2309 | 0 | } |
2310 | | |
2311 | 0 | static int populateVirtualTable(layerVTableObj *vtable) { |
2312 | 0 | assert(vtable != NULL); |
2313 | | |
2314 | 0 | vtable->LayerSupportsCommonFilters = LayerDefaultSupportsCommonFilters; |
2315 | 0 | vtable->LayerTranslateFilter = LayerDefaultTranslateFilter; |
2316 | |
|
2317 | 0 | vtable->LayerInitItemInfo = LayerDefaultInitItemInfo; |
2318 | 0 | vtable->LayerFreeItemInfo = LayerDefaultFreeItemInfo; |
2319 | 0 | vtable->LayerOpen = LayerDefaultOpen; |
2320 | 0 | vtable->LayerIsOpen = LayerDefaultIsOpen; |
2321 | 0 | vtable->LayerWhichShapes = LayerDefaultWhichShapes; |
2322 | |
|
2323 | 0 | vtable->LayerNextShape = LayerDefaultNextShape; |
2324 | | /* vtable->LayerResultsGetShape = LayerDefaultResultsGetShape; */ |
2325 | 0 | vtable->LayerGetShape = LayerDefaultGetShape; |
2326 | 0 | vtable->LayerGetShapeCount = LayerDefaultGetShapeCount; |
2327 | 0 | vtable->LayerClose = LayerDefaultClose; |
2328 | 0 | vtable->LayerGetItems = LayerDefaultGetItems; |
2329 | 0 | vtable->LayerGetExtent = LayerDefaultGetExtent; |
2330 | |
|
2331 | 0 | vtable->LayerGetAutoStyle = LayerDefaultGetAutoStyle; |
2332 | 0 | vtable->LayerCloseConnection = LayerDefaultCloseConnection; |
2333 | 0 | vtable->LayerSetTimeFilter = msLayerMakePlainTimeFilter; |
2334 | |
|
2335 | 0 | vtable->LayerApplyFilterToLayer = msLayerApplyPlainFilterToLayer; |
2336 | |
|
2337 | 0 | vtable->LayerCreateItems = LayerDefaultCreateItems; |
2338 | |
|
2339 | 0 | vtable->LayerGetNumFeatures = LayerDefaultGetNumFeatures; |
2340 | |
|
2341 | 0 | vtable->LayerGetAutoProjection = LayerDefaultAutoProjection; |
2342 | |
|
2343 | 0 | vtable->LayerEscapeSQLParam = LayerDefaultEscapeSQLParam; |
2344 | |
|
2345 | 0 | vtable->LayerEscapePropertyName = LayerDefaultEscapePropertyName; |
2346 | |
|
2347 | 0 | vtable->LayerEnablePaging = msLayerDefaultEnablePaging; |
2348 | 0 | vtable->LayerGetPaging = msLayerDefaultGetPaging; |
2349 | |
|
2350 | 0 | return MS_SUCCESS; |
2351 | 0 | } |
2352 | | |
2353 | 0 | static int createVirtualTable(layerVTableObj **vtable) { |
2354 | 0 | *vtable = malloc(sizeof(**vtable)); |
2355 | 0 | MS_CHECK_ALLOC(*vtable, sizeof(**vtable), MS_FAILURE); |
2356 | |
|
2357 | 0 | return populateVirtualTable(*vtable); |
2358 | 0 | } |
2359 | | |
2360 | 0 | static int destroyVirtualTable(layerVTableObj **vtable) { |
2361 | 0 | memset(*vtable, 0, sizeof(**vtable)); |
2362 | 0 | msFree(*vtable); |
2363 | 0 | *vtable = NULL; |
2364 | 0 | return MS_SUCCESS; |
2365 | 0 | } |
2366 | | |
2367 | 0 | int msInitializeVirtualTable(layerObj *layer) { |
2368 | 0 | if (layer->vtable) { |
2369 | 0 | destroyVirtualTable(&layer->vtable); |
2370 | 0 | } |
2371 | 0 | createVirtualTable(&layer->vtable); |
2372 | |
|
2373 | 0 | if (layer->features && layer->connectiontype != MS_GRATICULE) |
2374 | 0 | layer->connectiontype = MS_INLINE; |
2375 | |
|
2376 | 0 | if (layer->tileindex && layer->connectiontype == MS_SHAPEFILE) |
2377 | 0 | layer->connectiontype = MS_TILED_SHAPEFILE; |
2378 | |
|
2379 | 0 | if (layer->type == MS_LAYER_RASTER && layer->connectiontype != MS_WMS && |
2380 | 0 | layer->connectiontype != MS_KERNELDENSITY) |
2381 | 0 | layer->connectiontype = MS_RASTER; |
2382 | |
|
2383 | 0 | switch (layer->connectiontype) { |
2384 | 0 | case (MS_INLINE): |
2385 | 0 | return (msINLINELayerInitializeVirtualTable(layer)); |
2386 | 0 | break; |
2387 | 0 | case (MS_SHAPEFILE): |
2388 | 0 | return (msSHPLayerInitializeVirtualTable(layer)); |
2389 | 0 | break; |
2390 | 0 | case (MS_TILED_SHAPEFILE): |
2391 | 0 | return (msTiledSHPLayerInitializeVirtualTable(layer)); |
2392 | 0 | break; |
2393 | 0 | case (MS_OGR): |
2394 | 0 | return (msOGRLayerInitializeVirtualTable(layer)); |
2395 | 0 | break; |
2396 | 0 | case (MS_FLATGEOBUF): |
2397 | 0 | return (msFlatGeobufLayerInitializeVirtualTable(layer)); |
2398 | 0 | break; |
2399 | 0 | case (MS_POSTGIS): |
2400 | 0 | return (msPostGISLayerInitializeVirtualTable(layer)); |
2401 | 0 | break; |
2402 | 0 | case (MS_WMS): |
2403 | | /* WMS should be treated as a raster layer */ |
2404 | 0 | return (msRASTERLayerInitializeVirtualTable(layer)); |
2405 | 0 | break; |
2406 | 0 | case (MS_KERNELDENSITY): |
2407 | | /* KERNELDENSITY should be treated as a raster layer */ |
2408 | 0 | return (msRASTERLayerInitializeVirtualTable(layer)); |
2409 | 0 | break; |
2410 | 0 | case (MS_ORACLESPATIAL): |
2411 | 0 | return (msOracleSpatialLayerInitializeVirtualTable(layer)); |
2412 | 0 | break; |
2413 | 0 | case (MS_WFS): |
2414 | 0 | return (msWFSLayerInitializeVirtualTable(layer)); |
2415 | 0 | break; |
2416 | 0 | case (MS_GRATICULE): |
2417 | 0 | return (msGraticuleLayerInitializeVirtualTable(layer)); |
2418 | 0 | break; |
2419 | 0 | case (MS_RASTER): |
2420 | 0 | return (msRASTERLayerInitializeVirtualTable(layer)); |
2421 | 0 | break; |
2422 | 0 | case (MS_PLUGIN): |
2423 | 0 | return (msPluginLayerInitializeVirtualTable(layer)); |
2424 | 0 | break; |
2425 | 0 | case (MS_UNION): |
2426 | 0 | return (msUnionLayerInitializeVirtualTable(layer)); |
2427 | 0 | break; |
2428 | 0 | case (MS_UVRASTER): |
2429 | 0 | return (msUVRASTERLayerInitializeVirtualTable(layer)); |
2430 | 0 | break; |
2431 | 0 | case (MS_CONTOUR): |
2432 | 0 | return (msContourLayerInitializeVirtualTable(layer)); |
2433 | 0 | break; |
2434 | 0 | case (MS_RASTER_LABEL): |
2435 | 0 | return (msRasterLabelLayerInitializeVirtualTable(layer)); |
2436 | 0 | break; |
2437 | 0 | default: |
2438 | 0 | msSetError(MS_MISCERR, "Unknown connectiontype, it was %d", |
2439 | 0 | "msInitializeVirtualTable()", layer->connectiontype); |
2440 | 0 | return MS_FAILURE; |
2441 | 0 | break; |
2442 | 0 | } |
2443 | | |
2444 | | /* not reached */ |
2445 | 0 | return MS_FAILURE; |
2446 | 0 | } |
2447 | | |
2448 | | /* |
2449 | | * INLINE: Virtual table functions |
2450 | | */ |
2451 | | |
2452 | | typedef struct { |
2453 | | rectObj searchrect; |
2454 | | int is_relative; /* relative coordinates? */ |
2455 | | } msINLINELayerInfo; |
2456 | | |
2457 | 0 | int msINLINELayerIsOpen(layerObj *layer) { |
2458 | 0 | if (layer->layerinfo) |
2459 | 0 | return (MS_TRUE); |
2460 | 0 | else |
2461 | 0 | return (MS_FALSE); |
2462 | 0 | } |
2463 | | |
2464 | 0 | msINLINELayerInfo *msINLINECreateLayerInfo(void) { |
2465 | 0 | msINLINELayerInfo *layerinfo = msSmallMalloc(sizeof(msINLINELayerInfo)); |
2466 | 0 | layerinfo->searchrect.minx = -1.0; |
2467 | 0 | layerinfo->searchrect.miny = -1.0; |
2468 | 0 | layerinfo->searchrect.maxx = -1.0; |
2469 | 0 | layerinfo->searchrect.maxy = -1.0; |
2470 | 0 | layerinfo->is_relative = MS_FALSE; |
2471 | 0 | return layerinfo; |
2472 | 0 | } |
2473 | | |
2474 | 0 | int msINLINELayerOpen(layerObj *layer) { |
2475 | 0 | msINLINELayerInfo *layerinfo; |
2476 | |
|
2477 | 0 | if (layer->layerinfo) { |
2478 | 0 | if (layer->debug) { |
2479 | 0 | msDebug("msINLINELayerOpen: Layer is already open!\n"); |
2480 | 0 | } |
2481 | 0 | return MS_SUCCESS; /* already open */ |
2482 | 0 | } |
2483 | | |
2484 | | /* |
2485 | | ** Initialize the layerinfo |
2486 | | **/ |
2487 | 0 | layerinfo = msINLINECreateLayerInfo(); |
2488 | |
|
2489 | 0 | layer->currentfeature = |
2490 | 0 | layer->features; /* point to the beginning of the feature list */ |
2491 | |
|
2492 | 0 | layer->layerinfo = (void *)layerinfo; |
2493 | |
|
2494 | 0 | return (MS_SUCCESS); |
2495 | 0 | } |
2496 | | |
2497 | 0 | int msINLINELayerClose(layerObj *layer) { |
2498 | 0 | if (layer->layerinfo) { |
2499 | 0 | free(layer->layerinfo); |
2500 | 0 | layer->layerinfo = NULL; |
2501 | 0 | } |
2502 | |
|
2503 | 0 | return MS_SUCCESS; |
2504 | 0 | } |
2505 | | |
2506 | 0 | int msINLINELayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { |
2507 | 0 | (void)isQuery; |
2508 | 0 | msINLINELayerInfo *layerinfo = NULL; |
2509 | 0 | layerinfo = (msINLINELayerInfo *)layer->layerinfo; |
2510 | |
|
2511 | 0 | layerinfo->searchrect = rect; |
2512 | 0 | layerinfo->is_relative = |
2513 | 0 | (layer->transform != MS_FALSE && layer->transform != MS_TRUE); |
2514 | |
|
2515 | 0 | return MS_SUCCESS; |
2516 | 0 | } |
2517 | | |
2518 | | /* Author: Cristoph Spoerri and Sean Gillies */ |
2519 | 0 | int msINLINELayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record) { |
2520 | 0 | int i = 0; |
2521 | 0 | featureListNodeObjPtr current; |
2522 | |
|
2523 | 0 | int shapeindex = record->shapeindex; /* only index necessary */ |
2524 | |
|
2525 | 0 | current = layer->features; |
2526 | 0 | while (current != NULL && i != shapeindex) { |
2527 | 0 | i++; |
2528 | 0 | current = current->next; |
2529 | 0 | } |
2530 | 0 | if (current == NULL) { |
2531 | 0 | msSetError(MS_SHPERR, "No inline feature with this index.", |
2532 | 0 | "msINLINELayerGetShape()"); |
2533 | 0 | return MS_FAILURE; |
2534 | 0 | } |
2535 | | |
2536 | 0 | if (msCopyShape(&(current->shape), shape) != MS_SUCCESS) { |
2537 | 0 | msSetError( |
2538 | 0 | MS_SHPERR, |
2539 | 0 | "Cannot retrieve inline shape. There some problem with the shape", |
2540 | 0 | "msINLINELayerGetShape()"); |
2541 | 0 | return MS_FAILURE; |
2542 | 0 | } |
2543 | | /* check for the expected size of the values array */ |
2544 | 0 | if (layer->numitems > shape->numvalues) { |
2545 | 0 | shape->values = (char **)msSmallRealloc(shape->values, |
2546 | 0 | sizeof(char *) * (layer->numitems)); |
2547 | 0 | for (i = shape->numvalues; i < layer->numitems; i++) |
2548 | 0 | shape->values[i] = msStrdup(""); |
2549 | 0 | } |
2550 | 0 | msComputeBounds(shape); |
2551 | 0 | return MS_SUCCESS; |
2552 | 0 | } |
2553 | | |
2554 | 0 | int msINLINELayerNextShape(layerObj *layer, shapeObj *shape) { |
2555 | 0 | msINLINELayerInfo *layerinfo = NULL; |
2556 | 0 | shapeObj *s; |
2557 | |
|
2558 | 0 | layerinfo = (msINLINELayerInfo *)layer->layerinfo; |
2559 | |
|
2560 | 0 | while (1) { |
2561 | |
|
2562 | 0 | if (!(layer->currentfeature)) { |
2563 | | /* out of features */ |
2564 | 0 | return (MS_DONE); |
2565 | 0 | } |
2566 | | |
2567 | 0 | s = &(layer->currentfeature->shape); |
2568 | 0 | layer->currentfeature = layer->currentfeature->next; |
2569 | 0 | msComputeBounds(s); |
2570 | |
|
2571 | 0 | if (layerinfo->is_relative || |
2572 | 0 | msRectOverlap(&s->bounds, &layerinfo->searchrect)) { |
2573 | |
|
2574 | 0 | msCopyShape(s, shape); |
2575 | | |
2576 | | /* check for the expected size of the values array */ |
2577 | 0 | if (layer->numitems > shape->numvalues) { |
2578 | 0 | int i; |
2579 | 0 | shape->values = (char **)msSmallRealloc( |
2580 | 0 | shape->values, sizeof(char *) * (layer->numitems)); |
2581 | 0 | for (i = shape->numvalues; i < layer->numitems; i++) |
2582 | 0 | shape->values[i] = msStrdup(""); |
2583 | 0 | shape->numvalues = layer->numitems; |
2584 | 0 | } |
2585 | |
|
2586 | 0 | break; |
2587 | 0 | } |
2588 | 0 | } |
2589 | | |
2590 | 0 | return (MS_SUCCESS); |
2591 | 0 | } |
2592 | | |
2593 | 0 | int msINLINELayerGetNumFeatures(layerObj *layer) { |
2594 | 0 | int i = 0; |
2595 | 0 | featureListNodeObjPtr current; |
2596 | |
|
2597 | 0 | current = layer->features; |
2598 | 0 | while (current != NULL) { |
2599 | 0 | i++; |
2600 | 0 | current = current->next; |
2601 | 0 | } |
2602 | 0 | return i; |
2603 | 0 | } |
2604 | | |
2605 | | /* |
2606 | | Returns an escaped string |
2607 | | */ |
2608 | 0 | char *msLayerEscapeSQLParam(layerObj *layer, const char *pszString) { |
2609 | 0 | if (!layer->vtable) { |
2610 | 0 | int rv = msInitializeVirtualTable(layer); |
2611 | 0 | if (rv != MS_SUCCESS) |
2612 | 0 | return ""; |
2613 | 0 | } |
2614 | 0 | cppcheck_assert(layer->vtable); |
2615 | 0 | return layer->vtable->LayerEscapeSQLParam(layer, pszString); |
2616 | 0 | } |
2617 | | |
2618 | 0 | char *msLayerEscapePropertyName(layerObj *layer, const char *pszString) { |
2619 | 0 | if (!layer->vtable) { |
2620 | 0 | int rv = msInitializeVirtualTable(layer); |
2621 | 0 | if (rv != MS_SUCCESS) |
2622 | 0 | return ""; |
2623 | 0 | } |
2624 | 0 | cppcheck_assert(layer->vtable); |
2625 | 0 | return layer->vtable->LayerEscapePropertyName(layer, pszString); |
2626 | 0 | } |
2627 | | |
2628 | 0 | int msINLINELayerInitializeVirtualTable(layerObj *layer) { |
2629 | 0 | assert(layer != NULL); |
2630 | 0 | assert(layer->vtable != NULL); |
2631 | | |
2632 | | /* layer->vtable->LayerInitItemInfo, use default */ |
2633 | | /* layer->vtable->LayerFreeItemInfo, use default */ |
2634 | 0 | layer->vtable->LayerOpen = msINLINELayerOpen; |
2635 | 0 | layer->vtable->LayerIsOpen = msINLINELayerIsOpen; |
2636 | 0 | layer->vtable->LayerWhichShapes = msINLINELayerWhichShapes; |
2637 | 0 | layer->vtable->LayerNextShape = msINLINELayerNextShape; |
2638 | | /* layer->vtable->LayerGetShapeCount, use default */ |
2639 | 0 | layer->vtable->LayerGetShape = msINLINELayerGetShape; |
2640 | 0 | layer->vtable->LayerClose = msINLINELayerClose; |
2641 | | /* layer->vtable->LayerGetItems, use default */ |
2642 | | |
2643 | | /* |
2644 | | * Original code contained following |
2645 | | * TODO: need to compute extents |
2646 | | */ |
2647 | | /* layer->vtable->LayerGetExtent, use default */ |
2648 | | |
2649 | | /* layer->vtable->LayerGetAutoStyle, use default */ |
2650 | | /* layer->vtable->LayerCloseConnection, use default */ |
2651 | 0 | layer->vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter; |
2652 | | |
2653 | | /* layer->vtable->LayerApplyFilterToLayer, use default */ |
2654 | | |
2655 | | /* layer->vtable->LayerCreateItems, use default */ |
2656 | 0 | layer->vtable->LayerGetNumFeatures = msINLINELayerGetNumFeatures; |
2657 | | |
2658 | | /*layer->vtable->LayerEscapeSQLParam, use default*/ |
2659 | | /*layer->vtable->LayerEscapePropertyName, use default*/ |
2660 | | |
2661 | | /* layer->vtable->LayerEnablePaging, use default */ |
2662 | | /* layer->vtable->LayerGetPaging, use default */ |
2663 | |
|
2664 | 0 | return MS_SUCCESS; |
2665 | 0 | } |