Coverage Report

Created: 2025-11-16 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/MapServer/src/mapobject.c
Line
Count
Source
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  Functions for operating on a mapObj that don't belong in a
6
 *           more specific file such as mapfile.c, or mapdraw.c.
7
 * Author:   Frank Warmerdam, warmerdam@pobox.com
8
 *
9
 ******************************************************************************
10
 * Copyright (c) 2004, Frank Warmerdam
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a
13
 * copy of this software and associated documentation files (the "Software"),
14
 * to deal in the Software without restriction, including without limitation
15
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16
 * and/or sell copies of the Software, and to permit persons to whom the
17
 * Software is furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in
20
 * all copies of this Software or works derived from this Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28
 * DEALINGS IN THE SOFTWARE.
29
 ****************************************************************************/
30
31
#include "mapserver.h"
32
#include "mapows.h"
33
34
#include "gdal.h"
35
#include "cpl_conv.h"
36
37
void freeWeb(webObj *web);
38
void freeScalebar(scalebarObj *scalebar);
39
void freeReferenceMap(referenceMapObj *ref);
40
void freeLegend(legendObj *legend);
41
42
/************************************************************************/
43
/*                            msNewMapObj()                             */
44
/*                                                                      */
45
/*      Create a new initialized map object.                            */
46
/************************************************************************/
47
48
0
mapObj *msNewMapObj() {
49
0
  mapObj *map = NULL;
50
51
  /* create an empty map, no layers etc... */
52
0
  map = (mapObj *)calloc(1, sizeof(mapObj));
53
54
0
  if (!map) {
55
0
    msSetError(MS_MEMERR, NULL, "msCreateMap()");
56
0
    return NULL;
57
0
  }
58
59
0
  if (initMap(map) == -1) {
60
0
    msFreeMap(map);
61
0
    return NULL;
62
0
  }
63
64
0
  if (msPostMapParseOutputFormatSetup(map) == MS_FAILURE) {
65
0
    msFreeMap(map);
66
0
    return NULL;
67
0
  }
68
69
0
  return map;
70
0
}
71
72
/************************************************************************/
73
/*                             msFreeMap()                              */
74
/************************************************************************/
75
76
22.8k
void msFreeMap(mapObj *map) {
77
22.8k
  int i;
78
79
22.8k
  if (!map)
80
11.2k
    return;
81
82
  /* printf("msFreeMap(): maybe freeing map at %p count=%d.\n",map,
83
   * map->refcount); */
84
11.6k
  if (MS_REFCNT_DECR_IS_NOT_ZERO(map)) {
85
0
    return;
86
0
  }
87
11.6k
  if (map->debug >= MS_DEBUGLEVEL_VV)
88
1
    msDebug("msFreeMap(): freeing map at %p.\n", map);
89
90
11.6k
  msCloseConnections(map);
91
92
11.6k
  msFree(map->name);
93
11.6k
  msFree(map->shapepath);
94
11.6k
  msFree(map->mappath);
95
96
11.6k
  msFreeProjection(&(map->projection));
97
11.6k
  msFreeProjection(&(map->latlon));
98
11.6k
  msProjectionContextReleaseToPool(map->projContext);
99
100
11.6k
  msFreeLabelCache(&(map->labelcache));
101
102
11.6k
  msFree(map->imagetype);
103
104
11.6k
  msFreeFontSet(&(map->fontset));
105
106
11.6k
  msFreeSymbolSet(&map->symbolset); /* free symbols */
107
11.6k
  msFree(map->symbolset.filename);
108
109
11.6k
  freeWeb(&(map->web));
110
111
11.6k
  freeScalebar(&(map->scalebar));
112
11.6k
  freeReferenceMap(&(map->reference));
113
11.6k
  freeLegend(&(map->legend));
114
115
319k
  for (i = 0; i < map->maxlayers; i++) {
116
307k
    if (GET_LAYER(map, i) != NULL) {
117
30.8k
      GET_LAYER(map, i)->map = NULL;
118
30.8k
      if (freeLayer((GET_LAYER(map, i))) == MS_SUCCESS)
119
30.8k
        free(GET_LAYER(map, i));
120
30.8k
    }
121
307k
  }
122
11.6k
  msFree(map->layers);
123
124
11.6k
  if (map->layerorder)
125
4.78k
    free(map->layerorder);
126
127
11.6k
  msFree(map->templatepattern);
128
11.6k
  msFree(map->datapattern);
129
11.6k
  msFreeHashItems(&(map->configoptions));
130
11.6k
  if (map->outputformat && map->outputformat->refcount > 0 &&
131
1.18k
      --map->outputformat->refcount < 1)
132
0
    msFreeOutputFormat(map->outputformat);
133
134
12.7k
  for (i = 0; i < map->numoutputformats; i++) {
135
1.18k
    if (map->outputformatlist[i]->refcount > 0 &&
136
1.18k
        --map->outputformatlist[i]->refcount < 1)
137
1.18k
      msFreeOutputFormat(map->outputformatlist[i]);
138
1.18k
  }
139
11.6k
  if (map->outputformatlist != NULL)
140
1.18k
    msFree(map->outputformatlist);
141
142
11.6k
  msFreeQuery(&(map->query));
143
144
#ifdef USE_V8_MAPSCRIPT
145
  if (map->v8context)
146
    msV8FreeContext(map);
147
#endif
148
149
11.6k
  msFree(map);
150
11.6k
}
151
152
/************************************************************************/
153
/*                         msGetConfigOption()                          */
154
/************************************************************************/
155
156
const char *msGetConfigOption(mapObj *map, const char *key)
157
158
0
{
159
0
  return msLookupHashTable(&(map->configoptions), key);
160
0
}
161
162
/************************************************************************/
163
/*                         msSetConfigOption()                          */
164
/************************************************************************/
165
166
int msSetConfigOption(mapObj *map, const char *key, const char *value)
167
168
4.81k
{
169
  /* We have special "early" handling of this so that it will be */
170
  /* in effect when the projection blocks are parsed and pj_init is called. */
171
4.81k
  if (strcasecmp(key, "PROJ_DATA") == 0 || strcasecmp(key, "PROJ_LIB") == 0) {
172
    /* value may be relative to map path */
173
539
    msSetPROJ_DATA(value, map->mappath);
174
539
  }
175
176
  /* Same for MS_ERRORFILE, we want it to kick in as early as possible
177
   * to catch parsing errors.
178
   * Value can be relative to mapfile, unless it's already absolute
179
   */
180
4.81k
  if (strcasecmp(key, "MS_ERRORFILE") == 0) {
181
296
    if (msSetErrorFile(value, map->mappath) != MS_SUCCESS)
182
3
      return MS_FAILURE;
183
296
  }
184
185
4.80k
  if (msLookupHashTable(&(map->configoptions), key) != NULL)
186
2.28k
    msRemoveHashTable(&(map->configoptions), key);
187
4.80k
  msInsertHashTable(&(map->configoptions), key, value);
188
189
4.80k
  return MS_SUCCESS;
190
4.81k
}
191
192
/************************************************************************/
193
/*                         msTestConfigOption()                         */
194
/************************************************************************/
195
196
int msTestConfigOption(mapObj *map, const char *key, int default_result)
197
198
0
{
199
0
  const char *result = msGetConfigOption(map, key);
200
201
0
  if (result == NULL)
202
0
    return default_result;
203
204
0
  if (strcasecmp(result, "YES") == 0 || strcasecmp(result, "ON") == 0 ||
205
0
      strcasecmp(result, "TRUE") == 0)
206
0
    return MS_TRUE;
207
0
  else
208
0
    return MS_FALSE;
209
0
}
210
211
/************************************************************************/
212
/*                      msApplyMapConfigOptions()                       */
213
/************************************************************************/
214
215
void msApplyMapConfigOptions(mapObj *map)
216
217
1.18k
{
218
1.18k
  const char *key;
219
220
3.05k
  for (key = msFirstKeyFromHashTable(&(map->configoptions)); key != NULL;
221
1.86k
       key = msNextKeyFromHashTable(&(map->configoptions), key)) {
222
1.86k
    const char *value = msLookupHashTable(&(map->configoptions), key);
223
1.86k
    if (strcasecmp(key, "PROJ_DATA") == 0 || strcasecmp(key, "PROJ_LIB") == 0) {
224
25
      msSetPROJ_DATA(value, map->mappath);
225
1.84k
    } else if (strcasecmp(key, "MS_ERRORFILE") == 0) {
226
0
      msSetErrorFile(value, map->mappath);
227
1.84k
    } else {
228
1.84k
      CPLSetConfigOption(key, value);
229
1.84k
    }
230
1.86k
  }
231
1.18k
}
232
233
/************************************************************************/
234
/*                         msMapIgnoreMissingData() */
235
/************************************************************************/
236
237
0
int msMapIgnoreMissingData(mapObj *map) {
238
0
  const char *result = msGetConfigOption(map, "ON_MISSING_DATA");
239
0
  const int default_result =
240
0
#ifndef IGNORE_MISSING_DATA
241
0
      MS_MISSING_DATA_FAIL;
242
#else
243
      MS_MISSING_DATA_LOG;
244
#endif
245
246
0
  if (result == NULL)
247
0
    return default_result;
248
249
0
  if (strcasecmp(result, "FAIL") == 0)
250
0
    return MS_MISSING_DATA_FAIL;
251
0
  else if (strcasecmp(result, "LOG") == 0)
252
0
    return MS_MISSING_DATA_LOG;
253
0
  else if (strcasecmp(result, "IGNORE") == 0)
254
0
    return MS_MISSING_DATA_IGNORE;
255
256
0
  return default_result;
257
0
}
258
259
/************************************************************************/
260
/*                           msMapSetExtent()                           */
261
/************************************************************************/
262
263
int msMapSetExtent(mapObj *map, double minx, double miny, double maxx,
264
0
                   double maxy) {
265
266
0
  map->extent.minx = minx;
267
0
  map->extent.miny = miny;
268
0
  map->extent.maxx = maxx;
269
0
  map->extent.maxy = maxy;
270
271
0
  if (!MS_VALID_EXTENT(map->extent)) {
272
0
    msSetError(MS_MISCERR,
273
0
               "Given map extent is invalid. Check that it "
274
0
               "is in the form: minx, miny, maxx, maxy",
275
0
               "setExtent()");
276
0
    return MS_FAILURE;
277
0
  }
278
279
0
  map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height);
