Coverage Report

Created: 2026-04-10 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/MapServer/src/mapunion.cpp
Line
Count
Source
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  Implementation of the union layer data provider (RFC-68).
6
 * Author:   Tamas Szekeres (szekerest@gmail.com).
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
#define _CRT_SECURE_NO_WARNINGS 1
31
32
/* $Id$ */
33
#include <assert.h>
34
#include "mapserver.h"
35
36
#define MSUNION_NUMITEMS 3
37
0
#define MSUNION_SOURCELAYERNAME "Union_SourceLayerName"
38
0
#define MSUNION_SOURCELAYERNAMEINDEX -100
39
0
#define MSUNION_SOURCELAYERGROUP "Union_SourceLayerGroup"
40
0
#define MSUNION_SOURCELAYERGROUPINDEX -101
41
#define MSUNION_SOURCELAYERVISIBLE "Union_SourceLayerVisible"
42
0
#define MSUNION_SOURCELAYERVISIBLEINDEX -102
43
44
typedef struct {
45
  int layerIndex;   /* current source layer index */
46
  int classIndex;   /* current class index */
47
  char *classText;  /* current class text (autostyle) */
48
  int layerCount;   /* number of the source layers */
49
  layerObj *layers; /* structure to the source layers */
50
  int *status;      /* the layer status */
51
  int *classgroup;  /* current array of the valid classes */
52
  int nclasses;     /* number of the valid classes */
53
  reprojectionObj *reprojectorSrcLayerToLayer;
54
  int reprojectorCurSrcLayer;
55
} msUnionLayerInfo;
56
57
/* Close the the combined layer */
58
0
int msUnionLayerClose(layerObj *const layer) {
59
0
  int i;
60
0
  msUnionLayerInfo *layerinfo = (msUnionLayerInfo *)layer->layerinfo;
61
62
0
  if (!layerinfo)
63
0
    return MS_SUCCESS;
64
65
0
  if (!layer->map)
66
0
    return MS_FAILURE;
67
68
0
  msProjectDestroyReprojector(layerinfo->reprojectorSrcLayerToLayer);
69
0
  for (i = 0; i < layerinfo->layerCount; i++) {
70
0
    layerObj *const srclayer = &layerinfo->layers[i];
71
0
    msLayerClose(srclayer);
72
0
    freeLayer(srclayer);
73
0
  }
74
0
  msFree(layerinfo->layers);
75
0
  msFree(layerinfo->status);
76
0
  msFree(layerinfo->classgroup);
77
0
  msFree(layerinfo->classText);
78
0
  msFree(layerinfo);
79
0
  layer->layerinfo = NULL;
80
81
0
  return MS_SUCCESS;
82
0
}
83
84
0
int isScaleInRange(mapObj *map, layerObj *const layer) {
85
0
  if (map->scaledenom > 0) {
86
0
    int i;
87
    /* layer scale boundaries should be checked first */
88
0
    if ((layer->maxscaledenom > 0) && (map->scaledenom > layer->maxscaledenom))
89
0
      return MS_FALSE;
90
91
0
    if ((layer->minscaledenom > 0) && (map->scaledenom <= layer->minscaledenom))
92
0
      return MS_FALSE;
93
94
    /* now check class scale boundaries (all layers *must* pass these tests) */
95
0
    if (layer->numclasses > 0) {
96
0
      for (i = 0; i < layer->numclasses; i++) {
97
0
        if ((layer->_class[i]->maxscaledenom > 0) &&
98
0
            (map->scaledenom > layer->_class[i]->maxscaledenom))
99
0
          continue; /* can skip this one, next class */
100
0
        if ((layer->_class[i]->minscaledenom > 0) &&
101
0
            (map->scaledenom <= layer->_class[i]->minscaledenom))
102
0
          continue; /* can skip this one, next class */
103
104
0
        break; /* can't skip this class (or layer for that matter) */
105
0
      }
106
0
      if (i == layer->numclasses)
107
0
        return MS_FALSE;
108
0
    }
109
110
0
    if (layer->maxscaledenom <= 0 && layer->minscaledenom <= 0) {
111
0
      if ((layer->maxgeowidth > 0) &&
112
0
          ((map->extent.maxx - map->extent.minx) > layer->maxgeowidth))
113
0
        return MS_FALSE;
114
115
0
      if ((layer->mingeowidth > 0) &&
116
0
          ((map->extent.maxx - map->extent.minx) < layer->mingeowidth))
117
0
        return MS_FALSE;
118
0
    }
119
0
  }
120
0
  return MS_TRUE;
121
0
}
122
123
0
int msUnionLayerOpen(layerObj *const layer) {
124
0
  if (layer->layerinfo != NULL) {
125
0
    return MS_SUCCESS; /* Nothing to do... layer is already opened */
126
0
  }
127
128
0
  if (!layer->connection) {
129
0
    msSetError(MS_MISCERR,
130
0
               "The CONNECTION option is not specified for layer: %s",
131
0
               "msUnionLayerOpen()", layer->name);
132
0
    return MS_FAILURE;
133
0
  }
134
135
0
  if (!layer->map) {
136
0
    msSetError(MS_MISCERR, "No map assigned to this layer: %s",
137
0
               "msUnionLayerOpen()", layer->name);
138
0
    return MS_FAILURE;
139
0
  }
140
141
0
  mapObj *map = layer->map;
142
143
0
  msUnionLayerInfo *layerinfo =
144
0
      (msUnionLayerInfo *)calloc(1, sizeof(msUnionLayerInfo));
145
0
  MS_CHECK_ALLOC(layerinfo, sizeof(msUnionLayerInfo), MS_FAILURE);
146
147
0
  layer->layerinfo = layerinfo;
148
0
  layerinfo->layerIndex = 0;
149
150
0
  layerinfo->classgroup = NULL;
151
0
  layerinfo->nclasses = 0;
152
153
0
  layerinfo->layerCount = 0;
154
155
0
  layerinfo->classText = NULL;
156
0
  layerinfo->reprojectorCurSrcLayer = -1;
157
158
0
  const char *pkey = msLayerGetProcessingKey(layer, "UNION_STATUS_CHECK");
159
0
  const bool status_check = (pkey && strcasecmp(pkey, "true") == 0);
160
161
0
  pkey = msLayerGetProcessingKey(layer, "UNION_SCALE_CHECK");
162
0
  const bool scale_check = !(pkey && strcasecmp(pkey, "false") == 0);
163
164
0
  pkey = msLayerGetProcessingKey(layer, "UNION_SRCLAYER_CLOSE_CONNECTION");
165
166
0
  const auto layerNames = msStringSplit(layer->connection, ',');
167
168
0
  if (layerNames.empty()) {
169
0
    msSetError(MS_MISCERR, "No source layers specified in layer: %s",
170
0
               "msUnionLayerOpen()", layer->name);
171
0
    msUnionLayerClose(layer);
172
0
    return MS_FAILURE;
173
0
  }
174
175
0
  const int layerCount = static_cast<int>(layerNames.size());
176
0
  layerinfo->layers = (layerObj *)malloc(layerCount * sizeof(layerObj));
177
0
  MS_CHECK_ALLOC(layerinfo->layers, layerCount * sizeof(layerObj), MS_FAILURE);
178
179
0
  layerinfo->status = (int *)malloc(layerCount * sizeof(int));
180
0
  MS_CHECK_ALLOC(layerinfo->status, layerCount * sizeof(int), MS_FAILURE);
181
182
0
  for (int i = 0; i < layerCount; i++) {
183
0
    const char *layerName = layerNames[i].c_str();
184
0
    const int layerindex = msGetLayerIndex(map, layerName);
185
0
    if (layerindex >= 0 && layerindex < map->numlayers) {
186
0
      const layerObj *const srclayer = map->layers[layerindex];
187
188
0
      if (srclayer->type != layer->type) {
189
0
        msSetError(MS_MISCERR,
190
0
                   "The type of the source layer doesn't match with the union "
191
0
                   "layer: %s",
192
0
                   "msUnionLayerOpen()", srclayer->name);
193
0
        msUnionLayerClose(layer);
194
0
        return MS_FAILURE;
195
0
      }
196
197
      /* we need to create a new layer in order make the single pass query to
198
       * work */
199
0
      layerObj *dstlayer = &layerinfo->layers[i];
200
0
      if (initLayer(dstlayer, map) == -1) {
201
0
        msSetError(MS_MISCERR, "Cannot initialize source layer: %s",
202
0
                   "msUnionLayerOpen()", srclayer->name);
203
0
        msUnionLayerClose(layer);
204
0
        return MS_FAILURE;
205
0
      }
206
207
0
      ++layerinfo->layerCount;
208
209
0
      if (msCopyLayer(dstlayer, srclayer) != MS_SUCCESS) {
210
0
        msSetError(MS_MISCERR, "Cannot copy source layer: %s",
211
0
                   "msUnionLayerOpen()", srclayer->name);
212
0
        msUnionLayerClose(layer);
213
0
        return MS_FAILURE;
214
0
      }
215
216
0
      if (pkey) {
217
        /* override connection flag */
218
0
        msLayerSetProcessingKey(dstlayer, "CLOSE_CONNECTION", pkey);
219
0
      }
220
221
      /* check is we should skip this source (status check) */
222
0
      if (status_check && dstlayer->status == MS_OFF) {
223
0
        layerinfo->status[i] = MS_DONE;
224
0
        continue;
225
0
      }
226
227
      /* check is we should skip this source (scale check) */
228
0
      if (scale_check && isScaleInRange(map, dstlayer) == MS_FALSE) {
229
0
        layerinfo->status[i] = MS_DONE;
230
0
        continue;
231
0
      }
232
233
0
      layerinfo->status[i] = msLayerOpen(dstlayer);
234
0
      if (layerinfo->status[i] != MS_SUCCESS) {
235
0
        msUnionLayerClose(layer);
236
0
        return MS_FAILURE;
237
0
      }
238
0
    } else {
239
0
      msSetError(MS_MISCERR, "Invalid layer: %s", "msUnionLayerOpen()",
240
0
                 layerName);
241
0
      msUnionLayerClose(layer);
242
0
      return MS_FAILURE;
243
0
    }
244
0
  }
245
246
0
  return MS_SUCCESS;
247
0
}
248
249
/* Return MS_TRUE if layer is open, MS_FALSE otherwise. */
250
0
int msUnionLayerIsOpen(layerObj *const layer) {
251
0
  if (layer->layerinfo)
252
0
    return (MS_TRUE);
253
0
  else
254
0
    return (MS_FALSE);
255
0
}
256
257
/* Free the itemindexes array in a layer. */
258
0
void msUnionLayerFreeItemInfo(layerObj *const layer) {
259
0
  int i;
260
0
  msUnionLayerInfo *layerinfo = (msUnionLayerInfo *)layer->layerinfo;
261
262
0
  if (!layerinfo || !layer->map)
263
0
    return;
264
265
0
  msFree(layer->iteminfo);
266
267
0
  layer->iteminfo = NULL;
268
269
0
  for (i = 0; i < layerinfo->layerCount; i++) {
270
0
    msLayerFreeItemInfo(&(layerinfo->layers[i]));
271
0
    if (layerinfo->layers[i].items) {
272
      /* need to remove the source layer items */
273
0
      msFreeCharArray(layerinfo->layers[i].items,
274
0
                      layerinfo->layers[i].numitems);
275
0
      layerinfo->layers[i].items = NULL;
276
0
      layerinfo->layers[i].numitems = 0;
277
0
    }
278
0
  }
279
0
}
280
281
/* clean up expression tokens */
282
0
void msUnionLayerFreeExpressionTokens(layerObj *const layer) {
283
0
  int i, j;
284
0
  msFreeExpressionTokens(&(layer->filter));
285
0
  msFreeExpressionTokens(&(layer->cluster.group));
286
0
  msFreeExpressionTokens(&(layer->cluster.filter));
287
0
  for (i = 0; i < layer->numclasses; i++) {
288
0
    msFreeExpressionTokens(&(layer->_class[i]->expression));
289
0
    msFreeExpressionTokens(&(layer->_class[i]->text));
290
0
    for (j = 0; j < layer->_class[i]->numstyles; j++)
291
0
      msFreeExpressionTokens(&(layer->_class[i]->styles[j]->_geomtransform));
292
0
  }
293
0
}
294
295
/* allocate the iteminfo index array - same order as the item list */
296
0
int msUnionLayerInitItemInfo(layerObj *const layer) {
297
0
  int i, numitems;
298
0
  int *itemindexes;
299
0
  char *itemlist = NULL;
300
301
0
  msUnionLayerInfo *layerinfo = (msUnionLayerInfo *)layer->layerinfo;
302
303
0
  if (layer->numitems == 0) {
304
0
    return MS_SUCCESS;
305
0
  }
306
307
0
  if (!layerinfo || !layer->map)
308
0
    return MS_FAILURE;
309
310
  /* Cleanup any previous item selection */
311
0
  msUnionLayerFreeItemInfo(layer);
312
313
0
  layer->iteminfo = (int *)malloc(sizeof(int) * layer->numitems);
314
0
  MS_CHECK_ALLOC(layer->iteminfo, sizeof(int) * layer->numitems, MS_FAILURE);
315
316
0
  itemindexes = (int *)layer->iteminfo;
317
318
  /* check whether we require attributes from the source layers also */
319
0
  numitems = 0;
320
0
  for (i = 0; i < layer->numitems; i++) {
321
0
    if (EQUAL(layer->items[i], MSUNION_SOURCELAYERNAME))
322
0
      itemindexes[i] = MSUNION_SOURCELAYERNAMEINDEX;
323
0
    else if (EQUAL(layer->items[i], MSUNION_SOURCELAYERGROUP))
324
0
      itemindexes[i] = MSUNION_SOURCELAYERGROUPINDEX;
325
0
    else if (EQUAL(layer->items[i], MSUNION_SOURCELAYERVISIBLE))
326
0
      itemindexes[i] = MSUNION_SOURCELAYERVISIBLEINDEX;
327
0
    else {
328
0
      itemindexes[i] = numitems++;
329
0
      if (itemlist) {
330
0
        itemlist = msStringConcatenate(itemlist, ",");
331
0
        itemlist = msStringConcatenate(itemlist, layer->items[i]);
332
0
      } else {
333
0
        itemlist = msStrdup(layer->items[i]);
334
0
      }
335
0
    }
336
0
  }
337
338
0
  for (i = 0; i < layerinfo->layerCount; i++) {
339
0
    layerObj *const srclayer = &(layerinfo->layers[i]);
340
341
0
    if (layerinfo->status[i] != MS_SUCCESS)
342
0
      continue; /* skip empty layers */
343
344
0
    msUnionLayerFreeExpressionTokens(srclayer);
345
346
0
    if (itemlist) {
347
      /* get items requested by the union layer plus the required items */
348
0
      msLayerSetProcessingKey(srclayer, "ITEMS", itemlist);
349
0
      if (msLayerWhichItems(srclayer, MS_TRUE, NULL) != MS_SUCCESS) {
350
0
        msFree(itemlist);
351
0
        return MS_FAILURE;
352
0
      }
353
0
    } else {
354
      /* get only the required items */
355
0
      if (msLayerWhichItems(srclayer, MS_FALSE, NULL) != MS_SUCCESS)
356
0
        return MS_FAILURE;
357
0
    }
358
0
  }
359
360
0
  msFree(itemlist);
361
0
  return MS_SUCCESS;
362
0
}
363
364
// cppcheck-suppress passedByValue
365
0
int msUnionLayerWhichShapes(layerObj *const layer, rectObj rect, int isQuery) {
366
0
  msUnionLayerInfo *layerinfo = (msUnionLayerInfo *)layer->layerinfo;
367
368
0
  if (!layerinfo || !layer->map)
369
0
    return MS_FAILURE;
370
371
0
  for (int i = 0; i < layerinfo->layerCount; i++) {
372
0
    layerObj *const srclayer = &layerinfo->layers[i];
373
374
0
    if (layerinfo->status[i] != MS_SUCCESS)
375
0
      continue; /* skip empty layers */
376
377
0
    if (layer->styleitem && layer->numitems == 0) {
378
      /* need to initialize items */
379
0
      msUnionLayerFreeExpressionTokens(srclayer);
380
381
      /* get only the required items */
382
0
      if (msLayerWhichItems(srclayer, MS_FALSE, NULL) != MS_SUCCESS)
383
0
        return MS_FAILURE;
384
0
    }
385
386
0
    rectObj srcRect = rect;
387
388
0
    if (srclayer->transform == MS_TRUE && srclayer->project &&
389
0
        layer->transform == MS_TRUE && layer->project &&
390
0
        msProjectionsDiffer(&(srclayer->projection), &(layer->projection)))
391
0
      msProjectRect(&layer->projection, &srclayer->projection,
392
0
                    &srcRect); /* project the searchrect to source coords */
393
394
0
    layerinfo->status[i] = msLayerWhichShapes(srclayer, srcRect, isQuery);
395
0
    if (layerinfo->status[i] == MS_FAILURE)
396
0
      return MS_FAILURE;
397
0
  }
398
399
0
  layerinfo->layerIndex = 0;
400
0
  layerObj *const srclayer = &layerinfo->layers[0];
401
402
0
  msFree(layerinfo->classgroup);
403
404
0
  layerinfo->classgroup = NULL;
405
0
  layerinfo->nclasses = 0;
406
407
0
  if (srclayer->classgroup && srclayer->numclasses > 0)
408
0
    layerinfo->classgroup =
409
0
        msAllocateValidClassGroups(srclayer, &layerinfo->nclasses);
410
411
0
  return MS_SUCCESS;
412
0
}
413
414
static int BuildFeatureAttributes(layerObj *const layer,
415
0
                                  const layerObj *srclayer, shapeObj *shape) {
416
0
  const int *const itemindexes = static_cast<const int *>(layer->iteminfo);
417
418
0
  char **values =
419
0
      static_cast<char **>(msSmallMalloc(sizeof(char *) * (layer->numitems)));
420
0
  MS_CHECK_ALLOC(values, layer->numitems * sizeof(char *), MS_FAILURE);
421
0
  ;
422
423
0
  for (int i = 0; i < layer->numitems; i++) {
424
0
    if (itemindexes[i] == MSUNION_SOURCELAYERNAMEINDEX)
425
0
      values[i] = msStrdup(srclayer->name);
426
0
    else if (itemindexes[i] == MSUNION_SOURCELAYERGROUPINDEX)
427
0
      values[i] = msStrdup(srclayer->group);
428
0
    else if (itemindexes[i] == MSUNION_SOURCELAYERVISIBLEINDEX) {
429
0
      if (srclayer->status == MS_OFF)
430
0
        values[i] = msStrdup("0");
431
0
      else
432
0
        values[i] = msStrdup("1");
433
0
    } else if (shape->values[itemindexes[i]])
434
0
      values[i] = msStrdup(shape->values[itemindexes[i]]);
435
0
    else
436
0
      values[i] = msStrdup("");
437
0
  }
438
439
0
  if (shape->values)
440
0
    msFreeCharArray(shape->values, shape->numvalues);
441
442
0
  shape->values = values;
443
0
  shape->numvalues = layer->numitems;
444
445
0
  return MS_SUCCESS;
446
0
}
447
448
/* find the next shape with the appropriate shape type */
449
/* also, load in the attribute data */
450
/* MS_DONE => no more data */
451
0
int msUnionLayerNextShape(layerObj *const layer, shapeObj *shape) {
452
0
  msUnionLayerInfo *layerinfo = (msUnionLayerInfo *)layer->layerinfo;
453
454
0
  if (!layerinfo || !layer->map)
455
0
    return MS_FAILURE;
456
457
0
  if (layerinfo->layerIndex < 0 ||
458
0
      layerinfo->layerIndex >= layerinfo->layerCount)
459
0
    return MS_FAILURE;
460
461
0
  int rv = MS_DONE;
462
463
0
  while (layerinfo->layerIndex < layerinfo->layerCount) {
464
0
    layerObj *srclayer = &layerinfo->layers[layerinfo->layerIndex];
465
0
    if (layerinfo->status[layerinfo->layerIndex] == MS_SUCCESS) {
466
0
      while ((rv = srclayer->vtable->LayerNextShape(srclayer, shape)) ==
467
0
             MS_SUCCESS) {
468
0
        if (layer->styleitem) {
469
          /* need to retrieve the source layer classindex if styleitem AUTO is
470
           * set */
471
0
          layerinfo->classIndex =
472
0
              msShapeGetClass(srclayer, layer->map, shape,
473
0
                              layerinfo->classgroup, layerinfo->nclasses);
474
0
          if (layerinfo->classIndex < 0 ||
475
0
              layerinfo->classIndex >= srclayer->numclasses) {
476
            /*  this shape is not visible, skip it */
477
0
            msFreeShape(shape);
478
0
            continue;
479
0
          }
480
0
          if (srclayer->styleitem &&
481
0
              strcasecmp(srclayer->styleitem, "AUTO") != 0) {
482
            /* Generic feature style handling as per RFC-61 */
483
0
            msLayerGetFeatureStyle(layer->map, srclayer,
484
0
                                   srclayer->_class[layerinfo->classIndex],
485
0
                                   shape);
486
0
          }
487
          /* set up annotation */
488
0
          msFree(layerinfo->classText);
489
0
          layerinfo->classText = NULL;
490
0
          if (srclayer->_class[layerinfo->classIndex]->numlabels > 0) {
491
            /* pull text from the first label only */
492
0
            if (msGetLabelStatus(
493
0
                    layer->map, layer, shape,
494
0
                    srclayer->_class[layerinfo->classIndex]->labels[0]) ==
495
0
                MS_ON) {
496
0
              layerinfo->classText = msShapeGetLabelAnnotation(
497
0
                  layer, shape,
498
0
                  srclayer->_class[layerinfo->classIndex]->labels[0]);
499
0
            }
500
0
          }
501
0
        }
502
503
        /* reproject to the target layer */
504
0
        if (layerinfo->reprojectorCurSrcLayer != layerinfo->layerIndex) {
505
0
          msProjectDestroyReprojector(layerinfo->reprojectorSrcLayerToLayer);
506
0
          layerinfo->reprojectorSrcLayerToLayer = NULL;
507
0
          layerinfo->reprojectorCurSrcLayer = layerinfo->layerIndex;
508
0
          if (srclayer->project && msProjectionsDiffer(&(srclayer->projection),
509
0
                                                       &(layer->projection)))
510
0
            layerinfo->reprojectorSrcLayerToLayer = msProjectCreateReprojector(
511
0
                &(srclayer->projection), &(layer->projection));
512
0
          else
513
0
            srclayer->project = MS_FALSE;
514
0
        }
515
0
        if (layerinfo->reprojectorSrcLayerToLayer)
516
0
          msProjectShapeEx(layerinfo->reprojectorSrcLayerToLayer, shape);
517
518
        /* update the layer styles with the bound values */
519
0
        if (msBindLayerToShape(srclayer, shape, MS_FALSE) != MS_SUCCESS)
520
0
          return MS_FAILURE;
521
522
0
        shape->tileindex = layerinfo->layerIndex;
523
524
        /* construct the item array */
525
0
        if (layer->iteminfo)
526
0
          rv = BuildFeatureAttributes(layer, srclayer, shape);
527
528
        /* check the layer filter condition */
529
0
        if (layer->filter.string != NULL && layer->numitems > 0 &&
530
0
            layer->iteminfo) {
531
0
          if (layer->filter.type == MS_EXPRESSION &&
532
0
              layer->filter.tokens == NULL)
533
0
            msTokenizeExpression(&(layer->filter), layer->items,
534
0
                                 &(layer->numitems));
535
536
0
          if (!msEvalExpression(layer, shape, &(layer->filter),
537
0
                                layer->filteritemindex)) {
538
            /* this shape is filtered */
539
0
            msFreeShape(shape);
540
0
            continue;
541
0
          }
542
0
        }
543
544
0
        return rv;
545
0
      }
546
0
    }
547
548
0
    ++layerinfo->layerIndex;
549
0
    if (layerinfo->layerIndex == layerinfo->layerCount) {
550
0
      layerinfo->layerIndex = 0;
551
0
      return MS_DONE;
552
0
    }
553
554
    /* allocate the classgroups for the next layer */
555
0
    msFree(layerinfo->classgroup);
556
557
0
    layerinfo->classgroup = NULL;
558
0
    layerinfo->nclasses = 0;
559
560
0
    if (srclayer->classgroup && srclayer->numclasses > 0)
561
0
      layerinfo->classgroup =
562
0
          msAllocateValidClassGroups(srclayer, &layerinfo->nclasses);
563
0
  }
564
565
0
  return rv;
566
0
}
567
568
/* Random access of the feature. */
569
int msUnionLayerGetShape(layerObj *const layer, shapeObj *shape,
570
0
                         resultObj *record) {
571
0
  const long tile = record->tileindex;
572
0
  msUnionLayerInfo *layerinfo = (msUnionLayerInfo *)layer->layerinfo;
573
574
0
  if (!layerinfo || !layer->map)
575
0
    return MS_FAILURE;
576
577
0
  if (tile < 0 || tile >= layerinfo->layerCount) {
578
0
    msSetError(MS_MISCERR, "Invalid tile index: %s", "msUnionLayerGetShape()",
579
0
               layer->name);
580
0
    return MS_FAILURE;
581
0
  }
582
583
0
  layerObj *const srclayer = &layerinfo->layers[tile];
584
0
  record->tileindex = 0;
585
0
  int rv = srclayer->vtable->LayerGetShape(srclayer, shape, record);
586
0
  record->tileindex = tile;
587
588
0
  if (rv == MS_SUCCESS) {
589
    /* reproject to the target layer */
590
0
    if (layerinfo->reprojectorCurSrcLayer != tile) {
591
0
      msProjectDestroyReprojector(layerinfo->reprojectorSrcLayerToLayer);
592
0
      layerinfo->reprojectorSrcLayerToLayer = NULL;
593
0
      layerinfo->reprojectorCurSrcLayer = tile;
594
0
      if (srclayer->project &&
595
0
          msProjectionsDiffer(&(srclayer->projection), &(layer->projection)))
596
0
        layerinfo->reprojectorSrcLayerToLayer = msProjectCreateReprojector(
597
0
            &(srclayer->projection), &(layer->projection));
598
0
      else
599
0
        srclayer->project = MS_FALSE;
600
0
    }
601
0
    if (layerinfo->reprojectorSrcLayerToLayer)
602
0
      msProjectShapeEx(layerinfo->reprojectorSrcLayerToLayer, shape);
603
604
0
    shape->tileindex = tile;
605
606
    /* construct the item array */
607
0
    if (layer->iteminfo)
608
0
      rv = BuildFeatureAttributes(layer, srclayer, shape);
609
0
  }
610
611
0
  return rv;
612
0
}
613
614
/* Query for the items collection */
615
0
int msUnionLayerGetItems(layerObj *const layer) {
616
  /* we support certain built in attributes */
617
0
  layer->numitems = 2;
618
0
  layer->items =
619
0
      static_cast<char **>(msSmallMalloc(sizeof(char *) * (layer->numitems)));
620
0
  MS_CHECK_ALLOC(layer->items, layer->numitems * sizeof(char *), MS_FAILURE);
621
0
  layer->items[0] = msStrdup(MSUNION_SOURCELAYERNAME);
622
0
  layer->items[1] = msStrdup(MSUNION_SOURCELAYERGROUP);
623
624
0
  return msUnionLayerInitItemInfo(layer);
625
0
}
626
627
0
int msUnionLayerGetNumFeatures(layerObj *const layer) {
628
0
  msUnionLayerInfo *layerinfo = (msUnionLayerInfo *)layer->layerinfo;
629
630
0
  if (!layerinfo || !layer->map)
631
0
    return 0;
632
633
0
  int numFeatures = 0;
634
635
0
  for (int i = 0; i < layerinfo->layerCount; i++) {
636
0
    if (layerinfo->status[i] != MS_SUCCESS)
637
0
      continue; /* skip empty layers */
638
639
0
    int c = msLayerGetNumFeatures(&(layerinfo->layers[i]));
640
0
    if (c > 0)
641
0
      numFeatures += c;
642
0
  }
643
644
0
  return numFeatures;
645
0
}
646
647
static int msUnionLayerGetAutoStyle(mapObj *map, layerObj *const layer,
648
0
                                    classObj *c, shapeObj *shape) {
649
0
  msUnionLayerInfo *layerinfo = (msUnionLayerInfo *)layer->layerinfo;
650
651
0
  if (!layerinfo || !layer->map)
652
0
    return MS_FAILURE;
653
654
0
  if (shape->tileindex < 0 || shape->tileindex >= layerinfo->layerCount) {
655
0
    msSetError(MS_MISCERR, "Invalid tile index: %s",
656
0
               "msUnionLayerGetAutoStyle()", layer->name);
657
0
    return MS_FAILURE;
658
0
  }
659
660
0
  layerObj *const srclayer = &layerinfo->layers[shape->tileindex];
661
662
0
  if (srclayer->styleitem && strcasecmp(srclayer->styleitem, "AUTO") == 0) {
663
0
    const int tileindex = shape->tileindex;
664
0
    shape->tileindex = 0;
665
0
    int rv = msLayerGetAutoStyle(map, srclayer, c, shape);
666
0
    shape->tileindex = tileindex;
667
0
    return rv;
668
0
  } else {
669
0
    const classObj *src = srclayer->_class[layerinfo->classIndex];
670
    /* copy the style from the current class index */
671
    /* free any previous styles on the dst layer */
672
673
0
    resetClassStyle(c);
674
675
0
    for (int i = 0; i < src->numstyles; i++) {
676
0
      if (msMaybeAllocateClassStyle(c, i))
677
0
        return MS_FAILURE;
678
679
0
      if (msCopyStyle(c->styles[i], src->styles[i]) != MS_SUCCESS) {
680
0
        msSetError(MS_MEMERR, "Failed to copy style.",
681
0
                   "msUnionLayerGetAutoStyle()");
682
0
        return MS_FAILURE;
683
0
      }
684
      /* remove the bindings on the style */
685
0
      for (int j = 0; j < MS_STYLE_BINDING_LENGTH; j++) {
686
0
        msFree(c->styles[i]->bindings[j].item);
687
0
        c->styles[i]->bindings[j].item = NULL;
688
0
      }
689
0
      c->styles[i]->numbindings = 0;
690
0
    }
691
692
0
    for (int i = 0; i < src->numlabels; i++) {
693
      // RFC77 TODO: allocation need to be done, but is the right way (from
694
      // mapcopy.c)?
695
0
      if (msGrowClassLabels(c) == NULL)
696
0
        return MS_FAILURE;
697
0
      initLabel(c->labels[i]);
698
699
0
      if (msCopyLabel(c->labels[i], src->labels[i]) != MS_SUCCESS) {
700
0
        msSetError(MS_MEMERR, "Failed to copy label.",
701
0
                   "msUnionLayerGetAutoStyle()");
702
0
        return MS_FAILURE;
703
0
      }
704
705
      /* remove the bindings on the label */
706
0
      for (int j = 0; j < MS_LABEL_BINDING_LENGTH; j++) {
707
0
        msFree(c->labels[i]->bindings[j].item);
708
0
        c->labels[i]->bindings[j].item = NULL;
709
0
      }
710
0
      c->labels[i]->numbindings = 0;
711
0
    }
712
0
    c->numlabels = src->numlabels;
713
714
0
    c->layer = layer;
715
0
    c->text.string = layerinfo->classText;
716
0
    layerinfo->classText = NULL;
717
0
  }
718
0
  return MS_SUCCESS;
719
0
}
720
721
0
int msUnionLayerCopyVirtualTable(layerVTableObj *vtable) {
722
0
  vtable->LayerInitItemInfo = msUnionLayerInitItemInfo;
723
0
  vtable->LayerFreeItemInfo = msUnionLayerFreeItemInfo;
724
0
  vtable->LayerOpen = msUnionLayerOpen;
725
0
  vtable->LayerIsOpen = msUnionLayerIsOpen;
726
0
  vtable->LayerWhichShapes = msUnionLayerWhichShapes;
727
0
  vtable->LayerNextShape = msUnionLayerNextShape;
728
0
  vtable->LayerGetShape = msUnionLayerGetShape;
729
  /* layer->vtable->LayerGetShapeCount, use default */
730
0
  vtable->LayerClose = msUnionLayerClose;
731
732
0
  vtable->LayerGetItems = msUnionLayerGetItems;
733
0
  vtable->LayerCloseConnection = msUnionLayerClose;
734
0
  vtable->LayerGetAutoStyle = msUnionLayerGetAutoStyle;
735
736
0
  vtable->LayerGetNumFeatures = msUnionLayerGetNumFeatures;
737
738
0
  return MS_SUCCESS;
739
0
}
740
741
0
int msUnionLayerInitializeVirtualTable(layerObj *const layer) {
742
0
  assert(layer != NULL);
743
0
  assert(layer->vtable != NULL);
744
745
0
  return msUnionLayerCopyVirtualTable(layer->vtable);
746
0
}