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