280
281
  /* if the map size is also set, recompute scale, ignore errors? */
282
0
  if (map->width != -1 || map->height != -1)
283
0
    msCalculateScale(map->extent, map->units, map->width, map->height,
284
0
                     map->resolution, &(map->scaledenom));
285
286
0
  return msMapComputeGeotransform(map);
287
0
}
288
289
/************************************************************************/
290
/*                           msMapOffsetExtent()                        */
291
/************************************************************************/
292
293
0
int msMapOffsetExtent(mapObj *map, double x, double y) {
294
0
  return msMapSetExtent(map, map->extent.minx + x, map->extent.miny + y,
295
0
                        map->extent.maxx + x, map->extent.maxy + y);
296
0
}
297
298
/************************************************************************/
299
/*                           msMapScaleExtent()                         */
300
/************************************************************************/
301
302
int msMapScaleExtent(mapObj *map, double zoomfactor, double minscaledenom,
303
0
                     double maxscaledenom) {
304
0
  double geo_width, geo_height, center_x, center_y, md;
305
306
0
  if (zoomfactor <= 0.0) {
307
0
    msSetError(MS_MISCERR, "The given zoomfactor is invalid",
308
0
               "msMapScaleExtent()");
309
0
  }
310
311
0
  geo_width = map->extent.maxx - map->extent.minx;
312
0
  geo_height = map->extent.maxy - map->extent.miny;
313
314
0
  center_x = map->extent.minx + geo_width * 0.5;
315
0
  center_y = map->extent.miny + geo_height * 0.5;
316
317
0
  geo_width *= zoomfactor;
318
319
0
  if (minscaledenom > 0 || maxscaledenom > 0) {
320
    /* ensure we are within the valid scale domain */
321
0
    md = (map->width - 1) /
322
0
         (map->resolution * msInchesPerUnit(map->units, center_y));
323
0
    if (minscaledenom > 0 && geo_width < minscaledenom * md)
324
0
      geo_width = minscaledenom * md;
325
0
    if (maxscaledenom > 0 && geo_width > maxscaledenom * md)
326
0
      geo_width = maxscaledenom * md;
327
0
  }
328
329
0
  geo_width *= 0.5;
330
0
  geo_height = geo_width * map->height / map->width;
331
332
0
  return msMapSetExtent(map, center_x - geo_width, center_y - geo_height,
333
0
                        center_x + geo_width, center_y + geo_height);
334
0
}
335
336
/************************************************************************/
337
/*                           msMapSetCenter()                           */
338
/************************************************************************/
339
340
0
int msMapSetCenter(mapObj *map, pointObj *center) {
341
0
  return msMapOffsetExtent(
342
0
      map, center->x - (map->extent.minx + map->extent.maxx) * 0.5,
343
0
      center->y - (map->extent.miny + map->extent.maxy) * 0.5);
344
0
}
345
346
/************************************************************************/
347
/*                           msMapSetRotation()                         */
348
/************************************************************************/
349
350
int msMapSetRotation(mapObj *map, double rotation_angle)
351
352
499
{
353
499
  map->gt.rotation_angle = rotation_angle;
354
499
  if (map->gt.rotation_angle != 0.0)
355
154
    map->gt.need_geotransform = MS_TRUE;
356
345
  else
357
345
    map->gt.need_geotransform = MS_FALSE;
358
359
499
  return msMapComputeGeotransform(map);
360
499
}
361
362
/************************************************************************/
363
/*                             msMapSetSize()                           */
364
/************************************************************************/
365
366
int msMapSetSize(mapObj *map, int width, int height)
367
368
0
{
369
0
  map->width = width;
370
0
  map->height = height;
371
372
0
  return msMapComputeGeotransform(map); /* like SetRotation -- sean */
373
0
}
374
375
/************************************************************************/
376
/*                      msMapComputeGeotransform()                      */
377
/************************************************************************/
378
379
extern int InvGeoTransform(double *gt_in, double *gt_out);
380
381
int msMapComputeGeotransformEx(mapObj *map, double resolutionX,
382
                               double resolutionY)
