Coverage Report

Created: 2025-06-13 06:18

/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
}