383
384
430
{
385
430
  double rot_angle;
386
430
  double geo_width, geo_height, center_x, center_y;
387
388
430
  map->saved_extent = map->extent;
389
390
430
  rot_angle = map->gt.rotation_angle * MS_PI / 180.0;
391
392
430
  geo_width = map->extent.maxx - map->extent.minx;
393
430
  geo_height = map->extent.maxy - map->extent.miny;
394
395
430
  center_x = map->extent.minx + geo_width * 0.5;
396
430
  center_y = map->extent.miny + geo_height * 0.5;
397
398
  /*
399
  ** Per bug 1916 we have to adjust for the fact that map extents
400
  ** are based on the center of the edge pixels, not the outer
401
  ** edges as is expected in a geotransform.
402
  */
403
430
  map->gt.geotransform[1] = cos(rot_angle) * resolutionX;
404
430
  map->gt.geotransform[2] = sin(rot_angle) * resolutionY;
405
430
  map->gt.geotransform[0] = center_x -
406
430
                            (map->width * 0.5) * map->gt.geotransform[1] -
407
430
                            (map->height * 0.5) * map->gt.geotransform[2];
408
409
430
  map->gt.geotransform[4] = sin(rot_angle) * resolutionX;
410
430
  map->gt.geotransform[5] = -cos(rot_angle) * resolutionY;
411
430
  map->gt.geotransform[3] = center_y -
412
430
                            (map->width * 0.5) * map->gt.geotransform[4] -
413
430
                            (map->height * 0.5) * map->gt.geotransform[5];
414
415
430
  if (InvGeoTransform(map->gt.geotransform, map->gt.invgeotransform))
416
430
    return MS_SUCCESS;
417
0
  else
418
0
    return MS_FAILURE;
419
430
}
420
421
int msMapComputeGeotransform(mapObj *map)
422
423
1.68k
{
424
  /* Do we have all required parameters? */
425
1.68k
  if (map->extent.minx == map->extent.maxx || map->width <= 1 ||
426
436
      map->height <= 1)
427
1.25k
    return MS_FAILURE;
428
429
430
  const double geo_width = map->extent.maxx - map->extent.minx;
430
430
  const double geo_height = map->extent.maxy - map->extent.miny;
431
430
  return msMapComputeGeotransformEx(map, geo_width / (map->width - 1),
432
430
                                    geo_height / (map->height - 1));
433
1.68k
}
434
435
/************************************************************************/
436
/*                         msMapPixelToGeoref()                         */
437
/************************************************************************/
438
439
void msMapPixelToGeoref(mapObj *map, double *x, double *y)
440
441
0
{
442
0
  (void)map;
443
0
  (void)x;
444
0
  (void)y;
445
0
  msSetError(MS_MISCERR, NULL, "msMapPixelToGeoref() not yet implemented");
446
0
}
447
448
/************************************************************************/
449
/*                         msMapGeorefToPixel()                         */
450
/************************************************************************/
451
452
void msMapGeorefToPixel(mapObj *map, double *x, double *y)
453
454
0
{
455
0
  (void)map;
456
0
  (void)x;
457
0
  (void)y;
458
0
  msSetError(MS_MISCERR, NULL, "msMapGeorefToPixel() not yet implemented");
459
0
}
460
461
/************************************************************************/
462
/*                        msMapSetFakedExtent()                         */
463
/************************************************************************/
464
465
int msMapSetFakedExtent(mapObj *map)
466
467
0
{
468
0
  int i;
469
  /* -------------------------------------------------------------------- */
470
  /*      Remember the original map extents so we can restore them        */
471
  /*      later.                                                          */
472
  /* -------------------------------------------------------------------- */
473
0
  map->saved_extent = map->extent;
474
475
  /* -------------------------------------------------------------------- */
476
  /*      Set extents such that the bottom left corner is 0,0 and the     */
477
  /*      top right is width,height.  Note this is upside down from       */
478
  /*      the normal sense of pixel/line coordinates, but we do this      */
479
  /*      so that the normal "extent" concept of coordinates              */
480
  /*      increasing to the right, and up is maintained (like in          */
481
  /*      georeferenced coordinate systems).                              */
482
  /* -------------------------------------------------------------------- */
483
0
  map->extent.minx = 0;
484
0
  map->extent.maxx = map->width;
485
0
  map->extent.miny = 0;
486
0
  map->extent.maxy = map->height;
487
0
  map->cellsize = 1.0;
488
489
  /* -------------------------------------------------------------------- */
490
  /*      When we copy the geotransform into the projection object we     */
491
  /*      have to flip it to account for the preceding upside-down       */
492
  /*      coordinate system.                                              */
493
  /* -------------------------------------------------------------------- */
494
0
  map->projection.gt = map->gt;
495
496
0
  map->projection.gt.geotransform[0] += map->height * map->gt.geotransform[2];
497
0
  map->projection.gt.geotransform[3] += map->height * map->gt.geotransform[5];
498
499
0
  map->projection.gt.geotransform[2] *= -1;
500
0
  map->projection.gt.geotransform[5] *= -1;
501
502
0
  for (i = 0; i < map->numlayers; i++)
503
0
    GET_LAYER(map, i)->project = MS_TRUE;
504
505
0
  return InvGeoTransform(map->projection.gt.geotransform,
506
0
                         map->projection.gt.invgeotransform);
507
0
}
508
509
/************************************************************************/
510
/*                      msMapRestoreRealExtent()                        */
511
/************************************************************************/
512
513
int msMapRestoreRealExtent(mapObj *map)
514
515
0
{
516
0
  map->projection.gt.need_geotransform = MS_FALSE;
517
0
  map->extent = map->saved_extent;
518
0
  map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height);
519
520
0
  return MS_SUCCESS;
521
0
}
522
523
/************************************************************************/
524
/*                      msInsertLayer()                                 */
525
/************************************************************************/
526
/* Returns the index at which the layer was inserted
527
 */
528
529
0
int msInsertLayer(mapObj *map, layerObj *layer, int nIndex) {
530
0
  if (!layer) {
531
0
    msSetError(MS_CHILDERR, "Can't insert a NULL Layer", "msInsertLayer()");
532
0
    return -1;
533
0
  }
534
535
  /* Ensure there is room for a new layer */
536
0
  if (map->numlayers == map->maxlayers) {
537
0
    if (msGrowMapLayers(map) == NULL)
538
0
      return -1;
539
0
  }
540
541
  /* msGrowMapLayers allocates the new layer which we don't need to do since we
542
     have 1 that we are inserting not sure if it is possible for this to be non
543
     null otherwise, but better to check since this function replaces the value
544
   */
545
0
  if (map->layers[map->numlayers] != NULL)
546
0
    free(map->layers[map->numlayers]);
547
548
  /* Catch attempt to insert past end of layers array */
549
0
  if (nIndex >= map->numlayers) {
550
0
    msSetError(MS_CHILDERR, "Cannot insert layer beyond index %d",
551
0
               "msInsertLayer()", map->numlayers - 1);
552
0
    return -1;
553
0
  } else if (nIndex < 0) { /* Insert at the end by default */
554
0
    map->layerorder[map->numlayers] = map->numlayers;
555
0
    GET_LAYER(map, map->numlayers) = layer;
556
0
    GET_LAYER(map, map->numlayers)->index = map->numlayers;
557
0
    GET_LAYER(map, map->numlayers)->map = map;
558
0
    MS_REFCNT_INCR(layer);
559
0
    map->numlayers++;
560
0
    return map->numlayers - 1;
561
0
  } else {
562
    /* Move existing layers at the specified nIndex or greater */
563
    /* to an index one higher */
564
0
    int i;
565
0
    for (i = map->numlayers; i > nIndex; i--) {
566
0
      GET_LAYER(map, i) = GET_LAYER(map, i - 1);
567
0
      GET_LAYER(map, i)->index = i;
568
0
    }
569
570
    /* assign new layer to specified index */
571
0
    GET_LAYER(map, nIndex) = layer;
572
0
    GET_LAYER(map, nIndex)->index = nIndex;
573
0
    GET_LAYER(map, nIndex)->map = map;
574
575
    /* adjust layers drawing order */
576
0
    for (i = map->numlayers; i > nIndex; i--) {
577
0
      map->layerorder[i] = map->layerorder[i - 1];
578
0
      if (map->layerorder[i] >= nIndex)
579
0
        map->layerorder[i]++;
580
0
    }
581
0
    for (i = 0; i < nIndex; i++) {
582
0
      if (map->layerorder[i] >= nIndex)
583
0
        map->layerorder[i]++;
584
0
    }
585
0
    map->layerorder[nIndex] = nIndex;
586
587
    /* increment number of layers and return */
588
0
    MS_REFCNT_INCR(layer);
589
0
    map->numlayers++;
590
0
    return nIndex;
591
0
  }
592
0
}
593
594
/************************************************************************/
595
/*                           msRemoveLayer()                            */
596
/************************************************************************/
597
0
layerObj *msRemoveLayer(mapObj *map, int nIndex) {
598
0
  int i;
599
0
  int order_index;
600
0
  layerObj *layer;
601
602
0
  if (nIndex < 0 || nIndex >= map->numlayers) {
603
0
    msSetError(MS_CHILDERR, "Cannot remove Layer, invalid index %d",
604
0
               "msRemoveLayer()", nIndex);
605
0
    return NULL;
606
0
  } else {
607
0
    layer = GET_LAYER(map, nIndex);
608
    /* msCopyLayer(layer, (GET_LAYER(map, nIndex))); */
609
610
    /* Iteratively copy the higher index layers down one index */
611
0
    for (i = nIndex; i < map->numlayers - 1; i++) {
612
      /* freeLayer((GET_LAYER(map, i))); */
613
      /* initLayer((GET_LAYER(map, i)), map); */
614
      /* msCopyLayer(GET_LAYER(map, i), GET_LAYER(map, i+1)); */
615
0
      GET_LAYER(map, i) = GET_LAYER(map, i + 1);
616
0
      GET_LAYER(map, i)->index = i;
617
0
    }
618
    /* Free the extra layer at the end */
619
    /* freeLayer((GET_LAYER(map, map->numlayers-1))); */
620
0
    GET_LAYER(map, map->numlayers - 1) = NULL;
621
622
    /* Adjust drawing order */
623
0
    order_index = 0;
624
0
    for (i = 0; i < map->numlayers; i++) {
625
0
      if (map->layerorder[i] > nIndex)
626
0
        map->layerorder[i]--;
627
0
      if (map->layerorder[i] == nIndex) {
628
0
        order_index = i;
629
0
        break;
630
0
      }
631
0
    }
632
0
    for (i = order_index; i < map->numlayers - 1; i++) {
633
0
      map->layerorder[i] = map->layerorder[i + 1];
634
0
      if (map->layerorder[i] > nIndex)
635
0
        map->layerorder[i]--;
636
0
    }
637
638
    /* decrement number of layers and return copy of removed layer */
639
0
    map->numlayers--;
640
0
    layer->map = NULL;
641
0
    MS_REFCNT_DECR(layer);
642
0
    return layer;
643
0
  }
644
0
}
645
646
/*
647
** Move the layer's order for drawing purpose. Moving it up here
648
** will have the effect of drawing the layer earlier.
649
*/
650
0
int msMoveLayerUp(mapObj *map, int nLayerIndex) {
651
0
  int iCurrentIndex = -1;
652
0
  if (map && nLayerIndex < map->numlayers && nLayerIndex >= 0) {
653
0
    for (int i = 0; i < map->numlayers; i++) {
654
0
      if (map->layerorder[i] == nLayerIndex) {
655
0
        iCurrentIndex = i;
656
0
        break;
657
0
      }
658
0
    }
659
0
    if (iCurrentIndex >= 0) {
660
      /* we do not need to promote if it is the first one. */
661
0
      if (iCurrentIndex == 0)
662
0
        return MS_FAILURE;
663
664
0
      map->layerorder[iCurrentIndex] = map->layerorder[iCurrentIndex - 1];
665
0
      map->layerorder[iCurrentIndex - 1] = nLayerIndex;
666
667
0
      return MS_SUCCESS;
668
0
    }
669
0
  }
670
0
  msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveLayerUp()", nLayerIndex);
671
0
  return MS_FAILURE;
672
0
}
673
674
/*
675
** Move the layer's order for drawing purpose. Moving it down here
676
** will have the effect of drawing the layer later.
677
*/
678
0
int msMoveLayerDown(mapObj *map, int nLayerIndex) {
679
0
  int iCurrentIndex = -1;
680
0
  if (map && nLayerIndex < map->numlayers && nLayerIndex >= 0) {
681
0
    for (int i = 0; i < map->numlayers; i++) {
682
0
      if (map->layerorder[i] == nLayerIndex) {
683
0
        iCurrentIndex = i;
684
0
        break;
685
0
      }
686
0
    }
687
0
    if (iCurrentIndex >= 0) {
688
      /* we do not need to demote if it is the last one. */
689
0
      if (iCurrentIndex == map->numlayers - 1)
690
0
        return MS_FAILURE;
691
692
0
      map->layerorder[iCurrentIndex] = map->layerorder[iCurrentIndex + 1];
693
0
      map->layerorder[iCurrentIndex + 1] = nLayerIndex;
694
695
0
      return MS_SUCCESS;
696
0
    }
697
0
  }
698
0
  msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveLayerDown()",
699
0
             nLayerIndex);
700
0
  return MS_FAILURE;
701
0
}
702
703
/*
704
** Set the array used for the drawing order. The array passed must contain
705
** all the layer's index ordered by the drawing priority.
706
** Ex : for 3 layers in the map file, if
707
**                          panIndexes[0] = 2
708
**                          panIndexes[1] = 0
709
**                          panIndexes[2] = 1
710
**                          will set the darwing order to layer 2, layer 0,
711
**                          and then layer 1.
712
**
713
** Note : It is assumed that the index panIndexes has the same number of
714
**        of elements as the number of layers in the map.
715
** Return TRUE on success else FALSE.
716
*/
717
0
int msSetLayersdrawingOrder(mapObj *self, int *panIndexes) {
718
0
  if (self && panIndexes) {
719
0
    const int nElements = self->numlayers;
720
0
    for (int i = 0; i < nElements; i++) {
721
0
      int bFound = 0;
722
0
      for (int j = 0; j < nElements; j++) {
723
0
        if (panIndexes[j] == i) {
724
0
          bFound = 1;
725
0
          break;
726
0
        }
727
0
      }
728
0
      if (!bFound)
729
0
        return 0;
730
0
    }
731
    /* -------------------------------------------------------------------- */
732
    /*    At this point the array is valid so update the layers order array.*/
733
    /* -------------------------------------------------------------------- */
734
0
    for (int i = 0; i < nElements; i++) {
735
0
      self->layerorder[i] = panIndexes[i];
736
0
    }
737
0
    return 1;
738
0
  }
739
0
  return 0;
740
0
}
741
742
/* =========================================================================
743
   msMapLoadOWSParameters
744
745
   Function to support mapscript mapObj::loadOWSParameters
746
   ========================================================================= */
747
748
int msMapLoadOWSParameters(mapObj *map, cgiRequestObj *request,
749
0
                           const char *wmtver) {
750
0
#ifdef USE_WMS_SVR
751
0
  int version;
752
0
  char *wms_exception_format = NULL;
753
0
  const char *wms_request = NULL;
754
0
  int result, i = 0;
755
0
  owsRequestObj ows_request;
756
757
0
  msOWSInitRequestObj(&ows_request);
758
759
0
  version = msOWSParseVersionString(wmtver);
760
0
  for (i = 0; i < request->NumParams; i++) {
761
0
    if (strcasecmp(request->ParamNames[i], "EXCEPTIONS") == 0)
762
0
      wms_exception_format = request->ParamValues[i];
763
0
    else if (strcasecmp(request->ParamNames[i], "REQUEST") == 0)
764
0
      wms_request = request->ParamValues[i];
765
0
  }
766
767
0
  msOWSRequestLayersEnabled(map, "M", wms_request, &ows_request);
768
769
0
  result = msWMSLoadGetMapParams(
770
0
      map, version, request->ParamNames, request->ParamValues,
771
0
      request->NumParams, wms_exception_format, wms_request, &ows_request);
772
773
0
  msOWSClearRequestObj(&ows_request);
774
775
0
  return result;
776
777
#else
778
  msSetError(MS_WMSERR, "WMS server support is not available.",
779
             "msMapLoadOWSParameters()");
780
  return MS_FAILURE;
781
#endif
782
0
}