1 /******************************************************************************
2  * $id: mapfile.c 7854 2008-08-14 19:22:48Z dmorissette $
3  *
4  * Project:  MapServer
5  * Purpose:  High level Map file parsing code.
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 #ifndef _GNU_SOURCE
31 #define _GNU_SOURCE
32 #endif
33 
34 #include <stdarg.h>
35 #include <assert.h>
36 #include <ctype.h>
37 #include <float.h>
38 
39 #include "mapserver.h"
40 #include "mapfile.h"
41 #include "mapthread.h"
42 #include "maptime.h"
43 
44 extern int msyylex(void);
45 extern void msyyrestart(FILE *);
46 extern int msyylex_destroy(void);
47 
48 extern double msyynumber;
49 extern int msyylineno;
50 extern FILE *msyyin;
51 
52 extern int msyysource;
53 extern int msyystate;
54 extern char *msyystring;
55 extern char *msyybasepath;
56 extern int msyyreturncomments;
57 extern char *msyystring_buffer;
58 extern int msyystring_icase;
59 
60 extern int loadSymbol(symbolObj *s, char *symbolpath); /* in mapsymbol.c */
61 extern void writeSymbol(symbolObj *s, FILE *stream); /* in mapsymbol.c */
62 static int loadGrid( layerObj *pLayer );
63 static int loadStyle(styleObj *style);
64 static void writeStyle(FILE* stream, int indent, styleObj *style);
65 static int resolveSymbolNames(mapObj *map);
66 static int loadExpression(expressionObj *exp);
67 static void writeExpression(FILE *stream, int indent, const char *name, expressionObj *exp);
68 
69 
70 /*
71 ** Symbol to string static arrays needed for writing map files.
72 ** Must be kept in sync with enumerations and defines found in mapserver.h.
73 */
74 /* static char *msUnits[9]={"INCHES", "FEET", "MILES", "METERS", "KILOMETERS", "DD", "PIXELS", "PERCENTAGES", "NAUTICALMILES"}; */
75 /* static char *msLayerTypes[10]={"POINT", "LINE", "POLYGON", "RASTER", "ANNOTATION", "QUERY", "CIRCLE", "TILEINDEX","CHART"}; */
76 char *msPositionsText[MS_POSITIONS_LENGTH] = {"UL", "LR", "UR", "LL", "CR", "CL", "UC", "LC", "CC", "AUTO", "XY", "FOLLOW"}; /* msLabelPositions[] also used in mapsymbols.c (not static) */
77 /* static char *msBitmapFontSizes[5]={"TINY", "SMALL", "MEDIUM", "LARGE", "GIANT"}; */
78 /* static char *msQueryMapStyles[4]={"NORMAL", "HILITE", "SELECTED", "INVERTED"}; */
79 /* static char *msStatus[4]={"OFF", "ON", "DEFAULT", "EMBED"}; */
80 /* static char *msOnOff[2]={"OFF", "ON"}; */
81 /* static char *msTrueFalse[2]={"FALSE", "TRUE"}; */
82 /* static char *msYesNo[2]={"NO", "YES"}; */
83 /* static char *msJoinType[2]={"ONE-TO-ONE", "ONE-TO-MANY"}; */
84 /* static char *msAlignValue[3]={"LEFT","CENTER","RIGHT"}; */
85 
86 /*
87 ** Validates a string (value) against a series of patterns. We support up to four to allow cascading from classObj to
88 ** layerObj to webObj plus a legacy pattern like TEMPLATEPATTERN.
89 */
msValidateParameter(const char * value,const char * pattern1,const char * pattern2,const char * pattern3,const char * pattern4)90 int msValidateParameter(const char *value, const char *pattern1, const char *pattern2, const char *pattern3, const char *pattern4)
91 {
92   if(msEvalRegex(pattern1, value) == MS_TRUE) return MS_SUCCESS;
93   if(msEvalRegex(pattern2, value) == MS_TRUE) return MS_SUCCESS;
94   if(msEvalRegex(pattern3, value) == MS_TRUE) return MS_SUCCESS;
95   if(msEvalRegex(pattern4, value) == MS_TRUE) return MS_SUCCESS;
96 
97   return(MS_FAILURE);
98 }
99 
msIsValidRegex(const char * e)100 int msIsValidRegex(const char* e) {
101   ms_regex_t re;
102   if(ms_regcomp(&re, e, MS_REG_EXTENDED|MS_REG_NOSUB) != 0) {
103     msSetError(MS_REGEXERR, "Failed to compile expression (%s).", "msEvalRegex()", e);
104     return(MS_FALSE);
105   }
106   ms_regfree(&re);
107   return MS_TRUE;
108 }
109 
msEvalRegex(const char * e,const char * s)110 int msEvalRegex(const char *e, const char *s)
111 {
112   ms_regex_t re;
113 
114   if(!e || !s) return(MS_FALSE);
115 
116   if(ms_regcomp(&re, e, MS_REG_EXTENDED|MS_REG_NOSUB) != 0) {
117     msSetError(MS_REGEXERR, "Failed to compile expression (%s).", "msEvalRegex()", e);
118     return(MS_FALSE);
119   }
120 
121   if(ms_regexec(&re, s, 0, NULL, 0) != 0) { /* no match */
122     ms_regfree(&re);
123     return(MS_FALSE);
124   }
125   ms_regfree(&re);
126 
127   return(MS_TRUE);
128 }
129 
msCaseEvalRegex(const char * e,const char * s)130 int msCaseEvalRegex(const char *e, const char *s)
131 {
132   ms_regex_t re;
133 
134   if(!e || !s) return(MS_FALSE);
135 
136   if(ms_regcomp(&re, e, MS_REG_EXTENDED|MS_REG_ICASE|MS_REG_NOSUB) != 0) {
137     msSetError(MS_REGEXERR, "Failed to compile expression (%s).", "msEvalRegex()", e);
138     return(MS_FALSE);
139   }
140 
141   if(ms_regexec(&re, s, 0, NULL, 0) != 0) { /* no match */
142     ms_regfree(&re);
143     return(MS_FALSE);
144   }
145   ms_regfree(&re);
146 
147   return(MS_TRUE);
148 }
149 
150 #ifdef USE_MSFREE
msFree(void * p)151 void msFree(void *p)
152 {
153   if(p) free(p);
154 }
155 #endif
156 
157 /*
158 ** Free memory allocated for a character array
159 */
msFreeCharArray(char ** array,int num_items)160 void msFreeCharArray(char **array, int num_items)
161 {
162   int i;
163   if(!array) return;
164   for(i=0; i<num_items; i++)
165     msFree(array[i]);
166   msFree(array);
167 }
168 
169 /*
170 ** Checks symbol from lexer against variable length list of
171 ** legal symbols.
172 */
getSymbol(int n,...)173 int getSymbol(int n, ...)
174 {
175   int symbol;
176   va_list argp;
177   int i=0;
178 
179   symbol = msyylex();
180 
181   va_start(argp, n);
182   while(i<n) { /* check each symbol in the list */
183     if(symbol == va_arg(argp, int)) {
184       va_end(argp);
185       return(symbol);
186     }
187     i++;
188   }
189 
190   va_end(argp);
191 
192   msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getSymbol()", msyystring_buffer, msyylineno);
193   return(-1);
194 }
195 
196 /*
197 ** Same as getSymbol, except no error message is set on failure
198 */
getSymbol2(int n,...)199 int getSymbol2(int n, ...)
200 {
201   int symbol;
202   va_list argp;
203   int i=0;
204 
205   symbol = msyylex();
206 
207   va_start(argp, n);
208   while(i<n) { /* check each symbol in the list */
209     if(symbol == va_arg(argp, int)) {
210       va_end(argp);
211       return(symbol);
212     }
213     i++;
214   }
215 
216   va_end(argp);
217   return(-1);
218 }
219 
220 /*
221 ** Get a string or symbol as a string.   Operates like getString(), but also
222 ** supports symbols.
223 */
getToken(void)224 static char *getToken(void)
225 {
226   msyylex();
227   return msStrdup(msyystring_buffer);
228 }
229 
230 /*
231 ** Load a string from the map file. A "string" is defined in lexer.l.
232 */
getString(char ** s)233 int getString(char **s)
234 {
235   /* if (*s)
236     msSetError(MS_SYMERR, "Duplicate item (%s):(line %d)", "getString()", msyystring_buffer, msyylineno);
237     return(MS_FAILURE);
238   } else */
239   if(msyylex() == MS_STRING) {
240     if(*s) free(*s); /* avoid leak */
241     *s = msStrdup(msyystring_buffer);
242     return(MS_SUCCESS);
243   }
244 
245   msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getString()", msyystring_buffer, msyylineno);
246   return(MS_FAILURE);
247 }
248 
249 /*
250 ** Load a floating point number from the map file. (see lexer.l)
251 */
getDouble(double * d)252 int getDouble(double *d)
253 {
254   if(msyylex() == MS_NUMBER) {
255     *d = msyynumber;
256     return(0); /* success */
257   }
258 
259   msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getDouble()", msyystring_buffer, msyylineno);
260   return(-1);
261 }
262 
263 /*
264 ** Load a integer from the map file. (see lexer.l)
265 */
getInteger(int * i)266 int getInteger(int *i)
267 {
268   if(msyylex() == MS_NUMBER) {
269     *i = (int)msyynumber;
270     return(0); /* success */
271   }
272 
273   msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getInteger()", msyystring_buffer, msyylineno);
274   return(-1);
275 }
276 
getCharacter(char * c)277 int getCharacter(char *c)
278 {
279   if(msyylex() == MS_STRING) {
280     *c = msyystring_buffer[0];
281     return(0);
282   }
283 
284   msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getCharacter()", msyystring_buffer, msyylineno);
285   return(-1);
286 }
287 
288 /*
289 ** Try to load as an integer, then try as a named symbol.
290 ** Part of work on bug 490.
291 */
getIntegerOrSymbol(int * i,int n,...)292 int getIntegerOrSymbol(int *i, int n, ...)
293 {
294   int symbol;
295   va_list argp;
296   int j=0;
297 
298   symbol = msyylex();
299 
300   if (symbol == MS_NUMBER) {
301     *i = (int)msyynumber;
302     return MS_SUCCESS; /* success */
303   }
304 
305   va_start(argp, n);
306   while (j<n) { /* check each symbol in the list */
307     if(symbol == va_arg(argp, int)) {
308       va_end(argp);
309       *i = symbol;
310       return MS_SUCCESS;
311     }
312     j++;
313   }
314   va_end(argp);
315 
316   msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)",
317              "getIntegerOrSymbol()", msyystring_buffer, msyylineno);
318   return(-1);
319 }
320 
321 
322 /*
323 ** msBuildPluginLibraryPath
324 **
325 ** This function builds a path to be used dynamically to load plugin library.
326 */
msBuildPluginLibraryPath(char ** dest,const char * lib_str,mapObj * map)327 int msBuildPluginLibraryPath(char **dest, const char *lib_str, mapObj *map)
328 {
329   char szLibPath[MS_MAXPATHLEN] = { '\0' };
330   char szLibPathExt[MS_MAXPATHLEN] = { '\0' };
331   const char *plugin_dir = NULL;
332 
333   if (map)
334     plugin_dir = msLookupHashTable(&(map->configoptions), "MS_PLUGIN_DIR");
335 
336   /* do nothing on windows, filename without .dll will be loaded by default*/
337 #if !defined(_WIN32)
338   if (lib_str) {
339     size_t len = strlen(lib_str);
340     if (3 < len && strcmp(lib_str + len-3, ".so")) {
341       strlcpy(szLibPathExt, lib_str, MS_MAXPATHLEN);
342       strlcat(szLibPathExt, ".so", MS_MAXPATHLEN);
343       lib_str = szLibPathExt;
344     }
345   }
346 #endif /* !defined(_WIN32) */
347   if (NULL == msBuildPath(szLibPath, plugin_dir, lib_str)) {
348     return MS_FAILURE;
349   }
350   *dest = msStrdup(szLibPath);
351 
352   return MS_SUCCESS;
353 }
354 
355 /*
356 ** Returns the index of specified symbol or -1 if not found.
357 **
358 ** If try_addimage_if_notfound==MS_TRUE then msAddImageSymbol() will be called
359 ** to try to allocate the symbol as an image symbol.
360 */
msGetSymbolIndex(symbolSetObj * symbols,char * name,int try_addimage_if_notfound)361 int msGetSymbolIndex(symbolSetObj *symbols, char *name, int try_addimage_if_notfound)
362 {
363   int i;
364 
365   if(!symbols || !name) return(-1);
366 
367   /* symbol 0 has no name */
368   for(i=1; i<symbols->numsymbols; i++) {
369     if(symbols->symbol[i]->name)
370       if(strcasecmp(symbols->symbol[i]->name, name) == 0) return(i);
371   }
372 
373   if (try_addimage_if_notfound)
374     return(msAddImageSymbol(symbols, name)); /* make sure it's not a filename */
375 
376   return(-1);
377 }
378 
379 /*
380 ** Return the index number for a given layer based on its name.
381 */
msGetLayerIndex(mapObj * map,const char * name)382 int msGetLayerIndex(mapObj *map, const char *name)
383 {
384   int i;
385 
386   if(!name) return(-1);
387 
388   for(i=0; i<map->numlayers; i++) {
389     if(!GET_LAYER(map, i)->name) /* skip it */
390       continue;
391     if(strcmp(name, GET_LAYER(map, i)->name) == 0)
392       return(i);
393   }
394   return(-1);
395 }
396 
397 static
msGetClassIndex(layerObj * layer,const char * name)398 int msGetClassIndex(layerObj *layer, const char *name)
399 {
400   int i;
401 
402   if(!name) return(-1);
403 
404   for(i=0; i<layer->numclasses; i++) {
405     if(!layer->class[i]->name) /* skip it */
406       continue;
407     if(strcmp(name, layer->class[i]->name) == 0)
408       return(i);
409   }
410   return(-1);
411 }
412 
loadColor(colorObj * color,attributeBindingObj * binding)413 int loadColor(colorObj *color, attributeBindingObj *binding)
414 {
415   int symbol;
416   char hex[2];
417 
418   if(binding) {
419     if((symbol = getSymbol(3, MS_NUMBER, MS_BINDING, MS_STRING)) == -1) return MS_FAILURE;
420   } else {
421     if((symbol = getSymbol(2, MS_NUMBER, MS_STRING)) == -1) return MS_FAILURE;
422   }
423 
424   color->alpha=255;
425   if(symbol == MS_NUMBER) {
426     color->red = (int) msyynumber;
427     if(getInteger(&(color->green)) == -1) return MS_FAILURE;
428     if(getInteger(&(color->blue)) == -1) return MS_FAILURE;
429   } else if(symbol == MS_STRING) {
430     int len = strlen(msyystring_buffer);
431     if(msyystring_buffer[0] == '#' && (len == 7 || len == 9)) { /* got a hex color w/optional alpha */
432       hex[0] = msyystring_buffer[1];
433       hex[1] = msyystring_buffer[2];
434       color->red = msHexToInt(hex);
435       hex[0] = msyystring_buffer[3];
436       hex[1] = msyystring_buffer[4];
437       color->green = msHexToInt(hex);
438       hex[0] = msyystring_buffer[5];
439       hex[1] = msyystring_buffer[6];
440       color->blue = msHexToInt(hex);
441       if(len == 9) {
442         hex[0] = msyystring_buffer[7];
443         hex[1] = msyystring_buffer[8];
444         color->alpha = msHexToInt(hex);
445       }
446     } else {
447       /* TODO: consider named colors here */
448       msSetError(MS_SYMERR, "Invalid hex color (%s):(line %d)", "loadColor()", msyystring_buffer, msyylineno);
449       return MS_FAILURE;
450     }
451   } else {
452     binding->item = msStrdup(msyystring_buffer);
453     binding->index = -1;
454   }
455 
456   return MS_SUCCESS;
457 }
458 
459 #if ALPHACOLOR_ENABLED
loadColorWithAlpha(colorObj * color)460 int loadColorWithAlpha(colorObj *color)
461 {
462   char hex[2];
463 
464   if(getInteger(&(color->red)) == -1) {
465     if(msyystring_buffer[0] == '#' && strlen(msyystring_buffer) == 7) { /* got a hex color */
466       hex[0] = msyystring_buffer[1];
467       hex[1] = msyystring_buffer[2];
468       color->red = msHexToInt(hex);
469       hex[0] = msyystring_buffer[3];
470       hex[1] = msyystring_buffer[4];
471       color->green = msHexToInt(hex);
472       hex[0] = msyystring_buffer[5];
473       hex[1] = msyystring_buffer[6];
474       color->blue = msHexToInt(hex);
475       color->alpha = 0;
476 
477       return(MS_SUCCESS);
478     } else if(msyystring_buffer[0] == '#' && strlen(msyystring_buffer) == 9) { /* got a hex color with alpha */
479       hex[0] = msyystring_buffer[1];
480       hex[1] = msyystring_buffer[2];
481       color->red = msHexToInt(hex);
482       hex[0] = msyystring_buffer[3];
483       hex[1] = msyystring_buffer[4];
484       color->green = msHexToInt(hex);
485       hex[0] = msyystring_buffer[5];
486       hex[1] = msyystring_buffer[6];
487       color->blue = msHexToInt(hex);
488       hex[0] = msyystring_buffer[7];
489       hex[1] = msyystring_buffer[8];
490       color->alpha = msHexToInt(hex);
491       return(MS_SUCCESS);
492     }
493     return(MS_FAILURE);
494   }
495   if(getInteger(&(color->green)) == -1) return(MS_FAILURE);
496   if(getInteger(&(color->blue)) == -1) return(MS_FAILURE);
497   if(getInteger(&(color->alpha)) == -1) return(MS_FAILURE);
498 
499   return(MS_SUCCESS);
500 }
501 #endif
502 
503 /*
504 ** Helper functions for writing mapfiles.
505 */
writeLineFeed(FILE * stream)506 static void writeLineFeed(FILE *stream)
507 {
508   msIO_fprintf(stream, "\n");
509 }
510 
writeIndent(FILE * stream,int indent)511 static void writeIndent(FILE *stream, int indent)
512 {
513   const char *str="  "; /* change this string to define the indent */
514   int i;
515   for(i=0; i<indent; i++) msIO_fprintf(stream, "%s", str);
516 }
517 
writeBlockBegin(FILE * stream,int indent,const char * name)518 static void writeBlockBegin(FILE *stream, int indent, const char *name)
519 {
520   writeIndent(stream, indent);
521   msIO_fprintf(stream, "%s\n", name);
522 }
523 
writeBlockEnd(FILE * stream,int indent,const char * name)524 static void writeBlockEnd(FILE *stream, int indent, const char *name)
525 {
526   writeIndent(stream, indent);
527   msIO_fprintf(stream, "END # %s\n", name);
528 }
529 
writeKeyword(FILE * stream,int indent,const char * name,int value,int size,...)530 static void writeKeyword(FILE *stream, int indent, const char *name, int value, int size, ...)
531 {
532   va_list argp;
533   int i, j=0;
534   const char *s;
535 
536   va_start(argp, size);
537   while (j<size) { /* check each value/keyword mapping in the list, values with no match are ignored */
538     i = va_arg(argp, int);
539     s = va_arg(argp, const char *);
540     if(value == i) {
541       writeIndent(stream, ++indent);
542       msIO_fprintf(stream, "%s %s\n", name, s);
543       va_end(argp);
544       return;
545     }
546     j++;
547   }
548   va_end(argp);
549 }
550 
writeDimension(FILE * stream,int indent,const char * name,double x,double y,char * bind_x,char * bind_y)551 static void writeDimension(FILE *stream, int indent, const char *name, double x, double y, char *bind_x, char *bind_y)
552 {
553   writeIndent(stream, ++indent);
554   if(bind_x) msIO_fprintf(stream, "%s [%s] ", name, bind_x);
555   else msIO_fprintf(stream, "%s %.15g ", name, x);
556   if(bind_y) msIO_fprintf(stream, "[%s]\n", bind_y);
557   else msIO_fprintf(stream, "%.15g\n", y);
558 }
559 
writeDoubleRange(FILE * stream,int indent,const char * name,double x,double y)560 static void writeDoubleRange(FILE *stream, int indent, const char *name, double x, double y)
561 {
562   writeIndent(stream, ++indent);
563   msIO_fprintf(stream, "%s %f %f\n", name, x, y);
564 }
565 
writeExtent(FILE * stream,int indent,const char * name,rectObj extent)566 static void writeExtent(FILE *stream, int indent, const char *name, rectObj extent)
567 {
568   if(!MS_VALID_EXTENT(extent)) return;
569   writeIndent(stream, ++indent);
570   msIO_fprintf(stream, "%s %.15g %.15g %.15g %.15g\n", name, extent.minx, extent.miny, extent.maxx, extent.maxy);
571 }
572 
writeNumber(FILE * stream,int indent,const char * name,double defaultNumber,double number)573 static void writeNumber(FILE *stream, int indent, const char *name, double defaultNumber, double number)
574 {
575   if(number == defaultNumber) return; /* don't output default */
576   writeIndent(stream, ++indent);
577   msIO_fprintf(stream, "%s %.15g\n", name, number);
578 }
579 
writeCharacter(FILE * stream,int indent,const char * name,const char defaultCharacter,char character)580 static void writeCharacter(FILE *stream, int indent, const char *name, const char defaultCharacter, char character)
581 {
582   if(defaultCharacter == character) return;
583   writeIndent(stream, ++indent);
584   msIO_fprintf(stream, "%s '%c'\n", name, character);
585 }
586 
writeStringElement(FILE * stream,char * string)587 static void writeStringElement(FILE *stream, char *string)
588 {
589     char *string_escaped;
590 
591     if(strchr(string,'\\')) {
592       string_escaped = msStrdup(string);
593       string_escaped = msReplaceSubstring(string_escaped,"\\","\\\\");
594     } else {
595       string_escaped = string;
596     }
597     if ( (strchr(string_escaped, '\'') == NULL) && (strchr(string_escaped, '\"') == NULL))
598       msIO_fprintf(stream, "\"%s\"", string_escaped);
599     else if ( (strchr(string_escaped, '\"') != NULL) && (strchr(string_escaped, '\'') == NULL))
600       msIO_fprintf(stream, "'%s'", string_escaped);
601     else if ( (strchr(string_escaped, '\'') != NULL) && (strchr(string_escaped, '\"') == NULL))
602       msIO_fprintf(stream, "\"%s\"", string_escaped);
603     else {
604       char *string_tmp = msStringEscape(string_escaped);
605       msIO_fprintf(stream, "\"%s\"", string_tmp);
606       if(string_escaped!=string_tmp) free(string_tmp);
607     }
608     if(string_escaped!=string) free(string_escaped);
609 }
610 
writeString(FILE * stream,int indent,const char * name,const char * defaultString,char * string)611 static void writeString(FILE *stream, int indent, const char *name, const char *defaultString, char *string)
612 {
613   if(!string) return;
614   if(defaultString && strcmp(string, defaultString) == 0) return;
615   writeIndent(stream, ++indent);
616   if(name) msIO_fprintf(stream, "%s ", name);
617   writeStringElement(stream, string);
618   writeLineFeed(stream);
619 }
620 
writeNumberOrString(FILE * stream,int indent,const char * name,double defaultNumber,double number,char * string)621 static void writeNumberOrString(FILE *stream, int indent, const char *name, double defaultNumber, double number, char *string)
622 {
623   if(string)
624     writeString(stream, indent, name, NULL, string);
625   else
626     writeNumber(stream, indent, name, defaultNumber, number);
627 }
628 
writeNumberOrKeyword(FILE * stream,int indent,const char * name,double defaultNumber,double number,int value,int size,...)629 static void writeNumberOrKeyword(FILE *stream, int indent, const char *name, double defaultNumber, double number, int value, int size, ...)
630 {
631   va_list argp;
632   int i, j=0;
633   const char *s;
634 
635   va_start(argp, size);
636   while (j<size) { /* check each value/keyword mapping in the list */
637     i = va_arg(argp, int);
638     s = va_arg(argp, const char *);
639     if(value == i) {
640       writeIndent(stream, ++indent);
641       msIO_fprintf(stream, "%s %s\n", name, s);
642       va_end(argp);
643       return;
644     }
645     j++;
646   }
647   va_end(argp);
648 
649   writeNumber(stream, indent, name, defaultNumber, number);
650 }
651 
writeNameValuePair(FILE * stream,int indent,const char * name,const char * value)652 static void writeNameValuePair(FILE *stream, int indent, const char *name, const char *value)
653 {
654   if(!name || !value) return;
655   writeIndent(stream, ++indent);
656 
657   writeStringElement(stream, (char*)name);
658   msIO_fprintf(stream,"\t");
659   writeStringElement(stream, (char*)value);
660   writeLineFeed(stream);
661 }
662 
writeAttributeBinding(FILE * stream,int indent,const char * name,attributeBindingObj * binding)663 static void writeAttributeBinding(FILE *stream, int indent, const char *name, attributeBindingObj *binding)
664 {
665   if(!binding || !binding->item) return;
666   writeIndent(stream, ++indent);
667   msIO_fprintf(stream, "%s [%s]\n", name, binding->item);
668 }
669 
writeColor(FILE * stream,int indent,const char * name,colorObj * defaultColor,colorObj * color)670 static void writeColor(FILE *stream, int indent, const char *name, colorObj *defaultColor, colorObj *color)
671 {
672   if (!defaultColor && !MS_VALID_COLOR(*color)) return;
673   else if(defaultColor && MS_COMPARE_COLOR(*defaultColor, *color)) return; /* if defaultColor has the same value than the color, return.*/
674 
675   writeIndent(stream, ++indent);
676 #if ALPHACOLOR_ENABLED
677   msIO_fprintf(stream, "%s %d %d %d\n", name, color->red, color->green, color->blue, color->alpha);
678 #else
679   if(color->alpha != 255) {
680     char buffer[9];
681     sprintf(buffer, "%02x", color->red);
682     sprintf(buffer+2, "%02x", color->green);
683     sprintf(buffer+4, "%02x", color->blue);
684     sprintf(buffer+6, "%02x", color->alpha);
685     *(buffer+8) = 0;
686     msIO_fprintf(stream, "%s \"#%s\"\n", name, buffer);
687   } else {
688     msIO_fprintf(stream, "%s %d %d %d\n", name, color->red, color->green, color->blue);
689   }
690 #endif
691 }
692 
693 /* todo: deal with alpha's... */
writeColorRange(FILE * stream,int indent,const char * name,colorObj * mincolor,colorObj * maxcolor)694 static void writeColorRange(FILE *stream, int indent, const char *name, colorObj *mincolor, colorObj *maxcolor)
695 {
696   if(!MS_VALID_COLOR(*mincolor) || !MS_VALID_COLOR(*maxcolor)) return;
697   writeIndent(stream, ++indent);
698   msIO_fprintf(stream, "%s %d %d %d  %d %d %d\n", name, mincolor->red, mincolor->green, mincolor->blue, maxcolor->red, maxcolor->green, maxcolor->blue);
699 }
700 
701 /*
702 ** Initialize, load and free a single join
703 */
initJoin(joinObj * join)704 void initJoin(joinObj *join)
705 {
706   join->numitems = 0;
707 
708   join->name = NULL; /* unique join name, used for variable substitution */
709 
710   join->items = NULL; /* array to hold item names for the joined table */
711   join->values = NULL; /* arrays of strings to holds one record worth of data */
712 
713   join->table = NULL;
714 
715   join->joininfo = NULL;
716 
717   join->from = NULL; /* join items */
718   join->to = NULL;
719 
720   join->header = NULL;
721   join->template = NULL; /* only html type templates are supported */
722   join->footer = NULL;
723 
724   join->type = MS_JOIN_ONE_TO_ONE;
725 
726   join->connection = NULL;
727   join->connectiontype = MS_DB_XBASE;
728 }
729 
freeJoin(joinObj * join)730 void freeJoin(joinObj *join)
731 {
732   msFree(join->name);
733   msFree(join->table);
734   msFree(join->from);
735   msFree(join->to);
736 
737   msFree(join->header);
738   msFree(join->template);
739   msFree(join->footer);
740 
741   msFreeCharArray(join->items, join->numitems); /* these may have been free'd elsewhere */
742   msFreeCharArray(join->values, join->numitems);
743   join->numitems = 0;
744 
745   msJoinClose(join);
746   msFree(join->connection);
747 }
748 
loadJoin(joinObj * join)749 int loadJoin(joinObj *join)
750 {
751   int nTmp;
752   initJoin(join);
753 
754   for(;;) {
755     switch(msyylex()) {
756       case(CONNECTION):
757         if(getString(&join->connection) == MS_FAILURE) return(-1);
758         break;
759       case(CONNECTIONTYPE):
760         if((nTmp = getSymbol(5, MS_DB_XBASE, MS_DB_MYSQL, MS_DB_ORACLE, MS_DB_POSTGRES, MS_DB_CSV)) == -1) return(-1);
761         join->connectiontype = nTmp;
762         break;
763       case(EOF):
764         msSetError(MS_EOFERR, NULL, "loadJoin()");
765         return(-1);
766       case(END):
767         if((join->from == NULL) || (join->to == NULL) || (join->table == NULL)) {
768           msSetError(MS_EOFERR, "Join must define table, name, from and to properties.", "loadJoin()");
769           return(-1);
770         }
771         if((join->type == MS_MULTIPLE) && ((join->template == NULL) || (join->name == NULL))) {
772           msSetError(MS_EOFERR, "One-to-many joins must define template and name properties.", "loadJoin()");
773           return(-1);
774         }
775         return(0);
776       case(FOOTER):
777         if(getString(&join->footer) == MS_FAILURE) return(-1);
778         break;
779       case(FROM):
780         if(getString(&join->from) == MS_FAILURE) return(-1);
781         break;
782       case(HEADER):
783         if(getString(&join->header) == MS_FAILURE) return(-1);
784         break;
785       case(JOIN):
786         break; /* for string loads */
787       case(NAME):
788         if(getString(&join->name) == MS_FAILURE) return(-1);
789         break;
790       case(TABLE):
791         if(getString(&join->table) == MS_FAILURE) return(-1);
792         break;
793       case(TEMPLATE):
794         if(getString(&join->template) == MS_FAILURE) return(-1);
795         break;
796       case(TO):
797         if(getString(&join->to) == MS_FAILURE) return(-1);
798         break;
799       case(TYPE):
800         if((nTmp = getSymbol(2, MS_JOIN_ONE_TO_ONE, MS_JOIN_ONE_TO_MANY)) == -1) return(-1);
801         join->type = nTmp;
802         break;
803       default:
804         msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadJoin()", msyystring_buffer, msyylineno);
805         return(-1);
806     }
807   } /* next token */
808 }
809 
writeScaleToken(FILE * stream,int indent,scaleTokenObj * token)810 static void writeScaleToken(FILE *stream, int indent, scaleTokenObj *token) {
811   int i;
812   indent++;
813   writeBlockBegin(stream,indent,"SCALETOKEN");
814   writeString(stream, indent, "NAME", NULL, token->name);
815   indent++;
816   writeBlockBegin(stream,indent,"VALUES");
817   for(i=0;i<token->n_entries;i++) {
818     char minscale[32];
819     sprintf(minscale,"%g",token->tokens[i].minscale);
820     writeNameValuePair(stream, indent, minscale, token->tokens[i].value);
821   }
822   writeBlockEnd(stream,indent,"VALUES");
823   indent--;
824   writeBlockEnd(stream,indent,"SCALETOKEN");
825 }
826 
writeJoin(FILE * stream,int indent,joinObj * join)827 static void writeJoin(FILE *stream, int indent, joinObj *join)
828 {
829   indent++;
830   writeBlockBegin(stream, indent, "JOIN");
831   writeString(stream, indent, "FOOTER", NULL, join->footer);
832   writeString(stream, indent, "FROM", NULL, join->from);
833   writeString(stream, indent, "HEADER", NULL, join->header);
834   writeString(stream, indent, "NAME", NULL, join->name);
835   writeString(stream, indent, "TABLE", NULL, join->table);
836   writeString(stream, indent, "TEMPLATE", NULL, join->template);
837   writeString(stream, indent, "TO", NULL, join->to);
838   writeKeyword(stream, indent, "CONNECTIONTYPE", join->connectiontype, 3, MS_DB_CSV, "CSV", MS_DB_POSTGRES, "POSTRESQL", MS_DB_MYSQL, "MYSQL");
839   writeKeyword(stream, indent, "TYPE", join->type, 1, MS_JOIN_ONE_TO_MANY, "ONE-TO-MANY");
840   writeBlockEnd(stream, indent, "JOIN");
841 }
842 
843 /* inserts a feature at the end of the list, can create a new list */
insertFeatureList(featureListNodeObjPtr * list,shapeObj * shape)844 featureListNodeObjPtr insertFeatureList(featureListNodeObjPtr *list, shapeObj *shape)
845 {
846   featureListNodeObjPtr node;
847 
848   node = (featureListNodeObjPtr) msSmallMalloc(sizeof(featureListNodeObj));
849 
850   msInitShape(&(node->shape));
851   if(msCopyShape(shape, &(node->shape)) == -1) {
852     msFree(node);
853     return(NULL);
854   }
855 
856   /* AJS - alans@wunderground.com O(n^2) -> O(n) conversion, keep a pointer to the end */
857 
858   /* set the tailifhead to NULL, since it is only set for the head of the list */
859   node->tailifhead = NULL;
860   node->next = NULL;
861 
862   /* if we are at the head of the list, we need to set the list to node, before pointing tailifhead somewhere  */
863   if(*list == NULL) {
864     *list=node;
865   } else {
866     if((*list)->tailifhead!=NULL) /* this should never be NULL, but just in case */
867       (*list)->tailifhead->next=node; /* put the node at the end of the list */
868   }
869 
870   /* repoint the head of the list to the end  - our new element
871      this causes a loop if we are at the head, be careful not to
872      walk in a loop */
873   (*list)->tailifhead = node;
874 
875   return(node); /* a pointer to last object in the list */
876 }
877 
freeFeatureList(featureListNodeObjPtr list)878 void freeFeatureList(featureListNodeObjPtr list)
879 {
880   featureListNodeObjPtr listNext = NULL;
881   while (list!=NULL) {
882     listNext = list->next;
883     msFreeShape(&(list->shape));
884     msFree(list);
885     list = listNext;
886   }
887 }
888 
889 /* lineObj = multipointObj */
loadFeaturePoints(lineObj * points)890 static int loadFeaturePoints(lineObj *points)
891 {
892   int buffer_size=0;
893 
894   points->point = (pointObj *)malloc(sizeof(pointObj)*MS_FEATUREINITSIZE);
895   MS_CHECK_ALLOC(points->point, sizeof(pointObj)*MS_FEATUREINITSIZE, MS_FAILURE);
896   points->numpoints = 0;
897   buffer_size = MS_FEATUREINITSIZE;
898 
899   for(;;) {
900     switch(msyylex()) {
901       case(EOF):
902         msSetError(MS_EOFERR, NULL, "loadFeaturePoints()");
903         return(MS_FAILURE);
904       case(END):
905         return(MS_SUCCESS);
906       case(MS_NUMBER):
907         if(points->numpoints == buffer_size) { /* just add it to the end */
908           points->point = (pointObj *) realloc(points->point, sizeof(pointObj)*(buffer_size+MS_FEATUREINCREMENT));
909           MS_CHECK_ALLOC(points->point, sizeof(pointObj)*(buffer_size+MS_FEATUREINCREMENT), MS_FAILURE);
910           buffer_size+=MS_FEATUREINCREMENT;
911         }
912 
913         points->point[points->numpoints].x = atof(msyystring_buffer);
914         if(getDouble(&(points->point[points->numpoints].y)) == -1) return(MS_FAILURE);
915 
916         points->numpoints++;
917         break;
918       default:
919         msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadFeaturePoints()",  msyystring_buffer, msyylineno );
920         return(MS_FAILURE);
921     }
922   }
923 }
924 
loadFeature(layerObj * player,int type)925 static int loadFeature(layerObj *player, int type)
926 {
927   int status=MS_SUCCESS;
928   featureListNodeObjPtr *list = &(player->features);
929   multipointObj points= {0,NULL};
930   shapeObj *shape=NULL;
931 
932   shape = (shapeObj *) malloc(sizeof(shapeObj));
933   MS_CHECK_ALLOC(shape, sizeof(shapeObj), MS_FAILURE);
934 
935   msInitShape(shape);
936   shape->type = type;
937 
938   for(;;) {
939     switch(msyylex()) {
940       case(EOF):
941         msSetError(MS_EOFERR, NULL, "loadFeature()");
942         msFreeShape(shape); /* clean up */
943         msFree(shape);
944         return(MS_FAILURE);
945       case(END):
946         if(player->features != NULL && player->features->tailifhead != NULL)
947           shape->index = player->features->tailifhead->shape.index + 1;
948         else
949           shape->index = 0;
950         if(insertFeatureList(list, shape) == NULL)
951           status = MS_FAILURE;
952 
953         msFreeShape(shape); /* clean up */
954         msFree(shape);
955 
956         return(status);
957       case(FEATURE):
958         break; /* for string loads */
959       case(POINTS):
960         if(loadFeaturePoints(&points) == MS_FAILURE) {
961           msFreeShape(shape); /* clean up */
962           msFree(shape);
963           return(MS_FAILURE);
964         }
965         status = msAddLine(shape, &points);
966 
967         msFree(points.point); /* clean up */
968         points.numpoints = 0;
969 
970         if(status == MS_FAILURE) {
971           msFreeShape(shape); /* clean up */
972           msFree(shape);
973           return(MS_FAILURE);
974         }
975         break;
976       case(ITEMS): {
977         char *string=NULL;
978         if(getString(&string) == MS_FAILURE) {
979           msFreeShape(shape); /* clean up */
980           msFree(shape);
981           return(MS_FAILURE);
982         }
983         if (string) {
984           if(shape->values) msFreeCharArray(shape->values, shape->numvalues);
985           shape->values = msStringSplitComplex(string, ";", &shape->numvalues,MS_ALLOWEMPTYTOKENS);
986           msFree(string); /* clean up */
987         }
988         break;
989       }
990       case(TEXT):
991         if(getString(&shape->text) == MS_FAILURE) {
992           msFreeShape(shape); /* clean up */
993           msFree(shape);
994           return(MS_FAILURE);
995         }
996         break;
997       case(WKT): {
998         char *string=NULL;
999 
1000         /* todo, what do we do with multiple WKT property occurances? */
1001 
1002         msFreeShape(shape);
1003         msFree(shape);
1004         if(getString(&string) == MS_FAILURE) return(MS_FAILURE);
1005 
1006         if((shape = msShapeFromWKT(string)) == NULL)
1007           status = MS_FAILURE;
1008 
1009         msFree(string); /* clean up */
1010 
1011         if(status == MS_FAILURE) {
1012           msFreeShape(shape); /* clean up */
1013           msFree(shape);
1014           return(MS_FAILURE);
1015         }
1016         break;
1017       }
1018       default:
1019         msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadfeature()", msyystring_buffer, msyylineno);
1020         msFreeShape(shape); /* clean up */
1021         msFree(shape);
1022         return(MS_FAILURE);
1023     }
1024   } /* next token */
1025 }
1026 
writeFeature(FILE * stream,int indent,shapeObj * feature)1027 static void writeFeature(FILE *stream, int indent, shapeObj *feature)
1028 {
1029   int i,j;
1030 
1031   indent++;
1032   writeBlockBegin(stream, indent, "FEATURE");
1033 
1034   indent++;
1035   for(i=0; i<feature->numlines; i++) {
1036     writeBlockBegin(stream, indent, "POINTS");
1037     for(j=0; j<feature->line[i].numpoints; j++) {
1038       writeIndent(stream, indent);
1039       msIO_fprintf(stream, "%.15g %.15g\n", feature->line[i].point[j].x, feature->line[i].point[j].y);
1040     }
1041     writeBlockEnd(stream, indent, "POINTS");
1042   }
1043   indent--;
1044 
1045   if (feature->numvalues) {
1046     writeIndent(stream, indent);
1047     msIO_fprintf(stream, "ITEMS \"");
1048     for (i=0; i<feature->numvalues; i++) {
1049       if (i == 0)
1050         msIO_fprintf(stream, "%s", feature->values[i]);
1051       else
1052         msIO_fprintf(stream, ";%s", feature->values[i]);
1053     }
1054     msIO_fprintf(stream, "\"\n");
1055   }
1056 
1057   writeString(stream, indent, "TEXT", NULL, feature->text);
1058   writeBlockEnd(stream, indent, "FEATURE");
1059 }
1060 
initGrid(graticuleObj * pGraticule)1061 void initGrid( graticuleObj *pGraticule )
1062 {
1063   memset( pGraticule, 0, sizeof( graticuleObj ) );
1064 }
1065 
freeGrid(graticuleObj * pGraticule)1066 void freeGrid( graticuleObj *pGraticule )
1067 {
1068   msFree(pGraticule->labelformat);
1069   msFree(pGraticule->pboundingpoints);
1070   msFree(pGraticule->pboundinglines);
1071 }
1072 
loadGrid(layerObj * pLayer)1073 static int loadGrid( layerObj *pLayer )
1074 {
1075   for(;;) {
1076     switch(msyylex()) {
1077       case(EOF):
1078         msSetError(MS_EOFERR, NULL, "loadGrid()");
1079         return(-1);
1080       case(END):
1081         return(0);
1082       case(GRID):
1083         break; /* for string loads */
1084       case( LABELFORMAT ):
1085         if(getString(&(pLayer->grid->labelformat)) == MS_FAILURE) {
1086           if(strcasecmp(msyystring_buffer, "DD") == 0) /* DD triggers a symbol to be returned instead of a string so check for this special case */
1087             pLayer->grid->labelformat = msStrdup("DD");
1088           else
1089             return(-1);
1090         }
1091         break;
1092       case( MINARCS ):
1093         if(getDouble(&(pLayer->grid->minarcs)) == -1)
1094           return(-1);
1095         break;
1096       case( MAXARCS ):
1097         if(getDouble(&(pLayer->grid->maxarcs)) == -1)
1098           return(-1);
1099         break;
1100       case( MININTERVAL ):
1101         if(getDouble(&(pLayer->grid->minincrement)) == -1)
1102           return(-1);
1103         break;
1104       case( MAXINTERVAL ):
1105         if(getDouble(&(pLayer->grid->maxincrement)) == -1)
1106           return(-1);
1107         break;
1108       case( MINSUBDIVIDE ):
1109         if(getDouble(&(pLayer->grid->minsubdivides)) == -1)
1110           return(-1);
1111         break;
1112       case( MAXSUBDIVIDE ):
1113         if(getDouble(&(pLayer->grid->maxsubdivides)) == -1)
1114           return(-1);
1115         break;
1116       default:
1117         msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadGrid()", msyystring_buffer, msyylineno);
1118         return(-1);
1119     }
1120   }
1121 }
1122 
writeGrid(FILE * stream,int indent,graticuleObj * pGraticule)1123 static void writeGrid(FILE *stream, int indent, graticuleObj *pGraticule)
1124 {
1125   if(!pGraticule) return;
1126 
1127   indent++;
1128   writeBlockBegin(stream, indent, "GRID");
1129   writeString(stream, indent, "LABELFORMAT", NULL, pGraticule->labelformat);
1130   writeNumber(stream, indent, "MAXARCS", 0, pGraticule->maxarcs);
1131   writeNumber(stream, indent, "MAXSUBDIVIDE", 0, pGraticule->maxsubdivides);
1132   writeNumber(stream, indent, "MAXINTERVAL", 0, pGraticule->maxincrement);
1133   writeNumber(stream, indent, "MINARCS", 0, pGraticule->minarcs);
1134   writeNumber(stream, indent, "MININTERVAL", 0, pGraticule->minincrement);
1135   writeNumber(stream, indent, "MINSUBDIVIDE", 0, pGraticule->minsubdivides);
1136   writeBlockEnd(stream, indent, "GRID");
1137 }
1138 
loadProjection(projectionObj * p)1139 static int loadProjection(projectionObj *p)
1140 {
1141   int i=0;
1142 
1143   p->gt.need_geotransform = MS_FALSE;
1144 
1145   if ( p->proj != NULL ) {
1146     msSetError(MS_MISCERR, "Projection is already initialized. Multiple projection definitions are not allowed in this object. (line %d)",
1147                "loadProjection()", msyylineno);
1148     return(-1);
1149   }
1150 
1151   for(;;) {
1152     switch(msyylex()) {
1153       case(EOF):
1154         msSetError(MS_EOFERR, NULL, "loadProjection()");
1155         return(-1);
1156       case(END):
1157         if( i == 1 && strstr(p->args[0],"+") != NULL ) {
1158           char *one_line_def = p->args[0];
1159           int result;
1160 
1161           p->args[0] = NULL;
1162           result = msLoadProjectionString( p, one_line_def );
1163           free( one_line_def );
1164           return result;
1165         } else {
1166           p->numargs = i;
1167           if(p->numargs != 0)
1168             return msProcessProjection(p);
1169           else
1170             return 0;
1171         }
1172         break;
1173       case(MS_STRING):
1174       case(MS_AUTO):
1175         p->args[i] = msStrdup(msyystring_buffer);
1176         p->automatic = MS_TRUE;
1177         i++;
1178         break;
1179       default:
1180         msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadProjection()",
1181                    msyystring_buffer, msyylineno);
1182         return(-1);
1183     }
1184   } /* next token */
1185 }
1186 
1187 
1188 /************************************************************************/
1189 /*                     msLoadProjectionStringEPSGLike                   */
1190 /************************************************************************/
1191 
msLoadProjectionStringEPSGLike(projectionObj * p,const char * value,const char * pszPrefix,int bFollowEPSGAxisOrder)1192 static int msLoadProjectionStringEPSGLike(projectionObj *p, const char *value,
1193                                           const char* pszPrefix,
1194                                           int bFollowEPSGAxisOrder)
1195 {
1196     size_t buffer_size = 0;
1197     char *init_string =  NULL;
1198     const char *code;
1199     const char *next_sep;
1200     size_t prefix_len;
1201 
1202     prefix_len = strlen(pszPrefix);
1203     if( strncasecmp(value, pszPrefix, prefix_len) != 0 )
1204         return -1;
1205 
1206     code = value + prefix_len;
1207     next_sep = strchr(code, pszPrefix[prefix_len-1]);
1208     if( next_sep != NULL )
1209         code = next_sep + 1;
1210 
1211     buffer_size = 10 + strlen(code) + 1;
1212     init_string = (char*)msSmallMalloc(buffer_size);
1213 
1214     /* translate into PROJ.4 format. */
1215     snprintf( init_string, buffer_size, "init=epsg:%s", code );
1216 
1217     p->args = (char**)msSmallMalloc(sizeof(char*) * 2);
1218     p->args[0] = init_string;
1219     p->numargs = 1;
1220 
1221     if( bFollowEPSGAxisOrder && msIsAxisInverted(atoi(code))) {
1222       p->args[1] = msStrdup("+epsgaxis=ne");
1223       p->numargs = 2;
1224     }
1225 
1226     return 0;
1227 }
1228 
1229 /************************************************************************/
1230 /*                     msLoadProjectionStringCRSLike                    */
1231 /************************************************************************/
1232 
msLoadProjectionStringCRSLike(projectionObj * p,const char * value,const char * pszPrefix)1233 static int msLoadProjectionStringCRSLike(projectionObj *p, const char *value,
1234                                          const char* pszPrefix)
1235 {
1236     char init_string[100];
1237     const char *id;
1238     const char *next_sep;
1239     size_t prefix_len;
1240 
1241     prefix_len = strlen(pszPrefix);
1242     if( strncasecmp(value, pszPrefix, prefix_len) != 0 )
1243         return -1;
1244 
1245     id = value + prefix_len;
1246     next_sep = strchr(id, pszPrefix[prefix_len-1]);
1247     if( next_sep != NULL )
1248         id = next_sep + 1;
1249 
1250     init_string[0] = '\0';
1251 
1252     if( strcasecmp(id,"84") == 0 || strcasecmp(id,"CRS84") == 0 )
1253       strncpy( init_string, "init=epsg:4326", sizeof(init_string) );
1254     else if( strcasecmp(id,"83") == 0 || strcasecmp(id,"CRS83") == 0 )
1255       strncpy( init_string, "init=epsg:4269", sizeof(init_string) );
1256     else if( strcasecmp(id,"27") == 0 || strcasecmp(id,"CRS27") == 0 )
1257       strncpy( init_string, "init=epsg:4267", sizeof(init_string) );
1258     else {
1259       msSetError( MS_PROJERR,
1260                   "Unrecognised OGC CRS def '%s'.",
1261                   "msLoadProjectionString()",
1262                   value );
1263       return -1;
1264     }
1265 
1266     p->args = (char**)msSmallMalloc(sizeof(char*) * 2);
1267     p->args[0] = msStrdup(init_string);
1268     p->numargs = 1;
1269 
1270     return 0;
1271 }
1272 
1273 /************************************************************************/
1274 /*                         msLoadProjectionStringEPSG                   */
1275 /*                                                                      */
1276 /*      Checks for EPSG type projection and set the axes for a          */
1277 /*      certain code ranges.                                            */
1278 /*      Use for now in WMS 1.3.0 and WFS >= 1.1.0                       */
1279 /************************************************************************/
msLoadProjectionStringEPSG(projectionObj * p,const char * value)1280 int msLoadProjectionStringEPSG(projectionObj *p, const char *value)
1281 {
1282   assert(p);
1283 
1284   msFreeProjectionExceptContext(p);
1285 
1286   p->gt.need_geotransform = MS_FALSE;
1287 #ifdef USE_PROJ_FASTPATHS
1288   if(strcasestr(value,"epsg:4326")) {
1289     p->wellknownprojection = wkp_lonlat;
1290   } else if(strcasestr(value,"epsg:3857")) {
1291     p->wellknownprojection = wkp_gmerc;
1292   } else {
1293     p->wellknownprojection = wkp_none;
1294   }
1295 #endif
1296 
1297   if( msLoadProjectionStringEPSGLike(p, value, "EPSG:", MS_TRUE) == 0 )
1298   {
1299     return msProcessProjection( p );
1300   }
1301 
1302   return msLoadProjectionString(p, value);
1303 }
1304 
msLoadProjectionString(projectionObj * p,const char * value)1305 int msLoadProjectionString(projectionObj *p, const char *value)
1306 {
1307   assert(p);
1308   p->gt.need_geotransform = MS_FALSE;
1309 
1310   msFreeProjectionExceptContext(p);
1311 
1312   /*
1313    * Handle new style definitions, the same as they would be given to
1314    * the proj program.
1315    * eg.
1316    *    "+proj=utm +zone=11 +ellps=WGS84"
1317    */
1318   if( value[0] == '+' ) {
1319     char  *trimmed;
1320     int i, i_out=0;
1321 
1322     trimmed = msStrdup(value+1);
1323     for( i = 1; value[i] != '\0'; i++ ) {
1324       if( !isspace( value[i] ) )
1325         trimmed[i_out++] = value[i];
1326     }
1327     trimmed[i_out] = '\0';
1328 
1329     p->args = msStringSplit(trimmed,'+', &p->numargs);
1330     free( trimmed );
1331   } else if (strncasecmp(value, "AUTO:", 5) == 0 ||
1332              strncasecmp(value, "AUTO2:", 6) == 0) {
1333     /* WMS/WFS AUTO projection: "AUTO:proj_id,units_id,lon0,lat0" */
1334     /* WMS 1.3.0 projection: "AUTO2:auto_crs_id,factor,lon0,lat0"*/
1335     /* Keep the projection defn into a single token for writeProjection() */
1336     /* to work fine. */
1337     p->args = (char**)msSmallMalloc(sizeof(char*));
1338     p->args[0] = msStrdup(value);
1339     p->numargs = 1;
1340   } else if (msLoadProjectionStringEPSGLike(p, value, "EPSG:", MS_FALSE) == 0 ) {
1341    /* Assume lon/lat ordering. Use msLoadProjectionStringEPSG() if wanting to follow EPSG axis */
1342   } else if (msLoadProjectionStringEPSGLike(p, value, "urn:ogc:def:crs:EPSG:", MS_TRUE) == 0 ) {
1343   } else if (msLoadProjectionStringEPSGLike(p, value, "urn:EPSG:geographicCRS:", MS_TRUE) == 0 ) {
1344   } else if (msLoadProjectionStringEPSGLike(p, value, "urn:x-ogc:def:crs:EPSG:", MS_TRUE) == 0 ) {
1345     /*this case is to account for OGC CITE tests where x-ogc was used
1346       before the ogc name became an official NID. Note also we also account
1347       for the fact that a space for the version of the espg is not used with CITE tests.
1348       (Syntax used could be urn:ogc:def:objectType:authority:code)*/
1349   } else if (msLoadProjectionStringCRSLike(p, value, "urn:ogc:def:crs:OGC:") == 0 ) {
1350   } else if (msLoadProjectionStringEPSGLike(p, value, "http://www.opengis.net/def/crs/EPSG/", MS_TRUE) == 0 ) {
1351     /* URI projection support */
1352   } else if (msLoadProjectionStringCRSLike(p, value, "http://www.opengis.net/def/crs/OGC/") == 0 ) {
1353     /* Mandatory support for this URI format specified in WFS1.1 (also in 1.0?) */
1354   } else if (msLoadProjectionStringEPSGLike(p, value, "http://www.opengis.net/gml/srs/epsg.xml#", MS_FALSE) == 0 ) {
1355     /* We assume always lon/lat ordering, as that is what GeoServer does... */
1356   } else if (msLoadProjectionStringCRSLike(p, value, "CRS:") == 0 ) {
1357   }
1358   /*
1359    * Handle old style comma delimited.  eg. "proj=utm,zone=11,ellps=WGS84".
1360    */
1361   else {
1362     p->args = msStringSplit(value,',', &p->numargs);
1363   }
1364 
1365   return msProcessProjection( p );
1366 }
1367 
writeProjection(FILE * stream,int indent,projectionObj * p)1368 static void writeProjection(FILE *stream, int indent, projectionObj *p)
1369 {
1370   int i;
1371 
1372   if(!p || p->numargs <= 0) return;
1373   indent++;
1374   writeBlockBegin(stream, indent, "PROJECTION");
1375   for(i=0; i<p->numargs; i++)
1376     writeString(stream, indent, NULL, NULL, p->args[i]);
1377   writeBlockEnd(stream, indent, "PROJECTION");
1378 }
1379 
initLeader(labelLeaderObj * leader)1380 void initLeader(labelLeaderObj *leader)
1381 {
1382   leader->gridstep = 5;
1383   leader->maxdistance = 0;
1384 
1385   /* Set maxstyles = 0, styles[] will be allocated as needed on first call
1386    * to msGrowLabelLeaderStyles()
1387    */
1388   leader->numstyles = leader->maxstyles = 0;
1389   leader->styles = NULL;
1390 }
1391 
1392 /*
1393 ** Initialize, load and free a labelObj structure
1394 */
initLabel(labelObj * label)1395 void initLabel(labelObj *label)
1396 {
1397   int i;
1398 
1399   MS_REFCNT_INIT(label);
1400 
1401   label->align = MS_ALIGN_DEFAULT;
1402   MS_INIT_COLOR(label->color, 0,0,0,255);
1403   MS_INIT_COLOR(label->outlinecolor, -1,-1,-1,255); /* don't use it */
1404   label->outlinewidth=1;
1405 
1406   MS_INIT_COLOR(label->shadowcolor, -1,-1,-1,255); /* don't use it */
1407   label->shadowsizex = label->shadowsizey = 1;
1408 
1409   label->font = NULL;
1410   label->size = MS_MEDIUM;
1411 
1412   label->position = MS_CC;
1413   label->angle = 0;
1414   label->anglemode = MS_NONE;
1415   label->minsize = MS_MINFONTSIZE;
1416   label->maxsize = MS_MAXFONTSIZE;
1417   label->buffer = 0;
1418   label->offsetx = label->offsety = 0;
1419   label->minscaledenom=-1;
1420   label->maxscaledenom=-1;
1421   label->minfeaturesize = -1; /* no limit */
1422   label->autominfeaturesize = MS_FALSE;
1423   label->mindistance = -1; /* no limit */
1424   label->repeatdistance = 0; /* no repeat */
1425   label->maxoverlapangle = 22.5; /* default max overlap angle */
1426   label->partials = MS_FALSE;
1427   label->wrap = '\0';
1428   label->maxlength = 0;
1429   label->minlength = 0;
1430   label->space_size_10=0.0;
1431 
1432   label->encoding = NULL;
1433 
1434   label->force = MS_OFF;
1435   label->priority = MS_DEFAULT_LABEL_PRIORITY;
1436 
1437   /* Set maxstyles = 0, styles[] will be allocated as needed on first call
1438    * to msGrowLabelStyles()
1439    */
1440   label->numstyles = label->maxstyles = 0;
1441   label->styles = NULL;
1442 
1443   label->numbindings = 0;
1444   label->nexprbindings = 0;
1445   for(i=0; i<MS_LABEL_BINDING_LENGTH; i++) {
1446     label->bindings[i].item = NULL;
1447     label->bindings[i].index = -1;
1448     msInitExpression(&(label->exprBindings[i]));
1449   }
1450 
1451   msInitExpression(&(label->expression));
1452   msInitExpression(&(label->text));
1453 
1454   label->leader = NULL;
1455 
1456   return;
1457 }
1458 
freeLabelLeader(labelLeaderObj * leader)1459 int freeLabelLeader(labelLeaderObj *leader)
1460 {
1461   int i;
1462   for(i=0; i<leader->numstyles; i++) {
1463     msFree(leader->styles[i]);
1464   }
1465   msFree(leader->styles);
1466 
1467   return MS_SUCCESS;
1468 }
freeLabel(labelObj * label)1469 int freeLabel(labelObj *label)
1470 {
1471   int i;
1472 
1473   if( MS_REFCNT_DECR_IS_NOT_ZERO(label) ) {
1474     return MS_FAILURE;
1475   }
1476 
1477   msFree(label->font);
1478   msFree(label->encoding);
1479 
1480   for(i=0; i<label->numstyles; i++) { /* each style */
1481     if(label->styles[i]!=NULL) {
1482       if(freeStyle(label->styles[i]) == MS_SUCCESS) {
1483         msFree(label->styles[i]);
1484       }
1485     }
1486   }
1487   msFree(label->styles);
1488 
1489   for(i=0; i<MS_LABEL_BINDING_LENGTH; i++) {
1490     msFree(label->bindings[i].item);
1491     msFreeExpression(&(label->exprBindings[i]));
1492   }
1493 
1494   msFreeExpression(&(label->expression));
1495   msFreeExpression(&(label->text));
1496 
1497   if(label->leader) {
1498     freeLabelLeader(label->leader);
1499     msFree(label->leader);
1500     label->leader = NULL;
1501   }
1502 
1503   return MS_SUCCESS;
1504 }
1505 
loadLeader(labelLeaderObj * leader)1506 static int loadLeader(labelLeaderObj *leader)
1507 {
1508   for(;;) {
1509     switch(msyylex()) {
1510       case(END):
1511         return(0);
1512         break;
1513       case(EOF):
1514         msSetError(MS_EOFERR, NULL, "loadLeader()");
1515         return(-1);
1516       case GRIDSTEP:
1517         if(getInteger(&(leader->gridstep)) == -1) return(-1);
1518         break;
1519       case MAXDISTANCE:
1520         if(getInteger(&(leader->maxdistance)) == -1) return(-1);
1521         break;
1522       case STYLE:
1523         if(msGrowLeaderStyles(leader) == NULL)
1524           return(-1);
1525         initStyle(leader->styles[leader->numstyles]);
1526         if(loadStyle(leader->styles[leader->numstyles]) != MS_SUCCESS) return(-1);
1527         leader->numstyles++;
1528         break;
1529       default:
1530         if(strlen(msyystring_buffer) > 0) {
1531           msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadLeader()", msyystring_buffer, msyylineno);
1532           return(-1);
1533         } else {
1534           return(0); /* end of a string, not an error */
1535         }
1536     }
1537   }
1538 }
1539 
loadLabel(labelObj * label)1540 static int loadLabel(labelObj *label)
1541 {
1542   int symbol;
1543 
1544   for(;;) {
1545     switch(msyylex()) {
1546       case(ANGLE):
1547         if((symbol = getSymbol(5, MS_NUMBER,MS_AUTO,MS_AUTO2,MS_FOLLOW,MS_BINDING)) == -1)
1548           return(-1);
1549 
1550         if(symbol == MS_NUMBER)
1551           label->angle = msyynumber;
1552         else if(symbol == MS_BINDING) {
1553           if (label->bindings[MS_LABEL_BINDING_ANGLE].item != NULL)
1554             msFree(label->bindings[MS_LABEL_BINDING_ANGLE].item);
1555           label->bindings[MS_LABEL_BINDING_ANGLE].item = msStrdup(msyystring_buffer);
1556           label->numbindings++;
1557         } else {
1558           label->anglemode = symbol;
1559         }
1560         break;
1561       case(ALIGN):
1562         if((symbol = getSymbol(4, MS_ALIGN_LEFT,MS_ALIGN_CENTER,MS_ALIGN_RIGHT,MS_BINDING)) == -1)
1563           return(-1);
1564         if((symbol == MS_ALIGN_LEFT)||(symbol == MS_ALIGN_CENTER)||(symbol == MS_ALIGN_RIGHT)) {
1565           label->align = symbol;
1566         } else {
1567           if (label->bindings[MS_LABEL_BINDING_ALIGN].item != NULL)
1568             msFree(label->bindings[MS_LABEL_BINDING_ALIGN].item);
1569           label->bindings[MS_LABEL_BINDING_ALIGN].item = msStrdup(msyystring_buffer);
1570           label->numbindings++;
1571         }
1572         break;
1573       case(ANTIALIAS): /*ignore*/
1574         msyylex();
1575         break;
1576       case(BUFFER):
1577         if(getInteger(&(label->buffer)) == -1) return(-1);
1578         break;
1579       case(COLOR):
1580         if(loadColor(&(label->color), &(label->bindings[MS_LABEL_BINDING_COLOR])) != MS_SUCCESS) return(-1);
1581         if(label->bindings[MS_LABEL_BINDING_COLOR].item) label->numbindings++;
1582         break;
1583       case(ENCODING):
1584         if((getString(&label->encoding)) == MS_FAILURE) return(-1);
1585         break;
1586       case(END):
1587         return(0);
1588         break;
1589       case(EOF):
1590         msSetError(MS_EOFERR, NULL, "loadLabel()");
1591         freeLabel(label);       /* free any structures allocated before EOF */
1592         return(-1);
1593       case(EXPRESSION):
1594         if(loadExpression(&(label->expression)) == -1) return(-1); /* loadExpression() cleans up previously allocated expression */
1595         if(msyysource == MS_URL_TOKENS) {
1596           msSetError(MS_MISCERR, "URL-based EXPRESSION configuration not supported." , "loadLabel()");
1597           msFreeExpression(&(label->expression));
1598           return(-1);
1599         }
1600         break;
1601       case(FONT):
1602         if((symbol = getSymbol(2, MS_STRING, MS_BINDING)) == -1)
1603           return(-1);
1604 
1605         if(symbol == MS_STRING) {
1606           if (label->font != NULL)
1607             msFree(label->font);
1608           label->font = msStrdup(msyystring_buffer);
1609         } else {
1610           if (label->bindings[MS_LABEL_BINDING_FONT].item != NULL)
1611             msFree(label->bindings[MS_LABEL_BINDING_FONT].item);
1612           label->bindings[MS_LABEL_BINDING_FONT].item = msStrdup(msyystring_buffer);
1613           label->numbindings++;
1614         }
1615         break;
1616       case(FORCE):
1617         switch(msyylex()) {
1618           case MS_ON:
1619             label->force = MS_ON;
1620             break;
1621           case MS_OFF:
1622             label->force = MS_OFF;
1623             break;
1624           case GROUP:
1625             label->force = MS_LABEL_FORCE_GROUP;
1626             break;
1627           default:
1628             msSetError(MS_MISCERR, "Invalid FORCE, must be ON,OFF,or GROUP" , "loadLabel()");
1629             return(-1);
1630         }
1631         break;
1632       case(LABEL):
1633         break; /* for string loads */
1634       case(LEADER):
1635         msSetError(MS_MISCERR, "LABEL LEADER not implemented. LEADER goes at the CLASS level." , "loadLabel()");
1636         return(-1);
1637         label->leader = msSmallMalloc(sizeof(labelLeaderObj));
1638         if(loadLeader(label->leader) == -1) return(-1);
1639         break;
1640       case(MAXSIZE):
1641         if(getInteger(&(label->maxsize)) == -1) return(-1);
1642         break;
1643       case(MAXSCALEDENOM):
1644         if(getDouble(&(label->maxscaledenom)) == -1) return(-1);
1645         break;
1646       case(MAXLENGTH):
1647         if(getInteger(&(label->maxlength)) == -1) return(-1);
1648         break;
1649       case(MINLENGTH):
1650         if(getInteger(&(label->minlength)) == -1) return(-1);
1651         break;
1652       case(MINDISTANCE):
1653         if(getInteger(&(label->mindistance)) == -1) return(-1);
1654         break;
1655       case(REPEATDISTANCE):
1656         if(getInteger(&(label->repeatdistance)) == -1) return(-1);
1657         break;
1658       case(MAXOVERLAPANGLE):
1659         if(getDouble(&(label->maxoverlapangle)) == -1) return(-1);
1660         break;
1661       case(MINFEATURESIZE):
1662         if((symbol = getSymbol(2, MS_NUMBER,MS_AUTO)) == -1)  return(-1);
1663         if(symbol == MS_NUMBER)
1664           label->minfeaturesize = (int)msyynumber;
1665         else
1666           label->autominfeaturesize = MS_TRUE;
1667         break;
1668       case(MINSCALEDENOM):
1669         if(getDouble(&(label->minscaledenom)) == -1) return(-1);
1670         break;
1671       case(MINSIZE):
1672         if(getInteger(&(label->minsize)) == -1) return(-1);
1673         break;
1674       case(OFFSET):
1675         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(MS_FAILURE);
1676         if(symbol == MS_NUMBER)
1677           label->offsetx = (int) msyynumber;
1678         else {
1679           if (label->bindings[MS_LABEL_BINDING_OFFSET_X].item != NULL)
1680             msFree(label->bindings[MS_LABEL_BINDING_OFFSET_X].item);
1681           label->bindings[MS_LABEL_BINDING_OFFSET_X].item = msStrdup(msyystring_buffer);
1682           label->numbindings++;
1683         }
1684 
1685         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(MS_FAILURE);
1686         if(symbol == MS_NUMBER)
1687           label->offsety = (int) msyynumber;
1688         else {
1689           if (label->bindings[MS_LABEL_BINDING_OFFSET_Y].item != NULL)
1690             msFree(label->bindings[MS_LABEL_BINDING_OFFSET_Y].item);
1691           label->bindings[MS_LABEL_BINDING_OFFSET_Y].item = msStrdup(msyystring_buffer);
1692           label->numbindings++;
1693         }
1694         break;
1695       case(OUTLINECOLOR):
1696         if(loadColor(&(label->outlinecolor), &(label->bindings[MS_LABEL_BINDING_OUTLINECOLOR])) != MS_SUCCESS) return(-1);
1697         if(label->bindings[MS_LABEL_BINDING_OUTLINECOLOR].item) label->numbindings++;
1698         break;
1699       case(OUTLINEWIDTH):
1700         if(getInteger(&(label->outlinewidth)) == -1) return(-1);
1701         break;
1702       case(PARTIALS):
1703         if((label->partials = getSymbol(2, MS_TRUE,MS_FALSE)) == -1) return(-1);
1704         break;
1705       case(POSITION):
1706         if((label->position = getSymbol(11, MS_UL,MS_UC,MS_UR,MS_CL,MS_CC,MS_CR,MS_LL,MS_LC,MS_LR,MS_AUTO,MS_BINDING)) == -1)
1707           return(-1);
1708         if(label->position == MS_BINDING) {
1709           if(label->bindings[MS_LABEL_BINDING_POSITION].item != NULL)
1710             msFree(label->bindings[MS_LABEL_BINDING_POSITION].item);
1711           label->bindings[MS_LABEL_BINDING_POSITION].item = msStrdup(msyystring_buffer);
1712           label->numbindings++;
1713         }
1714         break;
1715       case(PRIORITY):
1716         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(-1);
1717         if(symbol == MS_NUMBER) {
1718           label->priority = (int) msyynumber;
1719           if(label->priority < 1 || label->priority > MS_MAX_LABEL_PRIORITY) {
1720             msSetError(MS_MISCERR, "Invalid PRIORITY, must be an integer between 1 and %d." , "loadLabel()", MS_MAX_LABEL_PRIORITY);
1721             return(-1);
1722           }
1723         } else {
1724           if (label->bindings[MS_LABEL_BINDING_PRIORITY].item != NULL)
1725             msFree(label->bindings[MS_LABEL_BINDING_PRIORITY].item);
1726           label->bindings[MS_LABEL_BINDING_PRIORITY].item = msStrdup(msyystring_buffer);
1727           label->numbindings++;
1728         }
1729         break;
1730       case(SHADOWCOLOR):
1731         if(loadColor(&(label->shadowcolor), NULL) != MS_SUCCESS) return(-1);
1732         break;
1733       case(SHADOWSIZE):
1734         /* if(getInteger(&(label->shadowsizex)) == -1) return(-1); */
1735         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(-1);
1736         if(symbol == MS_NUMBER) {
1737           label->shadowsizex = (int) msyynumber;
1738         } else {
1739           if (label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].item != NULL)
1740             msFree(label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].item);
1741           label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].item = msStrdup(msyystring_buffer);
1742           label->numbindings++;
1743         }
1744 
1745         /* if(getInteger(&(label->shadowsizey)) == -1) return(-1); */
1746         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(-1);
1747         if(symbol == MS_NUMBER) {
1748           label->shadowsizey = (int) msyynumber;
1749         } else {
1750           if (label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].item != NULL)
1751             msFree(label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].item);
1752           label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].item = msStrdup(msyystring_buffer);
1753           label->numbindings++;
1754         }
1755         break;
1756       case(SIZE):
1757         if(label->bindings[MS_LABEL_BINDING_SIZE].item) {
1758           msFree(label->bindings[MS_LABEL_BINDING_SIZE].item);
1759           label->bindings[MS_LABEL_BINDING_SIZE].item = NULL;
1760           label->numbindings--;
1761         }
1762         if (label->exprBindings[MS_LABEL_BINDING_SIZE].string) {
1763           msFreeExpression(&label->exprBindings[MS_LABEL_BINDING_SIZE]);
1764           label->nexprbindings--;
1765         }
1766 
1767         if((symbol = getSymbol(8, MS_EXPRESSION,MS_NUMBER,MS_BINDING,MS_TINY,MS_SMALL,MS_MEDIUM,MS_LARGE,MS_GIANT)) == -1)
1768           return(-1);
1769 
1770         if(symbol == MS_NUMBER) {
1771           label->size = (double) msyynumber;
1772         } else if(symbol == MS_BINDING) {
1773           label->bindings[MS_LABEL_BINDING_SIZE].item = msStrdup(msyystring_buffer);
1774           label->numbindings++;
1775         } else if (symbol == MS_EXPRESSION) {
1776           msFree(label->exprBindings[MS_LABEL_BINDING_SIZE].string);
1777           label->exprBindings[MS_LABEL_BINDING_SIZE].string = msStrdup(msyystring_buffer);
1778           label->exprBindings[MS_LABEL_BINDING_SIZE].type = MS_EXPRESSION;
1779           label->nexprbindings++;
1780         } else
1781           label->size = symbol;
1782         break;
1783       case(STYLE):
1784         if(msGrowLabelStyles(label) == NULL)
1785           return(-1);
1786         initStyle(label->styles[label->numstyles]);
1787         if(loadStyle(label->styles[label->numstyles]) != MS_SUCCESS) return(-1);
1788         if(label->styles[label->numstyles]->_geomtransform.type == MS_GEOMTRANSFORM_NONE)
1789           label->styles[label->numstyles]->_geomtransform.type = MS_GEOMTRANSFORM_LABELPOINT; /* set a default, a marker? */
1790         label->numstyles++;
1791         break;
1792       case(TEXT):
1793         if(loadExpression(&(label->text)) == -1) return(-1); /* loadExpression() cleans up previously allocated expression */
1794         if(msyysource == MS_URL_TOKENS) {
1795           msSetError(MS_MISCERR, "URL-based TEXT configuration not supported for labels." , "loadLabel()");
1796           msFreeExpression(&(label->text));
1797           return(-1);
1798         }
1799         if((label->text.type != MS_STRING) && (label->text.type != MS_EXPRESSION)) {
1800           msSetError(MS_MISCERR, "Text expressions support constant or tagged replacement strings." , "loadLabel()");
1801           return(-1);
1802         }
1803         break;
1804       case(TYPE):
1805         if(getSymbol(2, MS_TRUETYPE,MS_BITMAP) == -1) return(-1); /* ignore TYPE */
1806         break;
1807       case(WRAP):
1808         if(getCharacter(&(label->wrap)) == -1) return(-1);
1809         break;
1810       default:
1811         if(strlen(msyystring_buffer) > 0) {
1812           msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadLabel()", msyystring_buffer, msyylineno);
1813           return(-1);
1814         } else {
1815           return(0); /* end of a string, not an error */
1816         }
1817     }
1818   } /* next token */
1819 }
1820 
msUpdateLabelFromString(labelObj * label,char * string,int url_string)1821 int msUpdateLabelFromString(labelObj *label, char *string, int url_string)
1822 {
1823   if(!label || !string) return MS_FAILURE;
1824 
1825   msAcquireLock( TLOCK_PARSER );
1826 
1827   if(url_string)
1828     msyystate = MS_TOKENIZE_URL_STRING;
1829   else
1830     msyystate = MS_TOKENIZE_STRING;
1831 
1832   msyystring = string;
1833   msyylex(); /* sets things up, but doesn't process any tokens */
1834 
1835   msyylineno = 1; /* start at line 1 */
1836 
1837   if(loadLabel(label) == -1) {
1838     msReleaseLock( TLOCK_PARSER );
1839     return MS_FAILURE; /* parse error */;
1840   }
1841   msReleaseLock( TLOCK_PARSER );
1842 
1843   msyylex_destroy();
1844   return MS_SUCCESS;
1845 }
1846 
writeLeader(FILE * stream,int indent,labelLeaderObj * leader)1847 static void writeLeader(FILE *stream, int indent, labelLeaderObj *leader)
1848 {
1849   int i;
1850   if(leader->maxdistance == 0 && leader->numstyles == 0) {
1851     return;
1852   }
1853   indent++;
1854   writeBlockBegin(stream, indent, "LEADER");
1855   writeNumber(stream, indent, "MAXDISTANCE", 0, leader->maxdistance);
1856   writeNumber(stream, indent, "GRIDSTEP", 5, leader->gridstep);
1857   for(i=0; i<leader->numstyles; i++)
1858     writeStyle(stream, indent, leader->styles[i]);
1859 
1860   writeBlockEnd(stream, indent, "LEADER");
1861 }
1862 
writeLabel(FILE * stream,int indent,labelObj * label)1863 static void writeLabel(FILE *stream, int indent, labelObj *label)
1864 {
1865   int i;
1866   colorObj c;
1867 
1868   if(label->size == -1) return; /* there is no default label anymore */
1869 
1870   indent++;
1871   writeBlockBegin(stream, indent, "LABEL");
1872 
1873   if(label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_ANGLE].item)
1874     writeAttributeBinding(stream, indent, "ANGLE", &(label->bindings[MS_LABEL_BINDING_ANGLE]));
1875   else writeNumberOrKeyword(stream, indent, "ANGLE", 0, label->angle, label->anglemode, 3, MS_FOLLOW, "FOLLOW", MS_AUTO, "AUTO", MS_AUTO2, "AUTO2");
1876 
1877   writeExpression(stream, indent, "EXPRESSION", &(label->expression));
1878 
1879   if(label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_FONT].item)
1880     writeAttributeBinding(stream, indent, "FONT", &(label->bindings[MS_LABEL_BINDING_FONT]));
1881   else writeString(stream, indent, "FONT", NULL, label->font);
1882 
1883   writeNumber(stream, indent, "MAXSIZE",  MS_MAXFONTSIZE, label->maxsize);
1884   writeNumber(stream, indent, "MINSIZE",  MS_MINFONTSIZE, label->minsize);
1885 
1886   if(label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_SIZE].item)
1887     writeAttributeBinding(stream, indent, "SIZE", &(label->bindings[MS_LABEL_BINDING_SIZE]));
1888   else writeNumber(stream, indent, "SIZE", -1, label->size);
1889 
1890   writeKeyword(stream, indent, "ALIGN", label->align, 3, MS_ALIGN_LEFT, "LEFT", MS_ALIGN_CENTER, "CENTER", MS_ALIGN_RIGHT, "RIGHT");
1891   writeNumber(stream, indent, "BUFFER", 0, label->buffer);
1892 
1893   if(label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_COLOR].item)
1894     writeAttributeBinding(stream, indent, "COLOR", &(label->bindings[MS_LABEL_BINDING_COLOR]));
1895   else {
1896     MS_INIT_COLOR(c,0,0,0,255);
1897     writeColor(stream, indent, "COLOR", &c, &(label->color));
1898   }
1899 
1900   writeString(stream, indent, "ENCODING", NULL, label->encoding);
1901   if(label->leader)
1902     writeLeader(stream,indent,label->leader);
1903   writeKeyword(stream, indent, "FORCE", label->force, 2, MS_TRUE, "TRUE", MS_LABEL_FORCE_GROUP, "GROUP");
1904   writeNumber(stream, indent, "MAXLENGTH", 0, label->maxlength);
1905   writeNumber(stream, indent, "MAXSCALEDENOM", -1, label->maxscaledenom);
1906   writeNumber(stream, indent, "MINDISTANCE", -1, label->mindistance);
1907   writeNumberOrKeyword(stream, indent, "MINFEATURESIZE", -1, label->minfeaturesize, 1, label->autominfeaturesize, MS_TRUE, "AUTO");
1908   writeNumber(stream, indent, "MINLENGTH", 0, label->minlength);
1909   writeNumber(stream, indent, "MINSCALEDENOM", -1, label->minscaledenom);
1910   writeDimension(stream, indent, "OFFSET",  label->offsetx, label->offsety, NULL, NULL);
1911 
1912   if(label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_OUTLINECOLOR].item)
1913     writeAttributeBinding(stream, indent, "OUTLINECOLOR", &(label->bindings[MS_LABEL_BINDING_OUTLINECOLOR]));
1914   else  writeColor(stream, indent, "OUTLINECOLOR", NULL, &(label->outlinecolor));
1915 
1916   writeNumber(stream, indent, "OUTLINEWIDTH", 1, label->outlinewidth);
1917   writeKeyword(stream, indent, "PARTIALS", label->partials, 1, MS_TRUE, "TRUE");
1918 
1919   if(label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_POSITION].item)
1920     writeAttributeBinding(stream, indent, "POSITION", &(label->bindings[MS_LABEL_BINDING_POSITION]));
1921   else writeKeyword(stream, indent, "POSITION", label->position, 10, MS_UL, "UL", MS_UC, "UC", MS_UR, "UR", MS_CL, "CL", MS_CC, "CC", MS_CR, "CR", MS_LL, "LL", MS_LC, "LC", MS_LR, "LR", MS_AUTO, "AUTO");
1922 
1923   if(label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_PRIORITY].item)
1924     writeAttributeBinding(stream, indent, "PRIORITY", &(label->bindings[MS_LABEL_BINDING_PRIORITY]));
1925   else writeNumber(stream, indent, "PRIORITY", MS_DEFAULT_LABEL_PRIORITY, label->priority);
1926 
1927   writeNumber(stream, indent, "REPEATDISTANCE", 0, label->repeatdistance);
1928   writeColor(stream, indent, "SHADOWCOLOR", NULL, &(label->shadowcolor));
1929   writeDimension(stream, indent, "SHADOWSIZE", label->shadowsizex, label->shadowsizey, label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].item, label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].item);
1930 
1931   writeNumber(stream, indent, "MAXOVERLAPANGLE", 22.5, label->maxoverlapangle);
1932   for(i=0; i<label->numstyles; i++)
1933     writeStyle(stream, indent, label->styles[i]);
1934 
1935   writeExpression(stream, indent, "TEXT", &(label->text));
1936 
1937   writeCharacter(stream, indent, "WRAP", '\0', label->wrap);
1938   writeBlockEnd(stream, indent, "LABEL");
1939 }
1940 
msWriteLabelToString(labelObj * label)1941 char* msWriteLabelToString(labelObj *label)
1942 {
1943   msIOContext  context;
1944   msIOBuffer buffer;
1945 
1946   context.label = NULL;
1947   context.write_channel = MS_TRUE;
1948   context.readWriteFunc = msIO_bufferWrite;
1949   context.cbData = &buffer;
1950   buffer.data = NULL;
1951   buffer.data_len = 0;
1952   buffer.data_offset = 0;
1953 
1954   msIO_installHandlers( NULL, &context, NULL );
1955 
1956   writeLabel(stdout, -1, label);
1957   msIO_bufferWrite( &buffer, "", 1 );
1958 
1959   msIO_installHandlers( NULL, NULL, NULL );
1960 
1961   return (char*)buffer.data;
1962 }
1963 
msInitExpression(expressionObj * exp)1964 void msInitExpression(expressionObj *exp)
1965 {
1966   memset(exp, 0, sizeof(*exp));
1967   exp->type = MS_STRING;
1968 }
1969 
msFreeExpressionTokens(expressionObj * exp)1970 void msFreeExpressionTokens(expressionObj *exp)
1971 {
1972   tokenListNodeObjPtr node = NULL;
1973   tokenListNodeObjPtr nextNode = NULL;
1974 
1975   if(!exp) return;
1976 
1977   if(exp->tokens) {
1978     node = exp->tokens;
1979     while (node != NULL) {
1980       nextNode = node->next;
1981 
1982       msFree(node->tokensrc); /* not set very often */
1983 
1984       switch(node->token) {
1985         case MS_TOKEN_BINDING_DOUBLE:
1986         case MS_TOKEN_BINDING_INTEGER:
1987         case MS_TOKEN_BINDING_STRING:
1988         case MS_TOKEN_BINDING_TIME:
1989           msFree(node->tokenval.bindval.item);
1990           break;
1991         case MS_TOKEN_LITERAL_TIME:
1992           /* anything to do? */
1993           break;
1994         case MS_TOKEN_LITERAL_STRING:
1995           msFree(node->tokenval.strval);
1996           break;
1997         case MS_TOKEN_LITERAL_SHAPE:
1998           msFreeShape(node->tokenval.shpval);
1999           free(node->tokenval.shpval);
2000           break;
2001       }
2002 
2003       msFree(node);
2004       node = nextNode;
2005     }
2006     exp->tokens = exp->curtoken = NULL;
2007   }
2008 }
2009 
msFreeExpression(expressionObj * exp)2010 void msFreeExpression(expressionObj *exp)
2011 {
2012   if(!exp) return;
2013   msFree(exp->string);
2014   msFree(exp->native_string);
2015   if((exp->type == MS_REGEX) && exp->compiled) ms_regfree(&(exp->regex));
2016   msFreeExpressionTokens(exp);
2017   msInitExpression(exp); /* re-initialize */
2018 }
2019 
loadExpression(expressionObj * exp)2020 int loadExpression(expressionObj *exp)
2021 {
2022   /* TODO: should we call msFreeExpression if exp->string != NULL? We do some checking to avoid a leak but is it enough... */
2023 
2024   msyystring_icase = MS_TRUE;
2025   if((exp->type = getSymbol(6, MS_STRING,MS_EXPRESSION,MS_REGEX,MS_ISTRING,MS_IREGEX,MS_LIST)) == -1) return(-1);
2026   if (exp->string != NULL) {
2027     msFree(exp->string);
2028     msFree(exp->native_string);
2029   }
2030   exp->string = msStrdup(msyystring_buffer);
2031   exp->native_string = NULL;
2032 
2033   if(exp->type == MS_ISTRING) {
2034     exp->flags = exp->flags | MS_EXP_INSENSITIVE;
2035     exp->type = MS_STRING;
2036   } else if(exp->type == MS_IREGEX) {
2037     exp->flags = exp->flags | MS_EXP_INSENSITIVE;
2038     exp->type = MS_REGEX;
2039   }
2040 
2041   return(0);
2042 }
2043 
2044 /* ---------------------------------------------------------------------------
2045    msLoadExpressionString and loadExpressionString
2046 
2047    msLoadExpressionString wraps call to loadExpressionString with mutex
2048    acquisition and release.  This function should be used everywhere outside
2049    the mapfile loading phase of an application.  loadExpressionString does
2050    not check for a mutex!  It should be used only within code that has
2051    properly acquired a mutex.
2052 
2053    See bug 339 for more details -- SG.
2054    ------------------------------------------------------------------------ */
2055 
msLoadExpressionString(expressionObj * exp,char * value)2056 int msLoadExpressionString(expressionObj *exp, char *value)
2057 {
2058   int retval = MS_FAILURE;
2059 
2060   msAcquireLock( TLOCK_PARSER );
2061   retval = loadExpressionString( exp, value );
2062   msReleaseLock( TLOCK_PARSER );
2063 
2064   return retval;
2065 }
2066 
loadExpressionString(expressionObj * exp,char * value)2067 int loadExpressionString(expressionObj *exp, char *value)
2068 {
2069   msyystate = MS_TOKENIZE_STRING;
2070   msyystring = value;
2071   msyylex(); /* sets things up but processes no tokens */
2072 
2073   msFreeExpression(exp); /* we're totally replacing the old expression so free (which re-inits) to start over */
2074 
2075   msyystring_icase = MS_TRUE;
2076   if((exp->type = getSymbol2(5, MS_EXPRESSION,MS_REGEX,MS_IREGEX,MS_ISTRING,MS_LIST)) != -1) {
2077     exp->string = msStrdup(msyystring_buffer);
2078 
2079     if(exp->type == MS_ISTRING) {
2080       exp->type = MS_STRING;
2081       exp->flags = exp->flags | MS_EXP_INSENSITIVE;
2082     } else if(exp->type == MS_IREGEX) {
2083       exp->type = MS_REGEX;
2084       exp->flags = exp->flags | MS_EXP_INSENSITIVE;
2085     }
2086   } else {
2087     /* failure above is not an error since we'll consider anything not matching (like an unquoted number) as a STRING) */
2088     exp->type = MS_STRING;
2089     if((strlen(value) - strlen(msyystring_buffer)) == 2)
2090       exp->string = msStrdup(msyystring_buffer); /* value was quoted */
2091     else
2092       exp->string = msStrdup(value); /* use the whole value */
2093   }
2094 
2095   return(0);
2096 }
2097 
2098 /* msGetExpressionString()
2099  *
2100  * Returns the string representation of this expression, including delimiters
2101  * and any flags (e.g. i = case-insensitive).
2102  *
2103  * Returns a newly allocated buffer that should be freed by the caller or NULL.
2104  */
msGetExpressionString(expressionObj * exp)2105 char *msGetExpressionString(expressionObj *exp)
2106 {
2107   if(exp->string) {
2108     char *exprstring;
2109     size_t buffer_size;
2110     const char *case_insensitive = "";
2111 
2112     if(exp->flags & MS_EXP_INSENSITIVE)
2113       case_insensitive = "i";
2114 
2115     /* Alloc buffer big enough for string + 2 delimiters + 'i' + \0 */
2116     buffer_size = strlen(exp->string)+4;
2117     exprstring = (char*)msSmallMalloc(buffer_size);
2118 
2119     switch(exp->type) {
2120       case(MS_REGEX):
2121         snprintf(exprstring, buffer_size, "/%s/%s", exp->string, case_insensitive);
2122         return exprstring;
2123       case(MS_STRING):
2124         snprintf(exprstring, buffer_size, "\"%s\"%s", exp->string, case_insensitive);
2125         return exprstring;
2126       case(MS_EXPRESSION):
2127         snprintf(exprstring, buffer_size, "(%s)", exp->string);
2128         return exprstring;
2129       case(MS_LIST):
2130         snprintf(exprstring, buffer_size, "{%s}", exp->string);
2131         return exprstring;
2132       default:
2133         /* We should never get to here really! */
2134         free(exprstring);
2135         return NULL;
2136     }
2137   }
2138   return NULL;
2139 }
2140 
writeExpression(FILE * stream,int indent,const char * name,expressionObj * exp)2141 static void writeExpression(FILE *stream, int indent, const char *name, expressionObj *exp)
2142 {
2143   if(!exp || !exp->string) return;
2144 
2145   writeIndent(stream, ++indent);
2146   switch(exp->type) {
2147     case(MS_LIST):
2148       fprintf(stream, "%s {%s}", name, exp->string);
2149       break;
2150     case(MS_REGEX):
2151       msIO_fprintf(stream, "%s /%s/", name, exp->string);
2152       break;
2153     case(MS_STRING):
2154       msIO_fprintf(stream, "%s ", name);
2155       writeStringElement(stream, exp->string);
2156       break;
2157     case(MS_EXPRESSION):
2158       msIO_fprintf(stream, "%s (%s)", name, exp->string);
2159       break;
2160   }
2161   if((exp->type == MS_STRING || exp->type == MS_REGEX) && (exp->flags & MS_EXP_INSENSITIVE))
2162     msIO_fprintf(stream, "i");
2163   writeLineFeed(stream);
2164 }
2165 
loadHashTable(hashTableObj * ptable)2166 int loadHashTable(hashTableObj *ptable)
2167 {
2168   char *key=NULL, *data=NULL;
2169   assert(ptable);
2170 
2171   for(;;) {
2172     switch(msyylex()) {
2173       case(EOF):
2174         msSetError(MS_EOFERR, NULL, "loadHashTable()");
2175         return(MS_FAILURE);
2176       case(END):
2177         return(MS_SUCCESS);
2178       case(MS_STRING):
2179         key = msStrdup(msyystring_buffer); /* the key is *always* a string */
2180         if(getString(&data) == MS_FAILURE) return(MS_FAILURE);
2181         msInsertHashTable(ptable, key, data);
2182 
2183         free(key);
2184         free(data);
2185         data=NULL;
2186         break;
2187       default:
2188         msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadHashTable()", msyystring_buffer, msyylineno );
2189         return(MS_FAILURE);
2190     }
2191   }
2192 
2193   return(MS_SUCCESS);
2194 }
2195 
writeHashTable(FILE * stream,int indent,const char * title,hashTableObj * table)2196 static void writeHashTable(FILE *stream, int indent, const char *title, hashTableObj *table)
2197 {
2198   struct hashObj *tp;
2199   int i;
2200 
2201   if(!table) return;
2202   if(msHashIsEmpty(table)) return;
2203 
2204   indent++;
2205   writeBlockBegin(stream, indent, title);
2206   for (i=0; i<MS_HASHSIZE; i++) {
2207     if (table->items[i] != NULL) {
2208       for (tp=table->items[i]; tp!=NULL; tp=tp->next)
2209         writeNameValuePair(stream, indent, tp->key, tp->data);
2210     }
2211   }
2212   writeBlockEnd(stream, indent, title);
2213 }
2214 
writeHashTableInline(FILE * stream,int indent,char * name,hashTableObj * table)2215 static void writeHashTableInline(FILE *stream, int indent, char *name, hashTableObj* table)
2216 {
2217   struct hashObj *tp = NULL;
2218   int i;
2219 
2220   if(!table) return;
2221   if(msHashIsEmpty(table)) return;
2222 
2223   ++indent;
2224   for (i=0; i<MS_HASHSIZE; ++i) {
2225     if (table->items[i] != NULL) {
2226       for (tp=table->items[i]; tp!=NULL; tp=tp->next) {
2227         writeIndent(stream, indent);
2228         msIO_fprintf(stream, "%s ", name);
2229         writeStringElement(stream, tp->key);
2230         msIO_fprintf(stream," ");
2231         writeStringElement(stream, tp->data);
2232         writeLineFeed(stream);
2233       }
2234     }
2235   }
2236 }
2237 
2238 /*
2239 ** Initialize, load and free a cluster object
2240 */
initCluster(clusterObj * cluster)2241 void initCluster(clusterObj *cluster)
2242 {
2243   cluster->maxdistance = 10;
2244   cluster->buffer = 0;
2245   cluster->region = NULL;
2246   msInitExpression(&(cluster->group));
2247   msInitExpression(&(cluster->filter));
2248 }
2249 
freeCluster(clusterObj * cluster)2250 void freeCluster(clusterObj *cluster)
2251 {
2252   msFree(cluster->region);
2253   msFreeExpression(&(cluster->group));
2254   msFreeExpression(&(cluster->filter));
2255 }
2256 
loadCluster(clusterObj * cluster)2257 int loadCluster(clusterObj *cluster)
2258 {
2259   for(;;) {
2260     switch(msyylex()) {
2261       case(CLUSTER):
2262         break; /* for string loads */
2263       case(MAXDISTANCE):
2264         if(getDouble(&(cluster->maxdistance)) == -1) return(-1);
2265         break;
2266       case(BUFFER):
2267         if(getDouble(&(cluster->buffer)) == -1) return(-1);
2268         break;
2269       case(REGION):
2270         if(getString(&cluster->region) == MS_FAILURE) return(-1);
2271         break;
2272       case(END):
2273         return(0);
2274         break;
2275       case(GROUP):
2276         if(loadExpression(&(cluster->group)) == -1) return(-1);
2277         break;
2278       case(FILTER):
2279         if(loadExpression(&(cluster->filter)) == -1) return(-1);
2280         break;
2281       default:
2282         if(strlen(msyystring_buffer) > 0) {
2283           msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadCluster()", msyystring_buffer, msyylineno);
2284           return(-1);
2285         } else {
2286           return(0); /* end of a string, not an error */
2287         }
2288 
2289     }
2290   }
2291   return(MS_SUCCESS);
2292 }
2293 
msUpdateClusterFromString(clusterObj * cluster,char * string)2294 int msUpdateClusterFromString(clusterObj *cluster, char *string)
2295 {
2296   if(!cluster || !string) return MS_FAILURE;
2297 
2298   msAcquireLock( TLOCK_PARSER );
2299 
2300   msyystate = MS_TOKENIZE_STRING;
2301   msyystring = string;
2302   msyylex(); /* sets things up, but doesn't process any tokens */
2303 
2304   msyylineno = 1; /* start at line 1 */
2305 
2306   if(loadCluster(cluster) == -1) {
2307     msReleaseLock( TLOCK_PARSER );
2308     return MS_FAILURE; /* parse error */;
2309   }
2310   msReleaseLock( TLOCK_PARSER );
2311 
2312   msyylex_destroy();
2313   return MS_SUCCESS;
2314 }
2315 
writeCluster(FILE * stream,int indent,clusterObj * cluster)2316 static void writeCluster(FILE *stream, int indent, clusterObj *cluster)
2317 {
2318 
2319   if (cluster->maxdistance == 10 &&
2320       cluster->buffer == 0.0 &&
2321       cluster->region == NULL &&
2322       cluster->group.string == NULL &&
2323       cluster->filter.string == NULL)
2324     return;  /* Nothing to write */
2325 
2326   indent++;
2327   writeBlockBegin(stream, indent, "CLUSTER");
2328   writeNumber(stream, indent, "MAXDISTANCE", 10, cluster->maxdistance);
2329   writeNumber(stream, indent, "BUFFER", 0, cluster->buffer);
2330   writeString(stream, indent, "REGION", NULL, cluster->region);
2331   writeExpression(stream, indent, "GROUP", &(cluster->group));
2332   writeExpression(stream, indent, "FILTER", &(cluster->filter));
2333   writeBlockEnd(stream, indent, "CLUSTER");
2334 }
2335 
msWriteClusterToString(clusterObj * cluster)2336 char* msWriteClusterToString(clusterObj *cluster)
2337 {
2338   msIOContext  context;
2339   msIOBuffer buffer;
2340 
2341   context.label = NULL;
2342   context.write_channel = MS_TRUE;
2343   context.readWriteFunc = msIO_bufferWrite;
2344   context.cbData = &buffer;
2345   buffer.data = NULL;
2346   buffer.data_len = 0;
2347   buffer.data_offset = 0;
2348 
2349   msIO_installHandlers( NULL, &context, NULL );
2350 
2351   writeCluster(stdout, -1, cluster);
2352   msIO_bufferWrite( &buffer, "", 1 );
2353 
2354   msIO_installHandlers( NULL, NULL, NULL );
2355 
2356   return (char*)buffer.data;
2357 }
2358 
2359 /*
2360 ** Initialize, load and free a single style
2361 */
initStyle(styleObj * style)2362 int initStyle(styleObj *style)
2363 {
2364   int i;
2365   MS_REFCNT_INIT(style);
2366   MS_INIT_COLOR(style->color, -1,-1,-1,255); /* must explictly set colors */
2367   MS_INIT_COLOR(style->backgroundcolor, -1,-1,-1,255);
2368   MS_INIT_COLOR(style->outlinecolor, -1,-1,-1,255);
2369   /* New Color Range fields*/
2370   MS_INIT_COLOR(style->mincolor, -1,-1,-1,255);
2371   MS_INIT_COLOR(style->maxcolor, -1,-1,-1,255);
2372   style->minvalue = 0.0;
2373   style->maxvalue = 1.0;
2374   style->rangeitem = NULL;
2375   /* End Color Range fields*/
2376   style->symbol = 0; /* there is always a default symbol*/
2377   style->symbolname = NULL;
2378   style->size = -1; /* in SIZEUNITS (layerObj) */
2379   style->minsize = MS_MINSYMBOLSIZE;
2380   style->maxsize = MS_MAXSYMBOLSIZE;
2381   style->width = 1; /* in pixels */
2382   style->outlinewidth = 0; /* in pixels */
2383   style->minwidth = MS_MINSYMBOLWIDTH;
2384   style->maxwidth = MS_MAXSYMBOLWIDTH;
2385   style->minscaledenom=style->maxscaledenom = -1.0;
2386   style->offsetx = style->offsety = 0; /* no offset */
2387   style->polaroffsetpixel = style->polaroffsetangle = 0; /* no polar offset */
2388   style->angle = 0;
2389   style->autoangle= MS_FALSE;
2390   style->opacity = 100; /* fully opaque */
2391 
2392   msInitExpression(&(style->_geomtransform));
2393   style->_geomtransform.type = MS_GEOMTRANSFORM_NONE;
2394 
2395   style->patternlength = 0; /* solid line */
2396   style->gap = 0;
2397   style->initialgap = -1;
2398   style->position = MS_CC;
2399   style->linecap = MS_CJC_DEFAULT_CAPS;
2400   style->linejoin = MS_CJC_DEFAULT_JOINS;
2401   style->linejoinmaxsize = MS_CJC_DEFAULT_JOIN_MAXSIZE;
2402 
2403   style->numbindings = 0;
2404   style->nexprbindings = 0;
2405   for(i=0; i<MS_STYLE_BINDING_LENGTH; i++) {
2406     style->bindings[i].item = NULL;
2407     style->bindings[i].index = -1;
2408     msInitExpression(&(style->exprBindings[i]));
2409   }
2410 
2411   return MS_SUCCESS;
2412 }
2413 
loadStyle(styleObj * style)2414 int loadStyle(styleObj *style)
2415 {
2416   int symbol;
2417 
2418   for(;;) {
2419     switch(msyylex()) {
2420         /* New Color Range fields*/
2421       case (COLORRANGE):
2422         /*These are both in one line now*/
2423         if(loadColor(&(style->mincolor), NULL) != MS_SUCCESS) return(MS_FAILURE);
2424         if(loadColor(&(style->maxcolor), NULL) != MS_SUCCESS) return(MS_FAILURE);
2425         break;
2426       case(DATARANGE):
2427         /*These are both in one line now*/
2428         if(getDouble(&(style->minvalue)) == -1) return(-1);
2429         if(getDouble(&(style->maxvalue)) == -1) return(-1);
2430         break;
2431       case(RANGEITEM):
2432         if(getString(&style->rangeitem) == MS_FAILURE) return(-1);
2433         break;
2434         /* End Range fields*/
2435       case(ANGLE):
2436         if((symbol = getSymbol(3, MS_NUMBER,MS_BINDING,MS_AUTO)) == -1) return(MS_FAILURE);
2437 
2438         if(symbol == MS_NUMBER)
2439           style->angle = (double) msyynumber;
2440         else if(symbol==MS_BINDING) {
2441           if (style->bindings[MS_STYLE_BINDING_ANGLE].item != NULL)
2442             msFree(style->bindings[MS_STYLE_BINDING_ANGLE].item);
2443           style->bindings[MS_STYLE_BINDING_ANGLE].item = msStrdup(msyystring_buffer);
2444           style->numbindings++;
2445         } else {
2446           style->autoangle=MS_TRUE;
2447         }
2448         break;
2449       case(ANTIALIAS): /*ignore*/
2450         msyylex();
2451         break;
2452       case(BACKGROUNDCOLOR):
2453         if(loadColor(&(style->backgroundcolor), NULL) != MS_SUCCESS) return(MS_FAILURE);
2454         break;
2455       case(COLOR):
2456         if(loadColor(&(style->color), &(style->bindings[MS_STYLE_BINDING_COLOR])) != MS_SUCCESS) return(MS_FAILURE);
2457         if(style->bindings[MS_STYLE_BINDING_COLOR].item) style->numbindings++;
2458         break;
2459       case(EOF):
2460         msSetError(MS_EOFERR, NULL, "loadStyle()");
2461         return(MS_FAILURE); /* missing END (probably) */
2462       case(END): {
2463         int alpha;
2464 
2465         /* apply opacity as the alpha channel color(s) */
2466         if(style->opacity < 100) {
2467           alpha = MS_NINT(style->opacity*2.55);
2468 
2469           style->color.alpha = alpha;
2470           style->outlinecolor.alpha = alpha;
2471           style->backgroundcolor.alpha = alpha;
2472 
2473           style->mincolor.alpha = alpha;
2474           style->maxcolor.alpha = alpha;
2475         }
2476 
2477         return(MS_SUCCESS);
2478       }
2479       break;
2480       case(GAP):
2481         if((getDouble(&style->gap)) == -1) return(MS_FAILURE);
2482         break;
2483       case(INITIALGAP):
2484         if((getDouble(&style->initialgap)) == -1) return(MS_FAILURE);
2485         if(style->initialgap < 0) {
2486           msSetError(MS_MISCERR, "INITIALGAP requires a positive values", "loadStyle()");
2487           return(MS_FAILURE);
2488         }
2489         break;
2490       case(MAXSCALEDENOM):
2491         if(getDouble(&(style->maxscaledenom)) == -1) return(MS_FAILURE);
2492         break;
2493       case(MINSCALEDENOM):
2494         if(getDouble(&(style->minscaledenom)) == -1) return(MS_FAILURE);
2495         break;
2496       case(GEOMTRANSFORM): {
2497         int s;
2498         if((s = getSymbol(2, MS_STRING, MS_EXPRESSION)) == -1) return(MS_FAILURE);
2499         if(s == MS_STRING)
2500           msStyleSetGeomTransform(style, msyystring_buffer);
2501         else {
2502           /* handle expression case here for the moment */
2503           msFree(style->_geomtransform.string);
2504           style->_geomtransform.string = msStrdup(msyystring_buffer);
2505           style->_geomtransform.type = MS_GEOMTRANSFORM_EXPRESSION;
2506         }
2507       }
2508       break;
2509       case(LINECAP):
2510         if((style->linecap = getSymbol(4,MS_CJC_BUTT, MS_CJC_ROUND, MS_CJC_SQUARE, MS_CJC_TRIANGLE)) == -1) return(MS_FAILURE);
2511         break;
2512       case(LINEJOIN):
2513         if((style->linejoin = getSymbol(4,MS_CJC_NONE, MS_CJC_ROUND, MS_CJC_MITER, MS_CJC_BEVEL)) == -1) return(MS_FAILURE);
2514         break;
2515       case(LINEJOINMAXSIZE):
2516         if((getDouble(&style->linejoinmaxsize)) == -1) return(MS_FAILURE);
2517         break;
2518       case(MAXSIZE):
2519         if(getDouble(&(style->maxsize)) == -1) return(MS_FAILURE);
2520         break;
2521       case(MINSIZE):
2522         if(getDouble(&(style->minsize)) == -1) return(MS_FAILURE);
2523         break;
2524       case(MAXWIDTH):
2525         if(getDouble(&(style->maxwidth)) == -1) return(MS_FAILURE);
2526         break;
2527       case(MINWIDTH):
2528         if(getDouble(&(style->minwidth)) == -1) return(MS_FAILURE);
2529         break;
2530       case(OFFSET):
2531         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(MS_FAILURE);
2532         if(symbol == MS_NUMBER)
2533           style->offsetx = (double) msyynumber;
2534         else {
2535           if (style->bindings[MS_STYLE_BINDING_OFFSET_X].item != NULL)
2536             msFree(style->bindings[MS_STYLE_BINDING_OFFSET_X].item);
2537           style->bindings[MS_STYLE_BINDING_OFFSET_X].item = msStrdup(msyystring_buffer);
2538           style->numbindings++;
2539         }
2540 
2541         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(MS_FAILURE);
2542         if(symbol == MS_NUMBER)
2543           style->offsety = (double) msyynumber;
2544         else {
2545           if (style->bindings[MS_STYLE_BINDING_OFFSET_Y].item != NULL)
2546             msFree(style->bindings[MS_STYLE_BINDING_OFFSET_Y].item);
2547           style->bindings[MS_STYLE_BINDING_OFFSET_Y].item = msStrdup(msyystring_buffer);
2548           style->numbindings++;
2549         }
2550         break;
2551       case(OPACITY):
2552         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(MS_FAILURE);
2553         if(symbol == MS_NUMBER)
2554           style->opacity = MS_MAX(MS_MIN((int) msyynumber, 100), 0); /* force opacity to between 0 and 100 */
2555         else {
2556           if (style->bindings[MS_STYLE_BINDING_OPACITY].item != NULL)
2557             msFree(style->bindings[MS_STYLE_BINDING_OPACITY].item);
2558           style->bindings[MS_STYLE_BINDING_OPACITY].item = msStrdup(msyystring_buffer);
2559           style->numbindings++;
2560         }
2561         break;
2562       case(OUTLINECOLOR):
2563         if(loadColor(&(style->outlinecolor), &(style->bindings[MS_STYLE_BINDING_OUTLINECOLOR])) != MS_SUCCESS) return(MS_FAILURE);
2564         if(style->bindings[MS_STYLE_BINDING_OUTLINECOLOR].item) style->numbindings++;
2565         break;
2566       case(PATTERN): {
2567         int done = MS_FALSE;
2568         for(;;) { /* read till the next END */
2569           switch(msyylex()) {
2570             case(END):
2571               if(style->patternlength < 2) {
2572                 msSetError(MS_SYMERR, "Not enough pattern elements. A minimum of 2 are required", "loadStyle()");
2573                 return(MS_FAILURE);
2574               }
2575               done = MS_TRUE;
2576               break;
2577             case(MS_NUMBER): /* read the pattern values */
2578               if(style->patternlength == MS_MAXPATTERNLENGTH) {
2579                 msSetError(MS_SYMERR, "Pattern too long.", "loadStyle()");
2580                 return(-1);
2581               }
2582               style->pattern[style->patternlength] = atof(msyystring_buffer);
2583               style->patternlength++;
2584               break;
2585             default:
2586               msSetError(MS_TYPEERR, "Parsing error near (%s):(line %d)", "loadStyle()", msyystring_buffer, msyylineno);
2587               return(-1);
2588           }
2589           if(done == MS_TRUE)
2590             break;
2591         }
2592         break;
2593       }
2594       case(POSITION):
2595         /* if((s->position = getSymbol(3, MS_UC,MS_CC,MS_LC)) == -1)  */
2596         /* return(-1); */
2597         if((style->position = getSymbol(9, MS_UL,MS_UC,MS_UR,MS_CL,MS_CC,MS_CR,MS_LL,MS_LC,MS_LR)) == -1)
2598           return(-1);
2599         break;
2600       case(OUTLINEWIDTH):
2601         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(MS_FAILURE);
2602         if(symbol == MS_NUMBER) {
2603           style->outlinewidth = (double) msyynumber;
2604           if(style->outlinewidth < 0) {
2605             msSetError(MS_MISCERR, "Invalid OUTLINEWIDTH, must be greater than 0" , "loadStyle()");
2606             return(MS_FAILURE);
2607           }
2608         } else {
2609           if (style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].item != NULL)
2610             msFree(style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].item);
2611           style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].item = msStrdup(msyystring_buffer);
2612           style->numbindings++;
2613         }
2614         break;
2615       case(SIZE):
2616         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(MS_FAILURE);
2617         if(symbol == MS_NUMBER)
2618           style->size = (double) msyynumber;
2619         else {
2620           if (style->bindings[MS_STYLE_BINDING_SIZE].item != NULL)
2621             msFree(style->bindings[MS_STYLE_BINDING_SIZE].item);
2622           style->bindings[MS_STYLE_BINDING_SIZE].item = msStrdup(msyystring_buffer);
2623           style->numbindings++;
2624         }
2625         break;
2626       case(STYLE):
2627         break; /* for string loads */
2628       case(SYMBOL):
2629         if((symbol = getSymbol(3, MS_NUMBER,MS_STRING,MS_BINDING)) == -1) return(MS_FAILURE);
2630         if(symbol == MS_NUMBER) {
2631           if (style->symbolname != NULL) {
2632             msFree(style->symbolname);
2633             style->symbolname = NULL;
2634           }
2635           style->symbol = (int) msyynumber;
2636         } else if(symbol == MS_STRING) {
2637           if (style->symbolname != NULL)
2638             msFree(style->symbolname);
2639           style->symbolname = msStrdup(msyystring_buffer);
2640         } else {
2641           if (style->bindings[MS_STYLE_BINDING_SYMBOL].item != NULL)
2642             msFree(style->bindings[MS_STYLE_BINDING_SYMBOL].item);
2643           style->bindings[MS_STYLE_BINDING_SYMBOL].item = msStrdup(msyystring_buffer);
2644           style->numbindings++;
2645         }
2646         break;
2647       case(WIDTH):
2648         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(MS_FAILURE);
2649         if(symbol == MS_NUMBER)
2650           style->width = (double) msyynumber;
2651         else {
2652           if (style->bindings[MS_STYLE_BINDING_WIDTH].item != NULL)
2653             msFree(style->bindings[MS_STYLE_BINDING_WIDTH].item);
2654           style->bindings[MS_STYLE_BINDING_WIDTH].item = msStrdup(msyystring_buffer);
2655           style->numbindings++;
2656         }
2657         break;
2658       case(POLAROFFSET):
2659         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(MS_FAILURE);
2660         if(symbol == MS_NUMBER)
2661           style->polaroffsetpixel = (double) msyynumber;
2662         else {
2663           if (style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item != NULL)
2664             msFree(style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item);
2665           style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item = msStrdup(msyystring_buffer);
2666           style->numbindings++;
2667         }
2668 
2669         if((symbol = getSymbol(2, MS_NUMBER,MS_BINDING)) == -1) return(MS_FAILURE);
2670         if(symbol == MS_NUMBER)
2671           style->polaroffsetangle = (double) msyynumber;
2672         else {
2673           if (style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item != NULL)
2674             msFree(style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item);
2675           style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item = msStrdup(msyystring_buffer);
2676           style->numbindings++;
2677         }
2678         break;
2679       default:
2680         if(strlen(msyystring_buffer) > 0) {
2681           msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadStyle()", msyystring_buffer, msyylineno);
2682           return(MS_FAILURE);
2683         } else {
2684           return(MS_SUCCESS); /* end of a string, not an error */
2685         }
2686     }
2687   }
2688 }
2689 
msUpdateStyleFromString(styleObj * style,char * string,int url_string)2690 int msUpdateStyleFromString(styleObj *style, char *string, int url_string)
2691 {
2692   if(!style || !string) return MS_FAILURE;
2693 
2694   msAcquireLock( TLOCK_PARSER );
2695 
2696   if(url_string)
2697     msyystate = MS_TOKENIZE_URL_STRING;
2698   else
2699     msyystate = MS_TOKENIZE_STRING;
2700   msyystring = string;
2701   msyylex(); /* sets things up, but doesn't process any tokens */
2702 
2703   msyylineno = 1; /* start at line 1 */
2704 
2705   if(loadStyle(style) == -1) {
2706     msReleaseLock( TLOCK_PARSER );
2707     return MS_FAILURE; /* parse error */;
2708   }
2709   msReleaseLock( TLOCK_PARSER );
2710 
2711   msyylex_destroy();
2712   return MS_SUCCESS;
2713 }
2714 
freeStyle(styleObj * style)2715 int freeStyle(styleObj *style)
2716 {
2717   int i;
2718 
2719   if( MS_REFCNT_DECR_IS_NOT_ZERO(style) ) {
2720     return MS_FAILURE;
2721   }
2722 
2723   msFree(style->symbolname);
2724   msFreeExpression(&style->_geomtransform);
2725   msFree(style->rangeitem);
2726 
2727   for(i=0; i<MS_STYLE_BINDING_LENGTH; i++) {
2728     msFree(style->bindings[i].item);
2729     msFreeExpression(&(style->exprBindings[i]));
2730   }
2731 
2732   return MS_SUCCESS;
2733 }
2734 
writeStyle(FILE * stream,int indent,styleObj * style)2735 void writeStyle(FILE *stream, int indent, styleObj *style)
2736 {
2737 
2738   indent++;
2739   writeBlockBegin(stream, indent, "STYLE");
2740 
2741   if(style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_ANGLE].item)
2742     writeAttributeBinding(stream, indent, "ANGLE", &(style->bindings[MS_STYLE_BINDING_ANGLE]));
2743   else writeNumberOrKeyword(stream, indent, "ANGLE", 0, style->angle, style->autoangle, 1, MS_TRUE, "AUTO");
2744 
2745   writeColor(stream, indent, "BACKGROUNDCOLOR", NULL, &(style->backgroundcolor));
2746 
2747   if(style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_COLOR].item)
2748     writeAttributeBinding(stream, indent, "COLOR", &(style->bindings[MS_STYLE_BINDING_COLOR]));
2749   else writeColor(stream, indent, "COLOR", NULL, &(style->color));
2750 
2751   writeNumber(stream, indent, "GAP", 0, style->gap);
2752   writeNumber(stream, indent, "INITIALGAP", -1, style->initialgap);
2753 
2754   if(style->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) {
2755     writeIndent(stream, indent + 1);
2756     msIO_fprintf(stream, "GEOMTRANSFORM (%s)\n", style->_geomtransform.string);
2757   }
2758   else if(style->_geomtransform.type != MS_GEOMTRANSFORM_NONE) {
2759     writeKeyword(stream, indent, "GEOMTRANSFORM", style->_geomtransform.type, 8,
2760                  MS_GEOMTRANSFORM_BBOX, "\"bbox\"",
2761                  MS_GEOMTRANSFORM_END, "\"end\"",
2762                  MS_GEOMTRANSFORM_LABELPOINT, "\"labelpnt\"",
2763                  MS_GEOMTRANSFORM_LABELPOLY, "\"labelpoly\"",
2764                  MS_GEOMTRANSFORM_LABELCENTER, "\"labelcenter\"",
2765                  MS_GEOMTRANSFORM_START, "\"start\"",
2766                  MS_GEOMTRANSFORM_VERTICES, "\"vertices\"",
2767                  MS_GEOMTRANSFORM_CENTROID, "\"centroid\""
2768                 );
2769   }
2770 
2771   if(style->linecap != MS_CJC_DEFAULT_CAPS) {
2772     writeKeyword(stream,indent,"LINECAP",(int)style->linecap,5,
2773                  MS_CJC_NONE,"NONE",
2774                  MS_CJC_ROUND, "ROUND",
2775                  MS_CJC_SQUARE, "SQUARE",
2776                  MS_CJC_BUTT, "BUTT",
2777                  MS_CJC_TRIANGLE, "TRIANGLE");
2778   }
2779   if(style->linejoin != MS_CJC_DEFAULT_JOINS) {
2780     writeKeyword(stream,indent,"LINEJOIN",(int)style->linejoin,5,
2781                  MS_CJC_NONE,"NONE",
2782                  MS_CJC_ROUND, "ROUND",
2783                  MS_CJC_BEVEL, "BEVEL",
2784                  MS_CJC_MITER, "MITER");
2785   }
2786   writeNumber(stream, indent, "LINEJOINMAXSIZE", MS_CJC_DEFAULT_JOIN_MAXSIZE , style->linejoinmaxsize);
2787 
2788 
2789   writeNumber(stream, indent, "MAXSCALEDENOM", -1, style->maxscaledenom);
2790   writeNumber(stream, indent, "MAXSIZE", MS_MAXSYMBOLSIZE, style->maxsize);
2791   writeNumber(stream, indent, "MAXWIDTH", MS_MAXSYMBOLWIDTH, style->maxwidth);
2792   writeNumber(stream, indent, "MINSCALEDENOM", -1, style->minscaledenom);
2793   writeNumber(stream, indent, "MINSIZE", MS_MINSYMBOLSIZE, style->minsize);
2794   writeNumber(stream, indent, "MINWIDTH", MS_MINSYMBOLWIDTH, style->minwidth);
2795   if((style->numbindings > 0 && (style->bindings[MS_STYLE_BINDING_OFFSET_X].item||style->bindings[MS_STYLE_BINDING_OFFSET_Y].item))||style->offsetx!=0||style->offsety!=0)
2796     writeDimension(stream, indent, "OFFSET", style->offsetx, style->offsety, style->bindings[MS_STYLE_BINDING_OFFSET_X].item, style->bindings[MS_STYLE_BINDING_OFFSET_Y].item);
2797   if((style->numbindings > 0 && (style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item||style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item))||style->polaroffsetangle!=0||style->polaroffsetpixel!=0)
2798     writeDimension(stream, indent, "POLAROFFSET", style->polaroffsetpixel, style->polaroffsetangle,
2799                  style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item, style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item);
2800 
2801   if(style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_OPACITY].item)
2802     writeAttributeBinding(stream, indent, "OPACITY", &(style->bindings[MS_STYLE_BINDING_OPACITY]));
2803   else writeNumber(stream, indent, "OPACITY", 100, style->opacity);
2804 
2805   if(style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_OUTLINECOLOR].item)
2806     writeAttributeBinding(stream, indent, "OUTLINECOLOR", &(style->bindings[MS_STYLE_BINDING_OUTLINECOLOR]));
2807   else  writeColor(stream, indent, "OUTLINECOLOR", NULL, &(style->outlinecolor));
2808 
2809   if(style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].item)
2810     writeAttributeBinding(stream, indent, "OUTLINEWIDTH", &(style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH]));
2811   else writeNumber(stream, indent, "OUTLINEWIDTH", 0, style->outlinewidth);
2812 
2813   /* PATTERN */
2814   if(style->patternlength != 0) {
2815     int i;
2816     indent++;
2817     writeBlockBegin(stream,indent,"PATTERN");
2818     writeIndent(stream, indent);
2819     for(i=0; i<style->patternlength; i++)
2820       msIO_fprintf(stream, " %.2f", style->pattern[i]);
2821     msIO_fprintf(stream,"\n");
2822     writeBlockEnd(stream,indent,"PATTERN");
2823     indent--;
2824   }
2825 
2826   if(style->position != MS_CC) {
2827     writeKeyword(stream, indent, "POSITION", style->position, 9,
2828                  MS_UL, "UL", MS_UC, "UC", MS_UR, "UR", MS_CL, "CL",
2829                  MS_CC, "CC", MS_CR, "CR", MS_LL, "LL", MS_LC, "LC",
2830                  MS_LR, "LR");
2831   }
2832 
2833   if(style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_SIZE].item)
2834     writeAttributeBinding(stream, indent, "SIZE", &(style->bindings[MS_STYLE_BINDING_SIZE]));
2835   else writeNumber(stream, indent, "SIZE", -1, style->size);
2836 
2837   if(style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_SYMBOL].item)
2838     writeAttributeBinding(stream, indent, "SYMBOL", &(style->bindings[MS_STYLE_BINDING_SYMBOL]));
2839   else writeNumberOrString(stream, indent, "SYMBOL", 0, style->symbol, style->symbolname);
2840 
2841   if(style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_WIDTH].item)
2842     writeAttributeBinding(stream, indent, "WIDTH", &(style->bindings[MS_STYLE_BINDING_WIDTH]));
2843   else writeNumber(stream, indent, "WIDTH", 1, style->width);
2844 
2845   if(style->rangeitem) {
2846     writeString(stream, indent, "RANGEITEM", NULL, style->rangeitem);
2847     writeColorRange(stream, indent, "COLORRANGE", &(style->mincolor), &(style->maxcolor));
2848     writeDoubleRange(stream, indent, "DATARANGE", style->minvalue, style->maxvalue);
2849   }
2850 
2851   writeBlockEnd(stream, indent, "STYLE");
2852 }
2853 
msWriteStyleToString(styleObj * style)2854 char* msWriteStyleToString(styleObj *style)
2855 {
2856   msIOContext  context;
2857   msIOBuffer buffer;
2858 
2859   context.label = NULL;
2860   context.write_channel = MS_TRUE;
2861   context.readWriteFunc = msIO_bufferWrite;
2862   context.cbData = &buffer;
2863   buffer.data = NULL;
2864   buffer.data_len = 0;
2865   buffer.data_offset = 0;
2866 
2867   msIO_installHandlers( NULL, &context, NULL );
2868 
2869   writeStyle(stdout, -1, style);
2870   msIO_bufferWrite( &buffer, "", 1 );
2871 
2872   msIO_installHandlers( NULL, NULL, NULL );
2873 
2874   return (char*)buffer.data;
2875 }
2876 
2877 /*
2878 ** Initialize, load and free a single class
2879 */
initClass(classObj * class)2880 int initClass(classObj *class)
2881 {
2882   class->status = MS_ON;
2883   class->debug = MS_OFF;
2884   MS_REFCNT_INIT(class);
2885   class->isfallback = FALSE;
2886 
2887   msInitExpression(&(class->expression));
2888   class->name = NULL;
2889   class->title = NULL;
2890   msInitExpression(&(class->text));
2891 
2892   class->template = NULL;
2893 
2894   initHashTable(&(class->metadata));
2895   initHashTable(&(class->validation));
2896 
2897   class->maxscaledenom = class->minscaledenom = -1.0;
2898   class->minfeaturesize = -1; /* no limit */
2899 
2900   /* Set maxstyles = 0, styles[] will be allocated as needed on first call
2901    * to msGrowClassStyles()
2902    */
2903   class->numstyles = class->maxstyles = 0;
2904   class->styles = NULL;
2905 
2906   class->numlabels = class->maxlabels = 0;
2907   class->labels = NULL;
2908 
2909   class->keyimage = NULL;
2910 
2911   class->group = NULL;
2912 
2913   class->leader = NULL;
2914 
2915   return(0);
2916 }
2917 
freeClass(classObj * class)2918 int freeClass(classObj *class)
2919 {
2920   int i;
2921 
2922   if( MS_REFCNT_DECR_IS_NOT_ZERO(class) ) {
2923     return MS_FAILURE;
2924   }
2925 
2926   msFreeExpression(&(class->expression));
2927   msFreeExpression(&(class->text));
2928   msFree(class->name);
2929   msFree(class->title);
2930   msFree(class->template);
2931   msFree(class->group);
2932 
2933   if (&(class->metadata)) msFreeHashItems(&(class->metadata));
2934   if (&(class->validation)) msFreeHashItems(&(class->validation));
2935 
2936   for(i=0; i<class->numstyles; i++) { /* each style */
2937     if(class->styles[i]!=NULL) {
2938       if(freeStyle(class->styles[i]) == MS_SUCCESS) {
2939         msFree(class->styles[i]);
2940       }
2941     }
2942   }
2943   msFree(class->styles);
2944 
2945   for(i=0; i<class->numlabels; i++) { /* each label */
2946     if(class->labels[i]!=NULL) {
2947       if(freeLabel(class->labels[i]) == MS_SUCCESS) {
2948         msFree(class->labels[i]);
2949       }
2950     }
2951   }
2952   msFree(class->labels);
2953 
2954   msFree(class->keyimage);
2955 
2956   if(class->leader) {
2957     freeLabelLeader(class->leader);
2958     msFree(class->leader);
2959     class->leader = NULL;
2960   }
2961 
2962   return MS_SUCCESS;
2963 }
2964 
2965 /*
2966 ** Ensure there is at least one free entry in the sttyles array of this
2967 ** classObj. Grow the allocated styles array if necessary and allocate
2968 ** a new style for styles[numstyles] if there is not already one,
2969 ** setting its contents to all zero bytes (i.e. does not call initStyle()
2970 ** on it).
2971 **
2972 ** This function is safe to use for the initial allocation of the styles[]
2973 ** array as well (i.e. when maxstyles==0 and styles==NULL)
2974 **
2975 ** Returns a reference to the new styleObj on success, NULL on error.
2976 */
msGrowClassStyles(classObj * class)2977 styleObj *msGrowClassStyles( classObj *class )
2978 {
2979   /* Do we need to increase the size of styles[] by  MS_STYLE_ALLOCSIZE?
2980    */
2981   if (class->numstyles == class->maxstyles) {
2982     styleObj **newStylePtr;
2983     int i, newsize;
2984 
2985     newsize = class->maxstyles + MS_STYLE_ALLOCSIZE;
2986 
2987     /* Alloc/realloc styles */
2988     newStylePtr = (styleObj**)realloc(class->styles, newsize*sizeof(styleObj*));
2989     MS_CHECK_ALLOC(newStylePtr, newsize*sizeof(styleObj*), NULL);
2990 
2991     class->styles = newStylePtr;
2992     class->maxstyles = newsize;
2993     for(i=class->numstyles; i<class->maxstyles; i++) {
2994       class->styles[i] = NULL;
2995     }
2996   }
2997 
2998   if (class->styles[class->numstyles]==NULL) {
2999     class->styles[class->numstyles]=(styleObj*)calloc(1,sizeof(styleObj));
3000     MS_CHECK_ALLOC(class->styles[class->numstyles], sizeof(styleObj), NULL);
3001   }
3002 
3003   return class->styles[class->numstyles];
3004 }
3005 
3006 /* exactly the same as for a classObj */
msGrowLabelStyles(labelObj * label)3007 styleObj *msGrowLabelStyles( labelObj *label )
3008 {
3009   /* Do we need to increase the size of styles[] by  MS_STYLE_ALLOCSIZE?
3010    */
3011   if (label->numstyles == label->maxstyles) {
3012     styleObj **newStylePtr;
3013     int i, newsize;
3014 
3015     newsize = label->maxstyles + MS_STYLE_ALLOCSIZE;
3016 
3017     /* Alloc/realloc styles */
3018     newStylePtr = (styleObj**)realloc(label->styles, newsize*sizeof(styleObj*));
3019     MS_CHECK_ALLOC(newStylePtr, newsize*sizeof(styleObj*), NULL);
3020 
3021     label->styles = newStylePtr;
3022     label->maxstyles = newsize;
3023     for(i=label->numstyles; i<label->maxstyles; i++) {
3024       label->styles[i] = NULL;
3025     }
3026   }
3027 
3028   if (label->styles[label->numstyles]==NULL) {
3029     label->styles[label->numstyles]=(styleObj*)calloc(1,sizeof(styleObj));
3030     MS_CHECK_ALLOC(label->styles[label->numstyles], sizeof(styleObj), NULL);
3031   }
3032 
3033   return label->styles[label->numstyles];
3034 }
3035 
3036 /* exactly the same as for a labelLeaderObj, needs refactoring */
msGrowLeaderStyles(labelLeaderObj * leader)3037 styleObj *msGrowLeaderStyles( labelLeaderObj *leader )
3038 {
3039   /* Do we need to increase the size of styles[] by  MS_STYLE_ALLOCSIZE?
3040    */
3041   if (leader->numstyles == leader->maxstyles) {
3042     styleObj **newStylePtr;
3043     int i, newsize;
3044 
3045     newsize = leader->maxstyles + MS_STYLE_ALLOCSIZE;
3046 
3047     /* Alloc/realloc styles */
3048     newStylePtr = (styleObj**)realloc(leader->styles,
3049                                       newsize*sizeof(styleObj*));
3050     MS_CHECK_ALLOC(newStylePtr, newsize*sizeof(styleObj*), NULL);
3051 
3052     leader->styles = newStylePtr;
3053     leader->maxstyles = newsize;
3054     for(i=leader->numstyles; i<leader->maxstyles; i++) {
3055       leader->styles[i] = NULL;
3056     }
3057   }
3058 
3059   if (leader->styles[leader->numstyles]==NULL) {
3060     leader->styles[leader->numstyles]=(styleObj*)calloc(1,sizeof(styleObj));
3061     MS_CHECK_ALLOC(leader->styles[leader->numstyles], sizeof(styleObj), NULL);
3062   }
3063 
3064   return leader->styles[leader->numstyles];
3065 }
3066 
3067 /* msMaybeAllocateClassStyle()
3068 **
3069 ** Ensure that requested style index exists and has been initialized.
3070 **
3071 ** Returns MS_SUCCESS/MS_FAILURE.
3072 */
msMaybeAllocateClassStyle(classObj * c,int idx)3073 int msMaybeAllocateClassStyle(classObj* c, int idx)
3074 {
3075   if (c==NULL) return MS_FAILURE;
3076 
3077   if ( idx < 0 ) {
3078     msSetError(MS_MISCERR, "Invalid style index: %d", "msMaybeAllocateClassStyle()", idx);
3079     return MS_FAILURE;
3080   }
3081 
3082   /* Alloc empty styles as needed up to idx.
3083    * Nothing to do if requested style already exists
3084    */
3085   while(c->numstyles <= idx) {
3086     if (msGrowClassStyles(c) == NULL)
3087       return MS_FAILURE;
3088 
3089     if ( initStyle(c->styles[c->numstyles]) == MS_FAILURE ) {
3090       msSetError(MS_MISCERR, "Failed to init new styleObj",
3091                  "msMaybeAllocateClassStyle()");
3092       return(MS_FAILURE);
3093     }
3094     c->numstyles++;
3095   }
3096   return MS_SUCCESS;
3097 }
3098 
3099 
3100 
3101 /*
3102  * Reset style info in the class to defaults
3103  * the only members we don't touch are name, expression, and join/query stuff
3104  * This is used with STYLEITEM before overwriting the contents of a class.
3105  */
resetClassStyle(classObj * class)3106 void resetClassStyle(classObj *class)
3107 {
3108   int i;
3109 
3110   /* reset labels */
3111   for(i=0; i<class->numlabels; i++) {
3112     if(class->labels[i] != NULL) {
3113       if(freeLabel(class->labels[i]) == MS_SUCCESS ) {
3114         msFree(class->labels[i]);
3115       }
3116       class->labels[i] = NULL;
3117     }
3118   }
3119   class->numlabels = 0;
3120 
3121   msFreeExpression(&(class->text));
3122   msInitExpression(&(class->text));
3123 
3124   /* reset styles */
3125   for(i=0; i<class->numstyles; i++) {
3126     if(class->styles[i] != NULL) {
3127       if( freeStyle(class->styles[i]) == MS_SUCCESS ) {
3128         msFree(class->styles[i]);
3129       }
3130       class->styles[i] = NULL;
3131     }
3132   }
3133   class->numstyles = 0;
3134 
3135   class->layer = NULL;
3136 }
3137 
msGrowClassLabels(classObj * class)3138 labelObj *msGrowClassLabels( classObj *class )
3139 {
3140 
3141   /* Do we need to increase the size of labels[] by MS_LABEL_ALLOCSIZE?
3142    */
3143   if (class->numlabels == class->maxlabels) {
3144     labelObj **newLabelPtr;
3145     int i, newsize;
3146 
3147     newsize = class->maxlabels + MS_LABEL_ALLOCSIZE;
3148 
3149     /* Alloc/realloc labels */
3150     newLabelPtr = (labelObj**)realloc(class->labels, newsize*sizeof(labelObj*));
3151     MS_CHECK_ALLOC(newLabelPtr, newsize*sizeof(labelObj*), NULL);
3152 
3153     class->labels = newLabelPtr;
3154     class->maxlabels = newsize;
3155     for(i=class->numlabels; i<class->maxlabels; i++) {
3156       class->labels[i] = NULL;
3157     }
3158   }
3159 
3160   if (class->labels[class->numlabels]==NULL) {
3161     class->labels[class->numlabels]=(labelObj*)calloc(1,sizeof(labelObj));
3162     MS_CHECK_ALLOC(class->labels[class->numlabels], sizeof(labelObj), NULL);
3163   }
3164 
3165   return class->labels[class->numlabels];
3166 }
3167 
loadClass(classObj * class,layerObj * layer)3168 int loadClass(classObj *class, layerObj *layer)
3169 {
3170   int state;
3171   mapObj *map=NULL;
3172 
3173   class->layer = (layerObj *) layer;
3174   if(layer && layer->map) map = layer->map;
3175 
3176   for(;;) {
3177     switch(msyylex()) {
3178       case(CLASS):
3179         break; /* for string loads */
3180       case(DEBUG):
3181         if((class->debug = getSymbol(3, MS_ON,MS_OFF, MS_NUMBER)) == -1) return(-1);
3182         if(class->debug == MS_NUMBER) class->debug = (int) msyynumber;
3183         break;
3184       case(EOF):
3185         msSetError(MS_EOFERR, NULL, "loadClass()");
3186         return(-1);
3187       case(END):
3188         return(0);
3189         break;
3190       case(EXPRESSION):
3191         if(loadExpression(&(class->expression)) == -1) return(-1); /* loadExpression() cleans up previously allocated expression */
3192         if(msyysource == MS_URL_TOKENS) {
3193           if(msValidateParameter(class->expression.string, msLookupHashTable(&(class->validation), "expression"), msLookupHashTable(&(layer->validation), "expression"), msLookupHashTable(&(map->web.validation), "expression"), NULL) != MS_SUCCESS) {
3194             msSetError(MS_MISCERR, "URL-based EXPRESSION configuration failed pattern validation." , "loadClass()");
3195             msFreeExpression(&(class->expression));
3196             return(-1);
3197           }
3198         }
3199         break;
3200       case(GROUP):
3201         if(getString(&class->group) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
3202         if(msyysource == MS_URL_TOKENS) {
3203           if(msValidateParameter(class->group, msLookupHashTable(&(class->validation), "group"), msLookupHashTable(&(layer->validation), "group"), msLookupHashTable(&(map->web.validation), "group"), NULL) != MS_SUCCESS) {
3204             msSetError(MS_MISCERR, "URL-based GROUP configuration failed pattern validation." , "loadClass()");
3205             msFree(class->group);
3206             class->group=NULL;
3207             return(-1);
3208           }
3209         }
3210         break;
3211       case(KEYIMAGE):
3212         if(getString(&class->keyimage) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
3213         if(msyysource == MS_URL_TOKENS) {
3214           if(msValidateParameter(class->keyimage, msLookupHashTable(&(class->validation), "keyimage"), msLookupHashTable(&(layer->validation), "keyimage"), msLookupHashTable(&(map->web.validation), "keyimage"), NULL) != MS_SUCCESS) {
3215             msSetError(MS_MISCERR, "URL-based KEYIMAGE configuration failed pattern validation." , "loadClass()");
3216             msFree(class->keyimage);
3217             class->keyimage=NULL;
3218             return(-1);
3219           }
3220         }
3221         break;
3222       case(LABEL):
3223         if(msGrowClassLabels(class) == NULL) return(-1);
3224         initLabel(class->labels[class->numlabels]);
3225         class->labels[class->numlabels]->size = MS_MEDIUM; /* only set a default if the LABEL section is present */
3226         if(loadLabel(class->labels[class->numlabels]) == -1) {
3227           msFree(class->labels[class->numlabels]);
3228           return(-1);
3229         }
3230         class->numlabels++;
3231         break;
3232       case(LEADER):
3233         if(!class->leader) {
3234           class->leader = msSmallMalloc(sizeof(labelLeaderObj));
3235           initLeader(class->leader);
3236         }
3237         if(loadLeader(class->leader) == -1) return(-1);
3238         break;
3239       case(MAXSCALE):
3240       case(MAXSCALEDENOM):
3241         if(getDouble(&(class->maxscaledenom)) == -1) return(-1);
3242         break;
3243       case(METADATA):
3244         if(loadHashTable(&(class->metadata)) != MS_SUCCESS) return(-1);
3245         break;
3246       case(MINSCALE):
3247       case(MINSCALEDENOM):
3248         if(getDouble(&(class->minscaledenom)) == -1) return(-1);
3249         break;
3250       case(MINFEATURESIZE):
3251         if(getInteger(&(class->minfeaturesize)) == -1) return(-1);
3252         break;
3253       case(NAME):
3254         if(getString(&class->name) == MS_FAILURE) return(-1);
3255         break;
3256       case(STATUS):
3257         if((class->status = getSymbol(2, MS_ON,MS_OFF)) == -1) return(-1);
3258         break;
3259       case(STYLE):
3260         if(msGrowClassStyles(class) == NULL)
3261           return(-1);
3262         initStyle(class->styles[class->numstyles]);
3263         if(loadStyle(class->styles[class->numstyles]) != MS_SUCCESS) return(-1);
3264         class->numstyles++;
3265         break;
3266       case(TEMPLATE):
3267         if(getString(&class->template) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
3268         if(msyysource == MS_URL_TOKENS) {
3269           if(msValidateParameter(class->template, msLookupHashTable(&(class->validation), "template"), msLookupHashTable(&(layer->validation), "template"), msLookupHashTable(&(map->web.validation), "template"), map->templatepattern) != MS_SUCCESS) {
3270             msSetError(MS_MISCERR, "URL-based TEMPLATE configuration failed pattern validation." , "loadClass()");
3271             msFree(class->template);
3272             class->template=NULL;
3273             return(-1);
3274           }
3275         }
3276         break;
3277       case(TEXT):
3278         if(loadExpression(&(class->text)) == -1) return(-1); /* loadExpression() cleans up previously allocated expression */
3279         if(msyysource == MS_URL_TOKENS) {
3280           if(msValidateParameter(class->text.string, msLookupHashTable(&(class->validation), "text"), msLookupHashTable(&(layer->validation), "text"), msLookupHashTable(&(map->web.validation), "text"), NULL) != MS_SUCCESS) {
3281             msSetError(MS_MISCERR, "URL-based TEXT configuration failed pattern validation." , "loadClass()");
3282             msFreeExpression(&(class->text));
3283             return(-1);
3284           }
3285         }
3286         if((class->text.type != MS_STRING) && (class->text.type != MS_EXPRESSION)) {
3287           msSetError(MS_MISCERR, "Text expressions support constant or tagged replacement strings." , "loadClass()");
3288           return(-1);
3289         }
3290         break;
3291       case(TITLE):
3292         if(getString(&class->title) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
3293         if(msyysource == MS_URL_TOKENS) {
3294           if(msValidateParameter(class->title, msLookupHashTable(&(class->validation), "title"), msLookupHashTable(&(layer->validation), "title"), msLookupHashTable(&(map->web.validation), "title"), NULL) != MS_SUCCESS) {
3295             msSetError(MS_MISCERR, "URL-based TITLE configuration failed pattern validation." , "loadClass()");
3296             msFree(class->title);
3297             class->title=NULL;
3298             return(-1);
3299           }
3300         }
3301         break;
3302 
3303         /*
3304         ** for backwards compatability, these are shortcuts for style 0
3305         */
3306       case(BACKGROUNDCOLOR):
3307         if (msMaybeAllocateClassStyle(class, 0)) return MS_FAILURE;
3308         if(loadColor(&(class->styles[0]->backgroundcolor), NULL) != MS_SUCCESS) return(-1);
3309         break;
3310       case(COLOR):
3311         if (msMaybeAllocateClassStyle(class, 0)) return MS_FAILURE;
3312         if(loadColor(&(class->styles[0]->color), NULL) != MS_SUCCESS) return(-1);
3313         class->numstyles = 1; /* must *always* set a color or outlinecolor */
3314         break;
3315       case(MAXSIZE):
3316         if (msMaybeAllocateClassStyle(class, 0)) return MS_FAILURE;
3317         if(getDouble(&(class->styles[0]->maxsize)) == -1) return(-1);
3318         break;
3319       case(MINSIZE):
3320         if (msMaybeAllocateClassStyle(class, 0)) return MS_FAILURE;
3321         if(getDouble(&(class->styles[0]->minsize)) == -1) return(-1);
3322         break;
3323       case(OUTLINECOLOR):
3324         if (msMaybeAllocateClassStyle(class, 0)) return MS_FAILURE;
3325         if(loadColor(&(class->styles[0]->outlinecolor), NULL) != MS_SUCCESS) return(-1);
3326         class->numstyles = 1; /* must *always* set a color, symbol or outlinecolor */
3327         break;
3328       case(SIZE):
3329         if (msMaybeAllocateClassStyle(class, 0)) return MS_FAILURE;
3330         if(getDouble(&(class->styles[0]->size)) == -1) return(-1);
3331         break;
3332       case(SYMBOL):
3333         if (msMaybeAllocateClassStyle(class, 0)) return MS_FAILURE;
3334         if((state = getSymbol(2, MS_NUMBER,MS_STRING)) == -1) return(-1);
3335         if(state == MS_NUMBER)
3336           class->styles[0]->symbol = (int) msyynumber;
3337         else {
3338           if (class->styles[0]->symbolname != NULL)
3339             msFree(class->styles[0]->symbolname);
3340           class->styles[0]->symbolname = msStrdup(msyystring_buffer);
3341           class->numstyles = 1;
3342         }
3343         break;
3344 
3345         /*
3346         ** for backwards compatability, these are shortcuts for style 1
3347         */
3348       case(OVERLAYBACKGROUNDCOLOR):
3349         if (msMaybeAllocateClassStyle(class, 1)) return MS_FAILURE;
3350         if(loadColor(&(class->styles[1]->backgroundcolor), NULL) != MS_SUCCESS) return(-1);
3351         break;
3352       case(OVERLAYCOLOR):
3353         if (msMaybeAllocateClassStyle(class, 1)) return MS_FAILURE;
3354         if(loadColor(&(class->styles[1]->color), NULL) != MS_SUCCESS) return(-1);
3355         class->numstyles = 2; /* must *always* set a color, symbol or outlinecolor */
3356         break;
3357       case(OVERLAYMAXSIZE):
3358         if (msMaybeAllocateClassStyle(class, 1)) return MS_FAILURE;
3359         if(getDouble(&(class->styles[1]->maxsize)) == -1) return(-1);
3360         break;
3361       case(OVERLAYMINSIZE):
3362         if (msMaybeAllocateClassStyle(class, 1)) return MS_FAILURE;
3363         if(getDouble(&(class->styles[1]->minsize)) == -1) return(-1);
3364         break;
3365       case(OVERLAYOUTLINECOLOR):
3366         if (msMaybeAllocateClassStyle(class, 1)) return MS_FAILURE;
3367         if(loadColor(&(class->styles[1]->outlinecolor), NULL) != MS_SUCCESS) return(-1);
3368         class->numstyles = 2; /* must *always* set a color, symbol or outlinecolor */
3369         break;
3370       case(OVERLAYSIZE):
3371         if (msMaybeAllocateClassStyle(class, 1)) return MS_FAILURE;
3372         if(getDouble(&(class->styles[1]->size)) == -1) return(-1);
3373         break;
3374       case(OVERLAYSYMBOL):
3375         if (msMaybeAllocateClassStyle(class, 1)) return MS_FAILURE;
3376         if((state = getSymbol(2, MS_NUMBER,MS_STRING)) == -1) return(-1);
3377         if(state == MS_NUMBER)
3378           class->styles[1]->symbol = (int) msyynumber;
3379         else  {
3380           if (class->styles[1]->symbolname != NULL)
3381             msFree(class->styles[1]->symbolname);
3382           class->styles[1]->symbolname = msStrdup(msyystring_buffer);
3383         }
3384         class->numstyles = 2;
3385         break;
3386 
3387       case(VALIDATION):
3388         if(loadHashTable(&(class->validation)) != MS_SUCCESS) return(-1);
3389         break;
3390       default:
3391         if(strlen(msyystring_buffer) > 0) {
3392           msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadClass()", msyystring_buffer, msyylineno);
3393           return(-1);
3394         } else {
3395           return(0); /* end of a string, not an error */
3396         }
3397     }
3398   }
3399 }
3400 
classResolveSymbolNames(classObj * class)3401 static int classResolveSymbolNames(classObj *class)
3402 {
3403   int i,j;
3404   int try_addimage_if_notfound = MS_TRUE;
3405 
3406   if(msyysource == MS_URL_TOKENS) try_addimage_if_notfound = MS_FALSE;
3407 
3408   /* step through styles and labels to resolve symbol names */
3409   /* class styles */
3410   for(i=0; i<class->numstyles; i++) {
3411     if(class->styles[i]->symbolname) {
3412       if((class->styles[i]->symbol =  msGetSymbolIndex(&(class->layer->map->symbolset), class->styles[i]->symbolname, try_addimage_if_notfound)) == -1) {
3413         msSetError(MS_MISCERR, "Undefined symbol \"%s\" in class, style %d of layer %s.", "classResolveSymbolNames()", class->styles[i]->symbolname, i, class->layer->name);
3414         return MS_FAILURE;
3415       }
3416     }
3417   }
3418 
3419   /* label styles */
3420   for(i=0; i<class->numlabels; i++) {
3421     for(j=0; j<class->labels[i]->numstyles; j++) {
3422       if(class->labels[i]->styles[j]->symbolname) {
3423         if((class->labels[i]->styles[j]->symbol =  msGetSymbolIndex(&(class->layer->map->symbolset), class->labels[i]->styles[j]->symbolname, try_addimage_if_notfound)) == -1) {
3424           msSetError(MS_MISCERR, "Undefined symbol \"%s\" in class, label style %d of layer %s.", "classResolveSymbolNames()", class->labels[i]->styles[j]->symbolname, j, class->layer->name);
3425           return MS_FAILURE;
3426         }
3427       }
3428     }
3429   }
3430 
3431   return MS_SUCCESS;
3432 }
3433 
msUpdateClassFromString(classObj * class,char * string,int url_string)3434 int msUpdateClassFromString(classObj *class, char *string, int url_string)
3435 {
3436   if(!class || !string) return MS_FAILURE;
3437 
3438   msAcquireLock( TLOCK_PARSER );
3439 
3440   if(url_string)
3441     msyystate = MS_TOKENIZE_URL_STRING;
3442   else
3443     msyystate = MS_TOKENIZE_STRING;
3444   msyystring = string;
3445   msyylex(); /* sets things up, but doesn't process any tokens */
3446 
3447   msyylineno = 1; /* start at line 1 */
3448 
3449   if(loadClass(class, class->layer) == -1) {
3450     msReleaseLock( TLOCK_PARSER );
3451     return MS_FAILURE; /* parse error */;
3452   }
3453   msReleaseLock( TLOCK_PARSER );
3454 
3455   msyylex_destroy();
3456 
3457   if(classResolveSymbolNames(class) != MS_SUCCESS) return MS_FAILURE;
3458 
3459   return MS_SUCCESS;
3460 }
3461 
writeClass(FILE * stream,int indent,classObj * class)3462 static void writeClass(FILE *stream, int indent, classObj *class)
3463 {
3464   int i;
3465 
3466   if(class->status == MS_DELETE) return;
3467 
3468   indent++;
3469   writeBlockBegin(stream, indent, "CLASS");
3470   writeString(stream, indent, "NAME", NULL, class->name);
3471   writeString(stream, indent, "GROUP", NULL, class->group);
3472   writeNumber(stream, indent, "DEBUG", 0, class->debug);
3473   writeExpression(stream, indent, "EXPRESSION", &(class->expression));
3474   writeString(stream, indent, "KEYIMAGE", NULL, class->keyimage);
3475   for(i=0; i<class->numlabels; i++) writeLabel(stream, indent, class->labels[i]);
3476   if(class->leader)
3477     writeLeader(stream,indent,class->leader);
3478   writeNumber(stream, indent, "MAXSCALEDENOM", -1, class->maxscaledenom);
3479   writeHashTable(stream, indent, "METADATA", &(class->metadata));
3480   writeNumber(stream, indent, "MINSCALEDENOM", -1, class->minscaledenom);
3481   writeNumber(stream, indent, "MINFEATURESIZE", -1, class->minfeaturesize);
3482   writeKeyword(stream, indent, "STATUS", class->status, 1, MS_OFF, "OFF");
3483   for(i=0; i<class->numstyles; i++) writeStyle(stream, indent, class->styles[i]);
3484   writeString(stream, indent, "TEMPLATE", NULL, class->template);
3485   writeExpression(stream, indent, "TEXT", &(class->text));
3486   writeString(stream, indent, "TITLE", NULL, class->title);
3487   writeHashTable(stream, indent, "VALIDATION", &(class->validation));
3488   writeBlockEnd(stream, indent, "CLASS");
3489 }
3490 
msWriteClassToString(classObj * class)3491 char* msWriteClassToString(classObj *class)
3492 {
3493   msIOContext  context;
3494   msIOBuffer buffer;
3495 
3496   context.label = NULL;
3497   context.write_channel = MS_TRUE;
3498   context.readWriteFunc = msIO_bufferWrite;
3499   context.cbData = &buffer;
3500   buffer.data = NULL;
3501   buffer.data_len = 0;
3502   buffer.data_offset = 0;
3503 
3504   msIO_installHandlers( NULL, &context, NULL );
3505 
3506   writeClass(stdout, -1, class);
3507   msIO_bufferWrite( &buffer, "", 1 );
3508 
3509   msIO_installHandlers( NULL, NULL, NULL );
3510 
3511   return (char*)buffer.data;
3512 }
3513 
initCompositingFilter(CompositingFilter * filter)3514 int initCompositingFilter(CompositingFilter *filter) {
3515   filter->filter = NULL;
3516   filter->next = NULL;
3517   return MS_SUCCESS;
3518 }
3519 
freeCompositingFilter(CompositingFilter * filter)3520 void freeCompositingFilter(CompositingFilter *filter) {
3521   if(!filter) return;
3522   if(filter->next)
3523     freeCompositingFilter(filter->next);
3524   free(filter->filter);
3525   free(filter);
3526 }
3527 
initLayerCompositer(LayerCompositer * compositer)3528 int initLayerCompositer(LayerCompositer *compositer) {
3529   compositer->comp_op = MS_COMPOP_SRC_OVER;
3530   compositer->opacity = 100;
3531   compositer->next = NULL;
3532   compositer->filter = NULL;
3533   return MS_SUCCESS;
3534 }
3535 
freeLayerCompositer(LayerCompositer * compositer)3536 void freeLayerCompositer(LayerCompositer *compositer) {
3537   if(!compositer) return;
3538   if(compositer->next)
3539     freeLayerCompositer(compositer->next);
3540   freeCompositingFilter(compositer->filter);
3541   free(compositer);
3542 }
3543 
3544 /*
3545 ** Initialize, load and free a single layer structure
3546 */
initLayer(layerObj * layer,mapObj * map)3547 int initLayer(layerObj *layer, mapObj *map)
3548 {
3549   if (layer==NULL) {
3550     msSetError(MS_MEMERR, "Layer is null", "initLayer()");
3551     return(-1);
3552   }
3553   layer->debug = (int)msGetGlobalDebugLevel();
3554   MS_REFCNT_INIT(layer);
3555 
3556   /* Set maxclasses = 0, class[] will be allocated as needed on first call
3557    * to msGrowLayerClasses()
3558    */
3559   layer->numclasses = 0;
3560   layer->maxclasses = 0;
3561   layer->class = NULL;
3562 
3563   layer->name = NULL;
3564   layer->group = NULL;
3565   layer->status = MS_OFF;
3566   layer->data = NULL;
3567   layer->rendermode = MS_FIRST_MATCHING_CLASS;
3568 
3569   layer->map = map; /* point back to the encompassing structure */
3570 
3571   layer->type = -1;
3572 
3573   layer->toleranceunits = MS_PIXELS;
3574   layer->tolerance = -1; /* perhaps this should have a different value based on type */
3575 
3576   layer->symbolscaledenom = -1.0; /* -1 means nothing is set */
3577   layer->scalefactor = 1.0;
3578   layer->maxscaledenom = -1.0;
3579   layer->minscaledenom = -1.0;
3580   layer->minfeaturesize = -1; /* no limit */
3581   layer->maxgeowidth = -1.0;
3582   layer->mingeowidth = -1.0;
3583 
3584   layer->sizeunits = MS_PIXELS;
3585 
3586   layer->maxfeatures = -1; /* no quota */
3587   layer->startindex = -1; /*used for pagination*/
3588 
3589   layer->scaletokens = NULL;
3590   layer->numscaletokens = 0;
3591 
3592   layer->template = layer->header = layer->footer = NULL;
3593 
3594   layer->transform = MS_TRUE;
3595 
3596   layer->classitem = NULL;
3597   layer->classitemindex = -1;
3598 
3599   layer->units = MS_METERS;
3600   if(msInitProjection(&(layer->projection)) == -1) return(-1);
3601 
3602   if( map )
3603   {
3604     msProjectionInheritContextFrom(&(layer->projection), &(map->projection));
3605   }
3606 
3607   layer->project = MS_TRUE;
3608   layer->reprojectorLayerToMap = NULL;
3609   layer->reprojectorMapToLayer = NULL;
3610 
3611   initCluster(&layer->cluster);
3612 
3613   MS_INIT_COLOR(layer->offsite, -1,-1,-1, 255);
3614 
3615   layer->labelcache = MS_ON;
3616   layer->postlabelcache = MS_FALSE;
3617 
3618   layer->labelitem = NULL;
3619   layer->labelitemindex = -1;
3620 
3621   layer->labelmaxscaledenom = -1;
3622   layer->labelminscaledenom = -1;
3623 
3624   layer->tileitem = msStrdup("location");
3625   layer->tileitemindex = -1;
3626   layer->tileindex = NULL;
3627   layer->tilesrs = NULL;
3628 
3629   layer->bandsitem = NULL;
3630   layer->bandsitemindex = -1;
3631 
3632   layer->currentfeature = layer->features = NULL;
3633 
3634   layer->connection = NULL;
3635   layer->plugin_library = NULL;
3636   layer->plugin_library_original = NULL;
3637   layer->connectiontype = MS_SHAPEFILE;
3638   layer->vtable = NULL;
3639   layer->classgroup = NULL;
3640 
3641   layer->layerinfo = NULL;
3642   layer->wfslayerinfo = NULL;
3643 
3644   layer->items = NULL;
3645   layer->iteminfo = NULL;
3646   layer->numitems = 0;
3647 
3648   layer->resultcache= NULL;
3649 
3650   msInitExpression(&(layer->filter));
3651   layer->filteritem = NULL;
3652   layer->filteritemindex = -1;
3653 
3654   layer->requires = layer->labelrequires = NULL;
3655 
3656   initHashTable(&(layer->metadata));
3657   initHashTable(&(layer->bindvals));
3658   initHashTable(&(layer->validation));
3659 
3660   layer->dump = MS_FALSE;
3661 
3662   layer->styleitem = NULL;
3663   layer->styleitemindex = -1;
3664 
3665   layer->numprocessing = 0;
3666   layer->processing = NULL;
3667   layer->numjoins = 0;
3668   layer->joins = (joinObj *) malloc(MS_MAXJOINS*sizeof(joinObj));
3669   MS_CHECK_ALLOC(layer->joins, MS_MAXJOINS*sizeof(joinObj), -1);
3670 
3671   layer->extent.minx = -1.0;
3672   layer->extent.miny = -1.0;
3673   layer->extent.maxx = -1.0;
3674   layer->extent.maxy = -1.0;
3675 
3676   layer->mask = NULL;
3677   layer->maskimage = NULL;
3678   layer->grid = NULL;
3679 
3680   msInitExpression(&(layer->_geomtransform));
3681   layer->_geomtransform.type = MS_GEOMTRANSFORM_NONE;
3682 
3683   msInitExpression(&(layer->utfdata));
3684   layer->utfitem = NULL;
3685   layer->utfitemindex = -1;
3686 
3687   layer->encoding = NULL;
3688 
3689   layer->sortBy.nProperties = 0;
3690   layer->sortBy.properties = NULL;
3691   layer->orig_st = NULL;
3692 
3693   layer->compositer = NULL;
3694 
3695   initHashTable(&(layer->connectionoptions));
3696 
3697   return(0);
3698 }
3699 
initScaleToken(scaleTokenObj * token)3700 int initScaleToken(scaleTokenObj* token) {
3701   token->n_entries = 0;
3702   token->name = NULL;
3703   token->tokens = NULL;
3704   return MS_SUCCESS;
3705 }
3706 
freeScaleTokenEntry(scaleTokenEntryObj * token)3707 int freeScaleTokenEntry( scaleTokenEntryObj *token) {
3708   msFree(token->value);
3709   return MS_SUCCESS;
3710 }
3711 
freeScaleToken(scaleTokenObj * scaletoken)3712 int freeScaleToken(scaleTokenObj *scaletoken) {
3713   int i;
3714   msFree(scaletoken->name);
3715   for(i=0;i<scaletoken->n_entries;i++) {
3716     freeScaleTokenEntry(&scaletoken->tokens[i]);
3717   }
3718   msFree(scaletoken->tokens);
3719   return MS_SUCCESS;
3720 }
3721 
freeLayer(layerObj * layer)3722 int freeLayer(layerObj *layer)
3723 {
3724   int i;
3725   if (!layer) return MS_FAILURE;
3726   if( MS_REFCNT_DECR_IS_NOT_ZERO(layer) ) {
3727     return MS_FAILURE;
3728   }
3729 
3730   if (layer->debug >= MS_DEBUGLEVEL_VVV)
3731     msDebug("freeLayer(): freeing layer at %p.\n",layer);
3732 
3733   if(msLayerIsOpen(layer))
3734     msLayerClose(layer);
3735 
3736   msFree(layer->name);
3737   msFree(layer->encoding);
3738   msFree(layer->group);
3739   msFree(layer->data);
3740   msFree(layer->classitem);
3741   msFree(layer->labelitem);
3742   msFree(layer->header);
3743   msFree(layer->footer);
3744   msFree(layer->template);
3745   msFree(layer->tileindex);
3746   msFree(layer->tileitem);
3747   msFree(layer->tilesrs);
3748   msFree(layer->bandsitem);
3749   msFree(layer->plugin_library);
3750   msFree(layer->plugin_library_original);
3751   msFree(layer->connection);
3752   msFree(layer->vtable);
3753   msFree(layer->classgroup);
3754 
3755   msProjectDestroyReprojector(layer->reprojectorLayerToMap);
3756   msProjectDestroyReprojector(layer->reprojectorMapToLayer);
3757   msFreeProjection(&(layer->projection));
3758   msFreeExpression(&layer->_geomtransform);
3759 
3760   freeCluster(&layer->cluster);
3761 
3762   for(i=0; i<layer->maxclasses; i++) {
3763     if (layer->class[i] != NULL) {
3764       layer->class[i]->layer=NULL;
3765       if ( freeClass(layer->class[i]) == MS_SUCCESS ) {
3766         msFree(layer->class[i]);
3767       }
3768     }
3769   }
3770   msFree(layer->class);
3771 
3772   if(layer->numscaletokens>0) {
3773     for(i=0;i<layer->numscaletokens;i++) {
3774       freeScaleToken(&layer->scaletokens[i]);
3775     }
3776     msFree(layer->scaletokens);
3777   }
3778 
3779   if(layer->features)
3780     freeFeatureList(layer->features);
3781 
3782   if(layer->resultcache) {
3783     cleanupResultCache(layer->resultcache);
3784     msFree(layer->resultcache);
3785   }
3786 
3787   msFree(layer->styleitem);
3788 
3789   msFree(layer->filteritem);
3790   msFreeExpression(&(layer->filter));
3791 
3792   msFree(layer->requires);
3793   msFree(layer->labelrequires);
3794 
3795   if(&(layer->metadata)) msFreeHashItems(&(layer->metadata));
3796   if(&(layer->validation)) msFreeHashItems(&(layer->validation));
3797   if(&(layer->bindvals))  msFreeHashItems(&layer->bindvals);
3798 
3799   if(layer->numprocessing > 0)
3800     msFreeCharArray(layer->processing, layer->numprocessing);
3801 
3802   for(i=0; i<layer->numjoins; i++) /* each join */
3803     freeJoin(&(layer->joins[i]));
3804   msFree(layer->joins);
3805   layer->numjoins = 0;
3806 
3807   layer->classgroup = NULL;
3808 
3809   msFree(layer->mask);
3810   if(layer->maskimage) {
3811     msFreeImage(layer->maskimage);
3812   }
3813 
3814   if(layer->compositer) {
3815     freeLayerCompositer(layer->compositer);
3816   }
3817 
3818   if (layer->grid) {
3819     freeGrid(layer->grid);
3820     msFree(layer->grid);
3821   }
3822 
3823   msFreeExpression(&(layer->utfdata));
3824   msFree(layer->utfitem);
3825 
3826   for(i=0;i<layer->sortBy.nProperties;i++)
3827       msFree(layer->sortBy.properties[i].item);
3828   msFree(layer->sortBy.properties);
3829 
3830   if(&(layer->connectionoptions))  msFreeHashItems(&layer->connectionoptions);
3831 
3832   return MS_SUCCESS;
3833 }
3834 
3835 /*
3836 ** Ensure there is at least one free entry in the class array of this
3837 ** layerObj. Grow the allocated class array if necessary and allocate
3838 ** a new class for class[numclasses] if there is not already one,
3839 ** setting its contents to all zero bytes (i.e. does not call initClass()
3840 ** on it).
3841 **
3842 ** This function is safe to use for the initial allocation of the class[]
3843 ** array as well (i.e. when maxclasses==0 and class==NULL)
3844 **
3845 ** Returns a reference to the new classObj on success, NULL on error.
3846 */
msGrowLayerClasses(layerObj * layer)3847 classObj *msGrowLayerClasses( layerObj *layer )
3848 {
3849   /* Do we need to increase the size of class[] by  MS_CLASS_ALLOCSIZE?
3850    */
3851   if (layer->numclasses == layer->maxclasses) {
3852     classObj **newClassPtr;
3853     int i, newsize;
3854 
3855     newsize = layer->maxclasses + MS_CLASS_ALLOCSIZE;
3856 
3857     /* Alloc/realloc classes */
3858     newClassPtr = (classObj**)realloc(layer->class,
3859                                       newsize*sizeof(classObj*));
3860     MS_CHECK_ALLOC(newClassPtr, newsize*sizeof(classObj*), NULL);
3861 
3862     layer->class = newClassPtr;
3863     layer->maxclasses = newsize;
3864     for(i=layer->numclasses; i<layer->maxclasses; i++) {
3865       layer->class[i] = NULL;
3866     }
3867   }
3868 
3869   if (layer->class[layer->numclasses]==NULL) {
3870     layer->class[layer->numclasses]=(classObj*)calloc(1,sizeof(classObj));
3871     MS_CHECK_ALLOC(layer->class[layer->numclasses], sizeof(classObj), NULL);
3872   }
3873 
3874   return layer->class[layer->numclasses];
3875 }
3876 
msGrowLayerScaletokens(layerObj * layer)3877 scaleTokenObj *msGrowLayerScaletokens( layerObj *layer )
3878 {
3879   layer->scaletokens = msSmallRealloc(layer->scaletokens,(layer->numscaletokens+1)*sizeof(scaleTokenObj));
3880   memset(&layer->scaletokens[layer->numscaletokens],0,sizeof(scaleTokenObj));
3881   return &layer->scaletokens[layer->numscaletokens];
3882 }
3883 
loadScaletoken(scaleTokenObj * token,layerObj * layer)3884 int loadScaletoken(scaleTokenObj *token, layerObj *layer) {
3885   for(;;) {
3886     int stop = 0;
3887     switch(msyylex()) {
3888       case(EOF):
3889         msSetError(MS_EOFERR, NULL, "loadScaletoken()");
3890         return(MS_FAILURE);
3891       case(NAME):
3892         if(getString(&token->name) == MS_FAILURE) return(MS_FAILURE);
3893         break;
3894       case(VALUES):
3895          for(;;) {
3896            if(stop) break;
3897            switch(msyylex()) {
3898              case(EOF):
3899                msSetError(MS_EOFERR, NULL, "loadScaletoken()");
3900                return(MS_FAILURE);
3901              case(END):
3902                stop = 1;
3903                if(token->n_entries == 0) {
3904                  msSetError(MS_PARSEERR,"Scaletoken (line:%d) has no VALUES defined","loadScaleToken()",msyylineno);
3905                  return(MS_FAILURE);
3906                }
3907                token->tokens[token->n_entries-1].maxscale = DBL_MAX;
3908                break;
3909              case(MS_STRING):
3910                /* we have a key */
3911                token->tokens = msSmallRealloc(token->tokens,(token->n_entries+1)*sizeof(scaleTokenEntryObj));
3912 
3913                if(1 != sscanf(msyystring_buffer,"%lf",&token->tokens[token->n_entries].minscale)) {
3914                  msSetError(MS_PARSEERR, "failed to parse SCALETOKEN VALUE (%s):(line %d), expecting \"minscale\"", "loadScaletoken()",
3915                          msyystring_buffer,msyylineno);
3916                  return(MS_FAILURE);
3917                }
3918                if(token->n_entries == 0) {
3919                  /* check supplied value was 0*/
3920                  if(token->tokens[0].minscale != 0) {
3921                   msSetError(MS_PARSEERR, "First SCALETOKEN VALUE (%s):(line %d) must be zero, expecting \"0\"", "loadScaletoken()",
3922                          msyystring_buffer,msyylineno);
3923                   return(MS_FAILURE);
3924                  }
3925                } else {
3926                  /* set max scale of previous token */
3927                  token->tokens[token->n_entries-1].maxscale = token->tokens[token->n_entries].minscale;
3928                }
3929                token->tokens[token->n_entries].value = NULL;
3930                if(getString(&(token->tokens[token->n_entries].value)) == MS_FAILURE) return(MS_FAILURE);
3931                token->n_entries++;
3932                break;
3933              default:
3934                msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadScaletoken()",  msyystring_buffer, msyylineno );
3935                return(MS_FAILURE);
3936            }
3937          }
3938          break;
3939       case(END):
3940         if(!token->name || !*(token->name)) {
3941           msSetError(MS_PARSEERR,"ScaleToken missing mandatory NAME entry (line %d)","loadScaleToken()",msyylineno);
3942           return MS_FAILURE;
3943         }
3944         if(token->n_entries == 0) {
3945           msSetError(MS_PARSEERR,"ScaleToken missing at least one VALUES entry (line %d)","loadScaleToken()",msyylineno);
3946           return MS_FAILURE;
3947         }
3948         return MS_SUCCESS;
3949       default:
3950         msSetError(MS_IDENTERR, "Parsing error 2 near (%s):(line %d)", "loadScaletoken()",  msyystring_buffer, msyylineno );
3951         return(MS_FAILURE);
3952     }
3953   } /* next token*/
3954 }
3955 
loadLayerCompositer(LayerCompositer * compositer)3956 int loadLayerCompositer(LayerCompositer *compositer) {
3957   for(;;) {
3958     switch(msyylex()) {
3959       case COMPFILTER: {
3960         CompositingFilter **filter = &compositer->filter;
3961         while(*filter) {
3962           filter = &((*filter)->next);
3963         }
3964         *filter = msSmallMalloc(sizeof(CompositingFilter));
3965         initCompositingFilter(*filter);
3966         if(getString(&((*filter)->filter)) == MS_FAILURE) return(MS_FAILURE);
3967       }
3968         break;
3969       case COMPOP: {
3970         char *compop=NULL;
3971         if(getString(&compop) == MS_FAILURE) return(MS_FAILURE);
3972         else if(!strcmp(compop,"clear"))
3973           compositer->comp_op = MS_COMPOP_CLEAR;
3974         else if(!strcmp(compop,"color-burn"))
3975           compositer->comp_op = MS_COMPOP_COLOR_BURN;
3976         else if(!strcmp(compop,"color-dodge"))
3977           compositer->comp_op = MS_COMPOP_COLOR_DODGE;
3978         else if(!strcmp(compop,"contrast"))
3979           compositer->comp_op = MS_COMPOP_CONTRAST;
3980         else if(!strcmp(compop,"darken"))
3981           compositer->comp_op = MS_COMPOP_DARKEN;
3982         else if(!strcmp(compop,"difference"))
3983           compositer->comp_op = MS_COMPOP_DIFFERENCE;
3984         else if(!strcmp(compop,"dst"))
3985           compositer->comp_op = MS_COMPOP_DST;
3986         else if(!strcmp(compop,"dst-atop"))
3987           compositer->comp_op = MS_COMPOP_DST_ATOP;
3988         else if(!strcmp(compop,"dst-in"))
3989           compositer->comp_op = MS_COMPOP_DST_IN;
3990         else if(!strcmp(compop,"dst-out"))
3991           compositer->comp_op = MS_COMPOP_DST_OUT;
3992         else if(!strcmp(compop,"dst-over"))
3993           compositer->comp_op = MS_COMPOP_DST_OVER;
3994         else if(!strcmp(compop,"exclusion"))
3995           compositer->comp_op = MS_COMPOP_EXCLUSION;
3996         else if(!strcmp(compop,"hard-light"))
3997           compositer->comp_op = MS_COMPOP_HARD_LIGHT;
3998         else if(!strcmp(compop,"invert"))
3999           compositer->comp_op = MS_COMPOP_INVERT;
4000         else if(!strcmp(compop,"invert-rgb"))
4001           compositer->comp_op = MS_COMPOP_INVERT_RGB;
4002         else if(!strcmp(compop,"lighten"))
4003           compositer->comp_op = MS_COMPOP_LIGHTEN;
4004         else if(!strcmp(compop,"minus"))
4005           compositer->comp_op = MS_COMPOP_MINUS;
4006         else if(!strcmp(compop,"multiply"))
4007           compositer->comp_op = MS_COMPOP_MULTIPLY;
4008         else if(!strcmp(compop,"overlay"))
4009           compositer->comp_op = MS_COMPOP_OVERLAY;
4010         else if(!strcmp(compop,"plus"))
4011           compositer->comp_op = MS_COMPOP_PLUS;
4012         else if(!strcmp(compop,"screen"))
4013           compositer->comp_op = MS_COMPOP_SCREEN;
4014         else if(!strcmp(compop,"soft-light"))
4015           compositer->comp_op = MS_COMPOP_SOFT_LIGHT;
4016         else if(!strcmp(compop,"src"))
4017           compositer->comp_op = MS_COMPOP_SRC;
4018         else if(!strcmp(compop,"src-atop"))
4019           compositer->comp_op = MS_COMPOP_SRC_ATOP;
4020         else if(!strcmp(compop,"src-in"))
4021           compositer->comp_op = MS_COMPOP_SRC_IN;
4022         else if(!strcmp(compop,"src-out"))
4023           compositer->comp_op = MS_COMPOP_SRC_OUT;
4024         else if(!strcmp(compop,"src-over"))
4025           compositer->comp_op = MS_COMPOP_SRC_OVER;
4026         else if(!strcmp(compop,"xor"))
4027           compositer->comp_op = MS_COMPOP_XOR;
4028         else {
4029           msSetError(MS_PARSEERR,"Unknown COMPOP \"%s\"", "loadLayerCompositer()", compop);
4030           free(compop);
4031           if (compositer->filter) {
4032             msFree(compositer->filter->filter);
4033             msFree(compositer->filter);
4034             compositer->filter=NULL;
4035             }
4036           return MS_FAILURE;
4037         }
4038         free(compop);
4039       }
4040         break;
4041       case END:
4042         return MS_SUCCESS;
4043       case OPACITY:
4044         if (getInteger(&(compositer->opacity)) == -1) {
4045           if (compositer->filter) {
4046             msFree(compositer->filter->filter);
4047             msFree(compositer->filter);
4048             compositer->filter=NULL;
4049             }
4050           return MS_FAILURE;
4051           }
4052         if(compositer->opacity<0 || compositer->opacity>100) {
4053           if (compositer->filter) {
4054             msFree(compositer->filter->filter);
4055             msFree(compositer->filter);
4056             compositer->filter=NULL;
4057             }
4058           msSetError(MS_PARSEERR,"OPACITY must be between 0 and 100 (line %d)","loadLayerCompositer()",msyylineno);
4059           return MS_FAILURE;
4060         }
4061         break;
4062       default:
4063         if (compositer->filter) {
4064           msFree(compositer->filter->filter);
4065           msFree(compositer->filter);
4066           compositer->filter=NULL;
4067           }
4068         msSetError(MS_IDENTERR, "Parsing error 2 near (%s):(line %d)", "loadLayerCompositer()",  msyystring_buffer, msyylineno );
4069         return(MS_FAILURE);
4070     }
4071   }
4072 }
loadLayer(layerObj * layer,mapObj * map)4073 int loadLayer(layerObj *layer, mapObj *map)
4074 {
4075   int type;
4076 
4077   layer->map = (mapObj *)map;
4078 
4079   for(;;) {
4080     switch(msyylex()) {
4081       case(BINDVALS):
4082         if(loadHashTable(&(layer->bindvals)) != MS_SUCCESS) return(-1);
4083         break;
4084       case(CLASS):
4085         if (msGrowLayerClasses(layer) == NULL)
4086           return(-1);
4087         initClass(layer->class[layer->numclasses]);
4088         if(loadClass(layer->class[layer->numclasses], layer) == -1) return(-1);
4089         layer->numclasses++;
4090         break;
4091       case(CLUSTER):
4092         initCluster(&layer->cluster);
4093         if(loadCluster(&layer->cluster) == -1) return(-1);
4094         break;
4095       case(CLASSGROUP):
4096         if(getString(&layer->classgroup) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4097         if(msyysource == MS_URL_TOKENS) {
4098           if(msValidateParameter(layer->classgroup, msLookupHashTable(&(layer->validation), "classgroup"), msLookupHashTable(&(map->web.validation), "classgroup"), NULL, NULL) != MS_SUCCESS) {
4099             msSetError(MS_MISCERR, "URL-based CLASSGROUP configuration failed pattern validation." , "loadLayer()");
4100             msFree(layer->classgroup);
4101             layer->classgroup=NULL;
4102             return(-1);
4103           }
4104         }
4105         break;
4106       case(CLASSITEM):
4107         if(getString(&layer->classitem) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4108         if(msyysource == MS_URL_TOKENS) {
4109           if(msValidateParameter(layer->classitem, msLookupHashTable(&(layer->validation), "classitem"), msLookupHashTable(&(map->web.validation), "classitem"), NULL, NULL) != MS_SUCCESS) {
4110             msSetError(MS_MISCERR, "URL-based CLASSITEM configuration failed pattern validation." , "loadLayer()");
4111             msFree(layer->classitem);
4112             layer->classitem=NULL;
4113             return(-1);
4114           }
4115         }
4116         break;
4117       case(COMPOSITE): {
4118         LayerCompositer *compositer = msSmallMalloc(sizeof(LayerCompositer));
4119         initLayerCompositer(compositer);
4120         if(MS_FAILURE == loadLayerCompositer(compositer)) {
4121           msFree(compositer);
4122           return -1;
4123           }
4124         if(!layer->compositer) {
4125           layer->compositer = compositer;
4126         } else {
4127           LayerCompositer *lctmp = layer->compositer;
4128           while(lctmp->next) lctmp = lctmp->next;
4129           lctmp->next = compositer;
4130         }
4131         break;
4132       }
4133       case(CONNECTION):
4134         if(getString(&layer->connection) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4135         if(msyysource == MS_URL_TOKENS) {
4136           if(msValidateParameter(layer->connection, msLookupHashTable(&(layer->validation), "connection"), msLookupHashTable(&(map->web.validation), "connection"), NULL, NULL) != MS_SUCCESS) {
4137             msSetError(MS_MISCERR, "URL-based CONNECTION configuration failed pattern validation." , "loadLayer()");
4138             msFree(layer->connection);
4139             layer->connection=NULL;
4140             return(-1);
4141           }
4142         }
4143         break;
4144       case(CONNECTIONTYPE):
4145         if((type = getSymbol(11, MS_OGR, MS_POSTGIS, MS_WMS, MS_ORACLESPATIAL, MS_WFS, MS_GRATICULE, MS_PLUGIN, MS_UNION, MS_UVRASTER, MS_CONTOUR, MS_KERNELDENSITY)) == -1) return(-1);
4146         layer->connectiontype = type;
4147         break;
4148       case(DATA):
4149         if(getString(&layer->data) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4150         if(msyysource == MS_URL_TOKENS) {
4151           if(msValidateParameter(layer->data, msLookupHashTable(&(layer->validation), "data"), msLookupHashTable(&(map->web.validation), "data"), map->datapattern, NULL) != MS_SUCCESS) {
4152             msSetError(MS_MISCERR, "URL-based DATA configuration failed pattern validation." , "loadLayer()");
4153             msFree(layer->data);
4154             layer->data=NULL;
4155             return(-1);
4156           }
4157         }
4158         break;
4159       case(DEBUG):
4160         if((layer->debug = getSymbol(3, MS_ON,MS_OFF, MS_NUMBER)) == -1) return(-1);
4161         if(layer->debug == MS_NUMBER) layer->debug = (int) msyynumber;
4162         break;
4163       case(DUMP):
4164         if((layer->dump = getSymbol(2, MS_TRUE,MS_FALSE)) == -1) return(-1);
4165         break;
4166       case(EOF):
4167         msSetError(MS_EOFERR, NULL, "loadLayer()");
4168         return(-1);
4169         break;
4170       case(ENCODING):
4171         if(getString(&layer->encoding) == MS_FAILURE) return(-1);
4172         break;
4173       case(END):
4174         if((int)layer->type == -1) {
4175           msSetError(MS_MISCERR, "Layer type not set.", "loadLayer()");
4176           return(-1);
4177         }
4178 
4179         return(0);
4180         break;
4181       case(EXTENT): {
4182         if(getDouble(&(layer->extent.minx)) == -1) return(-1);
4183         if(getDouble(&(layer->extent.miny)) == -1) return(-1);
4184         if(getDouble(&(layer->extent.maxx)) == -1) return(-1);
4185         if(getDouble(&(layer->extent.maxy)) == -1) return(-1);
4186         if (!MS_VALID_EXTENT(layer->extent)) {
4187           msSetError(MS_MISCERR, "Given layer extent is invalid. Check that it is in the form: minx, miny, maxx, maxy", "loadLayer()");
4188           return(-1);
4189         }
4190         break;
4191       }
4192       case(FEATURE):
4193         if((int)layer->type == -1) {
4194           msSetError(MS_MISCERR, "Layer type must be set before defining inline features.", "loadLayer()");
4195           return(-1);
4196         }
4197 
4198         if(layer->type == MS_LAYER_POLYGON)
4199           type = MS_SHAPE_POLYGON;
4200         else if(layer->type == MS_LAYER_LINE)
4201           type = MS_SHAPE_LINE;
4202         else
4203           type = MS_SHAPE_POINT;
4204 
4205         layer->connectiontype = MS_INLINE;
4206 
4207         if(loadFeature(layer, type) == MS_FAILURE) return(-1);
4208         break;
4209       case(FILTER):
4210         if(loadExpression(&(layer->filter)) == -1) return(-1); /* loadExpression() cleans up previously allocated expression */
4211         if(msyysource == MS_URL_TOKENS) {
4212           if(msValidateParameter(layer->filter.string, msLookupHashTable(&(layer->validation), "filter"), msLookupHashTable(&(map->web.validation), "filter"), NULL, NULL) != MS_SUCCESS) {
4213             msSetError(MS_MISCERR, "URL-based FILTER configuration failed pattern validation." , "loadLayer()");
4214             msFreeExpression(&(layer->filter));
4215             return(-1);
4216           }
4217         }
4218         break;
4219       case(FILTERITEM):
4220         if(getString(&layer->filteritem) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4221         if(msyysource == MS_URL_TOKENS) {
4222           if(msValidateParameter(layer->filteritem, msLookupHashTable(&(layer->validation), "filteritem"), msLookupHashTable(&(map->web.validation), "filteritem"), NULL, NULL) != MS_SUCCESS) {
4223             msSetError(MS_MISCERR, "URL-based FILTERITEM configuration failed pattern validation." , "loadLayer()");
4224             msFree(layer->filteritem);
4225             layer->filteritem=NULL;
4226             return(-1);
4227           }
4228         }
4229         break;
4230       case(FOOTER):
4231         if(getString(&layer->footer) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4232         if(msyysource == MS_URL_TOKENS) {
4233           if(msValidateParameter(layer->footer, msLookupHashTable(&(layer->validation), "footer"), msLookupHashTable(&(map->web.validation), "footer"), map->templatepattern, NULL) != MS_SUCCESS) {
4234             msSetError(MS_MISCERR, "URL-based FOOTER configuration failed pattern validation." , "loadLayer()");
4235             msFree(layer->footer);
4236             layer->footer=NULL;
4237             return(-1);
4238           }
4239         }
4240         break;
4241       case(GRID):
4242         layer->connectiontype = MS_GRATICULE;
4243         if (layer->grid) {
4244           freeGrid(layer->grid);
4245           msFree(layer->grid);
4246         }
4247         layer->grid = (void *) malloc(sizeof(graticuleObj));
4248         MS_CHECK_ALLOC(layer->grid, sizeof(graticuleObj), -1);
4249 
4250         initGrid(layer->grid);
4251         loadGrid(layer);
4252         break;
4253       case(GROUP):
4254         if(getString(&layer->group) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4255         if(msyysource == MS_URL_TOKENS) {
4256           if(msValidateParameter(layer->group, msLookupHashTable(&(layer->validation), "group"), msLookupHashTable(&(map->web.validation), "group"), NULL, NULL) != MS_SUCCESS) {
4257             msSetError(MS_MISCERR, "URL-based GROUP configuration failed pattern validation." , "loadLayer()");
4258             msFree(layer->group);
4259             layer->group=NULL;
4260             return(-1);
4261           }
4262         }
4263         break;
4264       case(GEOMTRANSFORM): {
4265         int s;
4266         if((s = getSymbol(1, MS_EXPRESSION)) == -1) return(MS_FAILURE);
4267         /* handle expression case here for the moment */
4268         msFree(layer->_geomtransform.string);
4269         layer->_geomtransform.string = msStrdup(msyystring_buffer);
4270         layer->_geomtransform.type = MS_GEOMTRANSFORM_EXPRESSION;
4271       }
4272       break;
4273       case(HEADER):
4274         if(getString(&layer->header) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4275         if(msyysource == MS_URL_TOKENS) {
4276           if(msValidateParameter(layer->header, msLookupHashTable(&(layer->validation), "header"), msLookupHashTable(&(map->web.validation), "header"), map->templatepattern, NULL) != MS_SUCCESS) {
4277             msSetError(MS_MISCERR, "URL-based HEADER configuration failed pattern validation." , "loadLayer()");
4278             msFree(layer->header);
4279             layer->header=NULL;
4280             return(-1);
4281           }
4282         }
4283         break;
4284       case(JOIN):
4285         if(layer->numjoins == MS_MAXJOINS) { /* no room */
4286           msSetError(MS_IDENTERR, "Maximum number of joins reached.", "loadLayer()");
4287           return(-1);
4288         }
4289 
4290         if(loadJoin(&(layer->joins[layer->numjoins])) == -1) return(-1);
4291         layer->numjoins++;
4292         break;
4293       case(LABELCACHE):
4294         if((layer->labelcache = getSymbol(2, MS_ON, MS_OFF)) == -1) return(-1);
4295         break;
4296       case(LABELITEM):
4297         if(getString(&layer->labelitem) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4298         if(msyysource == MS_URL_TOKENS) {
4299           if(msValidateParameter(layer->labelitem, msLookupHashTable(&(layer->validation), "labelitem"), msLookupHashTable(&(map->web.validation), "labelitem"), NULL, NULL) != MS_SUCCESS) {
4300             msSetError(MS_MISCERR, "URL-based LABELITEM configuration failed pattern validation." , "loadLayer()");
4301             msFree(layer->labelitem);
4302             layer->labelitem=NULL;
4303             return(-1);
4304           }
4305         }
4306         break;
4307       case(LABELMAXSCALE):
4308       case(LABELMAXSCALEDENOM):
4309         if(getDouble(&(layer->labelmaxscaledenom)) == -1) return(-1);
4310         break;
4311       case(LABELMINSCALE):
4312       case(LABELMINSCALEDENOM):
4313         if(getDouble(&(layer->labelminscaledenom)) == -1) return(-1);
4314         break;
4315       case(LABELREQUIRES):
4316         if(getString(&layer->labelrequires) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4317         if(msyysource == MS_URL_TOKENS) {
4318           if(msValidateParameter(layer->labelrequires, msLookupHashTable(&(layer->validation), "labelrequires"), msLookupHashTable(&(map->web.validation), "labelrequires"), NULL, NULL) != MS_SUCCESS) {
4319             msSetError(MS_MISCERR, "URL-based LABELREQUIRES configuration failed pattern validation." , "loadLayer()");
4320             msFree(layer->labelrequires);
4321             layer->labelrequires=NULL;
4322             return(-1);
4323           }
4324         }
4325         break;
4326       case(LAYER):
4327         break; /* for string loads */
4328       case(MASK):
4329         if(getString(&layer->mask) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4330         if(msyysource == MS_URL_TOKENS) {
4331           if(msValidateParameter(layer->mask, msLookupHashTable(&(layer->validation), "mask"), msLookupHashTable(&(map->web.validation), "mask"), NULL, NULL) != MS_SUCCESS) {
4332             msSetError(MS_MISCERR, "URL-based MASK configuration failed pattern validation." , "loadLayer()");
4333             msFree(layer->mask);
4334             layer->mask=NULL;
4335             return(-1);
4336           }
4337         }
4338         break;
4339       case(MAXFEATURES):
4340         if(getInteger(&(layer->maxfeatures)) == -1) return(-1);
4341         break;
4342       case(MAXSCALE):
4343       case(MAXSCALEDENOM):
4344         if(getDouble(&(layer->maxscaledenom)) == -1) return(-1);
4345         break;
4346       case(MAXGEOWIDTH):
4347         if(getDouble(&(layer->maxgeowidth)) == -1) return(-1);
4348         break;
4349       case(METADATA):
4350         if(loadHashTable(&(layer->metadata)) != MS_SUCCESS) return(-1);
4351         break;
4352       case(MINSCALE):
4353       case(MINSCALEDENOM):
4354         if(getDouble(&(layer->minscaledenom)) == -1) return(-1);
4355         break;
4356       case(MINGEOWIDTH):
4357         if(getDouble(&(layer->mingeowidth)) == -1) return(-1);
4358         break;
4359       case(MINFEATURESIZE):
4360         if(getInteger(&(layer->minfeaturesize)) == -1) return(-1);
4361         break;
4362       case(NAME):
4363         if(getString(&layer->name) == MS_FAILURE) return(-1);
4364         break;
4365       case(OFFSITE):
4366         if(loadColor(&(layer->offsite), NULL) != MS_SUCCESS) return(-1);
4367         break;
4368 
4369       case(CONNECTIONOPTIONS):
4370         if(loadHashTable(&(layer->connectionoptions)) != MS_SUCCESS) return(-1);
4371         break;
4372 
4373       case(OPACITY):
4374       case(TRANSPARENCY): /* keyword supported for mapfile backwards compatability */
4375       {
4376         int opacity;
4377         if (getInteger(&opacity) == -1) return(-1);
4378         if(opacity != 100) {
4379           if(layer->compositer) {
4380             msSetError(MS_PARSEERR, "Cannot use OPACITY and COMPOSITER simultaneously at the LAYER level (line %d)", "loadLayer()", msyylineno );
4381             return -1;
4382           }
4383           layer->compositer = msSmallMalloc(sizeof(LayerCompositer));
4384           initLayerCompositer(layer->compositer);
4385           layer->compositer->opacity = opacity;
4386         }
4387       }
4388         break;
4389       case(MS_PLUGIN): {
4390         int rv;
4391         if(getString(&layer->plugin_library_original) == MS_FAILURE) return(-1);
4392         rv = msBuildPluginLibraryPath(&layer->plugin_library,
4393                                       layer->plugin_library_original,
4394                                       map);
4395         if (rv == MS_FAILURE) return(-1);
4396       }
4397       break;
4398       case(PROCESSING): {
4399         /* NOTE: processing array maintained as size+1 with NULL terminator.
4400                  This ensure that CSL (GDAL string list) functions can be
4401                  used on the list for easy processing. */
4402         char *value=NULL;
4403         if(getString(&value) == MS_FAILURE) return(-1);
4404         if(msyysource == MS_URL_TOKENS) {
4405           if(msValidateParameter(value, msLookupHashTable(&(layer->validation), "processing"), msLookupHashTable(&(map->web.validation), "processing"), NULL, NULL) != MS_SUCCESS) {
4406             msSetError(MS_MISCERR, "URL-based PROCESSING configuration failed pattern validation." , "loadLayer()");
4407             free(value);
4408             value=NULL;
4409             return(-1);
4410           }
4411         }
4412         msLayerAddProcessing( layer, value );
4413         free(value);
4414         value=NULL;
4415       }
4416       break;
4417       case(POSTLABELCACHE):
4418         if((layer->postlabelcache = getSymbol(2, MS_TRUE, MS_FALSE)) == -1) return(-1);
4419         if(layer->postlabelcache)
4420           layer->labelcache = MS_OFF;
4421         break;
4422       case(PROJECTION):
4423         if(loadProjection(&(layer->projection)) == -1) return(-1);
4424         layer->project = MS_TRUE;
4425         break;
4426       case(REQUIRES):
4427         if(getString(&layer->requires) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4428         if(msyysource == MS_URL_TOKENS) {
4429           if(msValidateParameter(layer->requires, msLookupHashTable(&(layer->validation), "requires"), msLookupHashTable(&(map->web.validation), "requires"), NULL, NULL) != MS_SUCCESS) {
4430             msSetError(MS_MISCERR, "URL-based REQUIRES configuration failed pattern validation." , "loadLayer()");
4431             msFree(layer->requires);
4432             layer->requires=NULL;
4433             return(-1);
4434           }
4435         }
4436         break;
4437       case(SCALETOKEN):
4438         if (msGrowLayerScaletokens(layer) == NULL)
4439           return(-1);
4440         initScaleToken(&layer->scaletokens[layer->numscaletokens]);
4441         if(loadScaletoken(&layer->scaletokens[layer->numscaletokens], layer) == -1) return(-1);
4442         layer->numscaletokens++;
4443         break;
4444       case(SIZEUNITS):
4445         if((layer->sizeunits = getSymbol(8, MS_INCHES,MS_FEET,MS_MILES,MS_METERS,MS_KILOMETERS,MS_NAUTICALMILES,MS_DD,MS_PIXELS)) == -1) return(-1);
4446         break;
4447       case(STATUS):
4448         if((layer->status = getSymbol(3, MS_ON,MS_OFF,MS_DEFAULT)) == -1) return(-1);
4449         break;
4450       case(STYLEITEM):
4451         if(getString(&layer->styleitem) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4452         if(msyysource == MS_URL_TOKENS) {
4453           if(msValidateParameter(layer->styleitem, msLookupHashTable(&(layer->validation), "styleitem"), msLookupHashTable(&(map->web.validation), "styleitem"), NULL, NULL) != MS_SUCCESS) {
4454             msSetError(MS_MISCERR, "URL-based STYLEITEM configuration failed pattern validation." , "loadLayer()");
4455             msFree(layer->styleitem);
4456             layer->styleitem=NULL;
4457             return(-1);
4458           }
4459         }
4460         break;
4461       case(SYMBOLSCALE):
4462       case(SYMBOLSCALEDENOM):
4463         if(getDouble(&(layer->symbolscaledenom)) == -1) return(-1);
4464         break;
4465       case(TEMPLATE):
4466         if(getString(&layer->template) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4467         if(msyysource == MS_URL_TOKENS) {
4468           if(msValidateParameter(layer->template, msLookupHashTable(&(layer->validation), "template"), msLookupHashTable(&(map->web.validation), "template"), map->templatepattern, NULL) != MS_SUCCESS) {
4469             msSetError(MS_MISCERR, "URL-based TEMPLATE configuration failed pattern validation." , "loadLayer()");
4470             msFree(layer->template);
4471             layer->template=NULL;
4472             return(-1);
4473           }
4474         }
4475         break;
4476       case(TILEINDEX):
4477         if(getString(&layer->tileindex) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4478         if(msyysource == MS_URL_TOKENS) {
4479           if(msValidateParameter(layer->tileindex, msLookupHashTable(&(layer->validation), "tileindex"), msLookupHashTable(&(map->web.validation), "tileindex"), NULL, NULL) != MS_SUCCESS) {
4480             msSetError(MS_MISCERR, "URL-based TILEINDEX configuration failed pattern validation." , "loadLayer()");
4481             msFree(layer->tileindex);
4482             layer->tileindex=NULL;
4483             return(-1);
4484           }
4485         }
4486         break;
4487       case(TILEITEM):
4488         if(getString(&layer->tileitem) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4489         if(msyysource == MS_URL_TOKENS) {
4490           if(msValidateParameter(layer->tileitem, msLookupHashTable(&(layer->validation), "tileitem"), msLookupHashTable(&(map->web.validation), "tileitem"), NULL, NULL) != MS_SUCCESS) {
4491             msSetError(MS_MISCERR, "URL-based TILEITEM configuration failed pattern validation." , "loadLayer()");
4492             msFree(layer->tileitem);
4493             layer->tileitem=NULL;
4494             return(-1);
4495           }
4496         }
4497         break;
4498       case(TILESRS):
4499         if(getString(&layer->tilesrs) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
4500         if(msyysource == MS_URL_TOKENS) {
4501           if(msValidateParameter(layer->tilesrs, msLookupHashTable(&(layer->validation), "tilesrs"), msLookupHashTable(&(map->web.validation), "tilesrs"), NULL, NULL) != MS_SUCCESS) {
4502             msSetError(MS_MISCERR, "URL-based TILESRS configuration failed pattern validation." , "loadLayer()");
4503             msFree(layer->tilesrs);
4504             layer->tilesrs=NULL;
4505             return(-1);
4506           }
4507         }
4508         break;
4509       case(TOLERANCE):
4510         if(getDouble(&(layer->tolerance)) == -1) return(-1);
4511         break;
4512       case(TOLERANCEUNITS):
4513         if((layer->toleranceunits = getSymbol(8, MS_INCHES,MS_FEET,MS_MILES,MS_METERS,MS_KILOMETERS,MS_NAUTICALMILES,MS_DD,MS_PIXELS)) == -1) return(-1);
4514         break;
4515       case(TRANSFORM):
4516         if((layer->transform = getSymbol(11, MS_TRUE,MS_FALSE, MS_UL,MS_UC,MS_UR,MS_CL,MS_CC,MS_CR,MS_LL,MS_LC,MS_LR)) == -1) return(-1);
4517         break;
4518       case(TYPE):
4519         if((type = getSymbol(9, MS_LAYER_POINT,MS_LAYER_LINE,MS_LAYER_RASTER,MS_LAYER_POLYGON,MS_LAYER_ANNOTATION,MS_LAYER_QUERY,MS_LAYER_CIRCLE,MS_LAYER_CHART,TILEINDEX)) == -1) return(-1);
4520         if(type == TILEINDEX) type = MS_LAYER_TILEINDEX; /* TILEINDEX is also a parameter */
4521         if(type == MS_LAYER_ANNOTATION) {
4522           msSetError(MS_IDENTERR, "Annotation Layers have been removed. To obtain same functionality, use a layer with label->styles and no class->styles", "loadLayer()");
4523           return -1;
4524         }
4525         layer->type = type;
4526         break;
4527       case(UNITS):
4528         if((layer->units = getSymbol(9, MS_INCHES,MS_FEET,MS_MILES,MS_METERS,MS_KILOMETERS,MS_NAUTICALMILES,MS_DD,MS_PIXELS,MS_PERCENTAGES)) == -1) return(-1);
4529         break;
4530       case(UTFDATA):
4531         if(loadExpression(&(layer->utfdata)) == -1) return(-1); /* loadExpression() cleans up previously allocated expression */
4532         break;
4533       case(UTFITEM):
4534         if(getString(&layer->utfitem) == MS_FAILURE) return(-1); /* loadExpression() cleans up previously allocated expression */
4535         break;
4536       case(VALIDATION):
4537         if(loadHashTable(&(layer->validation)) != MS_SUCCESS) return(-1);
4538         break;
4539       default:
4540         if(strlen(msyystring_buffer) > 0) {
4541           msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadLayer()", msyystring_buffer, msyylineno);
4542           return(-1);
4543         } else {
4544           return(0); /* end of a string, not an error */
4545         }
4546     }
4547   } /* next token */
4548 }
4549 
msUpdateLayerFromString(layerObj * layer,char * string,int url_string)4550 int msUpdateLayerFromString(layerObj *layer, char *string, int url_string)
4551 {
4552   int i;
4553 
4554   if(!layer || !string) return MS_FAILURE;
4555 
4556   msAcquireLock( TLOCK_PARSER );
4557 
4558   if(url_string)
4559     msyystate = MS_TOKENIZE_URL_STRING;
4560   else
4561     msyystate = MS_TOKENIZE_STRING;
4562   msyystring = string;
4563   msyylex(); /* sets things up, but doesn't process any tokens */
4564 
4565   msyylineno = 1; /* start at line 1 */
4566 
4567   if(loadLayer(layer, layer->map) == -1) {
4568     msReleaseLock( TLOCK_PARSER );
4569     return MS_FAILURE; /* parse error */;
4570   }
4571   msReleaseLock( TLOCK_PARSER );
4572 
4573   msyylex_destroy();
4574 
4575   /* step through classes to resolve symbol names */
4576   for(i=0; i<layer->numclasses; i++) {
4577     if(classResolveSymbolNames(layer->class[i]) != MS_SUCCESS) return MS_FAILURE;
4578   }
4579 
4580   return MS_SUCCESS;
4581 }
4582 
writeCompositingFilter(FILE * stream,int indent,CompositingFilter * filter)4583 static void writeCompositingFilter(FILE *stream, int indent, CompositingFilter *filter) {
4584   while(filter) {
4585     writeString(stream, indent, "COMPFILTER", "", filter->filter);
4586     filter = filter->next;
4587   }
4588 }
4589 
writeLayerCompositer(FILE * stream,int indent,LayerCompositer * compositor)4590 static void writeLayerCompositer(FILE *stream, int indent, LayerCompositer *compositor) {
4591   indent++;
4592   while(compositor) {
4593     writeBlockBegin(stream, indent, "COMPOSITE");
4594     writeCompositingFilter(stream, indent, compositor->filter);
4595     if(compositor->comp_op != MS_COMPOP_SRC_OVER) {
4596       switch(compositor->comp_op) {
4597         case MS_COMPOP_CLEAR:
4598           writeString(stream, indent, "COMPOP", NULL, "clear");
4599           break;
4600         case MS_COMPOP_COLOR_BURN:
4601           writeString(stream, indent, "COMPOP", NULL, "color-burn");
4602           break;
4603         case MS_COMPOP_COLOR_DODGE:
4604           writeString(stream, indent, "COMPOP", NULL, "color-dodge");
4605           break;
4606         case MS_COMPOP_CONTRAST:
4607           writeString(stream, indent, "COMPOP", NULL, "contrast");
4608           break;
4609         case MS_COMPOP_DARKEN:
4610           writeString(stream, indent, "COMPOP", NULL, "darken");
4611           break;
4612         case MS_COMPOP_DIFFERENCE:
4613           writeString(stream, indent, "COMPOP", NULL, "difference");
4614           break;
4615         case MS_COMPOP_DST:
4616           writeString(stream, indent, "COMPOP", NULL, "dst");
4617           break;
4618         case MS_COMPOP_DST_ATOP:
4619           writeString(stream, indent, "COMPOP", NULL, "dst-atop");
4620           break;
4621         case MS_COMPOP_DST_IN:
4622           writeString(stream, indent, "COMPOP", NULL, "dst-in");
4623           break;
4624         case MS_COMPOP_DST_OUT:
4625           writeString(stream, indent, "COMPOP", NULL, "dst-out");
4626           break;
4627         case MS_COMPOP_DST_OVER:
4628           writeString(stream, indent, "COMPOP", NULL, "dst-over");
4629           break;
4630         case MS_COMPOP_EXCLUSION:
4631           writeString(stream, indent, "COMPOP", NULL, "exclusion");
4632           break;
4633         case MS_COMPOP_HARD_LIGHT:
4634           writeString(stream, indent, "COMPOP", NULL, "hard-light");
4635           break;
4636         case MS_COMPOP_INVERT:
4637           writeString(stream, indent, "COMPOP", NULL, "invert");
4638           break;
4639         case MS_COMPOP_INVERT_RGB:
4640           writeString(stream, indent, "COMPOP", NULL, "invert-rgb");
4641           break;
4642         case MS_COMPOP_LIGHTEN:
4643           writeString(stream, indent, "COMPOP", NULL, "lighten");
4644           break;
4645         case MS_COMPOP_MINUS:
4646           writeString(stream, indent, "COMPOP", NULL, "minus");
4647           break;
4648         case MS_COMPOP_MULTIPLY:
4649           writeString(stream, indent, "COMPOP", NULL, "multiply");
4650           break;
4651         case MS_COMPOP_OVERLAY:
4652           writeString(stream, indent, "COMPOP", NULL, "overlay");
4653           break;
4654         case MS_COMPOP_PLUS:
4655           writeString(stream, indent, "COMPOP", NULL, "plus");
4656           break;
4657         case MS_COMPOP_SCREEN:
4658           writeString(stream, indent, "COMPOP", NULL, "screen");
4659           break;
4660         case MS_COMPOP_SOFT_LIGHT:
4661           writeString(stream, indent, "COMPOP", NULL, "soft-light");
4662           break;
4663         case MS_COMPOP_SRC:
4664           writeString(stream, indent, "COMPOP", NULL, "src");
4665           break;
4666         case MS_COMPOP_SRC_ATOP:
4667           writeString(stream, indent, "COMPOP", NULL, "src-atop");
4668           break;
4669         case MS_COMPOP_SRC_IN:
4670           writeString(stream, indent, "COMPOP", NULL, "src-in");
4671           break;
4672         case MS_COMPOP_SRC_OUT:
4673           writeString(stream, indent, "COMPOP", NULL, "src-out");
4674           break;
4675         case MS_COMPOP_SRC_OVER:
4676           writeString(stream, indent, "COMPOP", NULL, "src-over");
4677           break;
4678         case MS_COMPOP_XOR:
4679           writeString(stream, indent, "COMPOP", NULL, "xor");
4680           break;
4681       }
4682     }
4683     writeNumber(stream,indent,"OPACITY",100,compositor->opacity);
4684     writeBlockEnd(stream,indent,"COMPOSITE");
4685     compositor = compositor->next;
4686   }
4687 }
writeLayer(FILE * stream,int indent,layerObj * layer)4688 static void writeLayer(FILE *stream, int indent, layerObj *layer)
4689 {
4690   int i;
4691   featureListNodeObjPtr current=NULL;
4692 
4693   if(layer->status == MS_DELETE)
4694     return;
4695 
4696   indent++;
4697   writeBlockBegin(stream, indent, "LAYER");
4698   /* bindvals */
4699   /* class - see below */
4700   writeString(stream, indent, "CLASSGROUP", NULL, layer->classgroup);
4701   writeString(stream, indent, "CLASSITEM", NULL, layer->classitem);
4702   writeCluster(stream, indent, &(layer->cluster));
4703   writeLayerCompositer(stream, indent, layer->compositer);
4704   writeString(stream, indent, "CONNECTION", NULL, layer->connection);
4705   writeKeyword(stream, indent, "CONNECTIONTYPE", layer->connectiontype, 10, MS_OGR, "OGR", MS_POSTGIS, "POSTGIS", MS_WMS, "WMS", MS_ORACLESPATIAL, "ORACLESPATIAL", MS_WFS, "WFS", MS_PLUGIN, "PLUGIN", MS_UNION, "UNION", MS_UVRASTER, "UVRASTER", MS_CONTOUR, "CONTOUR", MS_KERNELDENSITY, "KERNELDENSITY");
4706   writeHashTableInline(stream, indent, "CONNECTIONOPTIONS", &(layer->connectionoptions));
4707   writeString(stream, indent, "DATA", NULL, layer->data);
4708   writeNumber(stream, indent, "DEBUG", 0, layer->debug); /* is this right? see loadLayer() */
4709   writeString(stream, indent, "ENCODING", NULL, layer->encoding);
4710   writeExtent(stream, indent, "EXTENT", layer->extent);
4711   writeExpression(stream, indent, "FILTER", &(layer->filter));
4712   writeString(stream, indent, "FILTERITEM", NULL, layer->filteritem);
4713   writeString(stream, indent, "FOOTER", NULL, layer->footer);
4714   writeString(stream, indent, "GROUP", NULL, layer->group);
4715 
4716   if(layer->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) {
4717     writeIndent(stream, indent + 1);
4718     fprintf(stream, "GEOMTRANSFORM (%s)\n", layer->_geomtransform.string);
4719   }
4720 
4721   writeString(stream, indent, "HEADER", NULL, layer->header);
4722   /* join - see below */
4723   writeKeyword(stream, indent, "LABELCACHE", layer->labelcache, 1, MS_OFF, "OFF");
4724   writeString(stream, indent, "LABELITEM", NULL, layer->labelitem);
4725   writeNumber(stream, indent, "LABELMAXSCALEDENOM", -1, layer->labelmaxscaledenom);
4726   writeNumber(stream, indent, "LABELMINSCALEDENOM", -1, layer->labelminscaledenom);
4727   writeString(stream, indent, "LABELREQUIRES", NULL, layer->labelrequires);
4728   writeNumber(stream, indent, "MAXFEATURES", -1, layer->maxfeatures);
4729   writeNumber(stream, indent, "MAXGEOWIDTH", -1, layer->maxgeowidth);
4730   writeNumber(stream, indent, "MAXSCALEDENOM", -1, layer->maxscaledenom);
4731   writeString(stream, indent, "MASK", NULL, layer->mask);
4732   writeHashTable(stream, indent, "METADATA", &(layer->metadata));
4733   writeNumber(stream, indent, "MINGEOWIDTH", -1, layer->mingeowidth);
4734   writeNumber(stream, indent, "MINSCALEDENOM", -1, layer->minscaledenom);
4735   writeNumber(stream, indent, "MINFEATURESIZE", -1, layer->minfeaturesize);
4736   writeString(stream, indent, "NAME", NULL, layer->name);
4737   writeColor(stream, indent, "OFFSITE", NULL, &(layer->offsite));
4738   writeString(stream, indent, "PLUGIN", NULL, layer->plugin_library_original);
4739   writeKeyword(stream, indent, "POSTLABELCACHE", layer->postlabelcache, 1, MS_TRUE, "TRUE");
4740   for(i=0; i<layer->numprocessing; i++)
4741     writeString(stream, indent, "PROCESSING", NULL, layer->processing[i]);
4742   writeProjection(stream, indent, &(layer->projection));
4743   writeString(stream, indent, "REQUIRES", NULL, layer->requires);
4744   writeKeyword(stream, indent, "SIZEUNITS", layer->sizeunits, 7, MS_INCHES, "INCHES", MS_FEET ,"FEET", MS_MILES, "MILES", MS_METERS, "METERS", MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES, "NAUTICALMILES", MS_DD, "DD");
4745   writeKeyword(stream, indent, "STATUS", layer->status, 3, MS_ON, "ON", MS_OFF, "OFF", MS_DEFAULT, "DEFAULT");
4746   writeString(stream, indent, "STYLEITEM", NULL, layer->styleitem);
4747   writeNumber(stream, indent, "SYMBOLSCALEDENOM", -1, layer->symbolscaledenom);
4748   writeString(stream, indent, "TEMPLATE", NULL, layer->template);
4749   writeString(stream, indent, "TILEINDEX", NULL, layer->tileindex);
4750   writeString(stream, indent, "TILEITEM", NULL, layer->tileitem);
4751   writeString(stream, indent, "TILESRS", NULL, layer->tilesrs);
4752   writeNumber(stream, indent, "TOLERANCE", -1, layer->tolerance);
4753   writeKeyword(stream, indent, "TOLERANCEUNITS", layer->toleranceunits, 7, MS_INCHES, "INCHES", MS_FEET ,"FEET", MS_MILES, "MILES", MS_METERS, "METERS", MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES, "NAUTICALMILES", MS_DD, "DD");
4754   writeKeyword(stream, indent, "TRANSFORM", layer->transform, 10, MS_FALSE, "FALSE", MS_UL, "UL", MS_UC, "UC", MS_UR, "UR", MS_CL, "CL", MS_CC, "CC", MS_CR, "CR", MS_LL, "LL", MS_LC, "LC", MS_LR, "LR");
4755   writeKeyword(stream, indent, "TYPE", layer->type, 9, MS_LAYER_POINT, "POINT", MS_LAYER_LINE, "LINE", MS_LAYER_POLYGON, "POLYGON", MS_LAYER_RASTER, "RASTER", MS_LAYER_ANNOTATION, "ANNOTATION", MS_LAYER_QUERY, "QUERY", MS_LAYER_CIRCLE, "CIRCLE", MS_LAYER_TILEINDEX, "TILEINDEX", MS_LAYER_CHART, "CHART");
4756   writeKeyword(stream, indent, "UNITS", layer->units, 9, MS_INCHES, "INCHES", MS_FEET ,"FEET", MS_MILES, "MILES", MS_METERS, "METERS", MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES, "NAUTICALMILES", MS_DD, "DD", MS_PIXELS, "PIXELS", MS_PERCENTAGES, "PERCENTATGES");
4757   writeHashTable(stream, indent, "VALIDATION", &(layer->validation));
4758 
4759   /* write potentially multiply occuring objects last */
4760   for(i=0; i<layer->numscaletokens; i++)  writeScaleToken(stream, indent, &(layer->scaletokens[i]));
4761   for(i=0; i<layer->numjoins; i++)  writeJoin(stream, indent, &(layer->joins[i]));
4762   for(i=0; i<layer->numclasses; i++) writeClass(stream, indent, layer->class[i]);
4763 
4764   if( layer->grid &&  layer->connectiontype == MS_GRATICULE)
4765     writeGrid(stream, indent, layer->grid);
4766   else {
4767     current = layer->features;
4768     while(current != NULL) {
4769       writeFeature(stream, indent, &(current->shape));
4770       current = current->next;
4771     }
4772   }
4773 
4774   writeBlockEnd(stream, indent, "LAYER");
4775   writeLineFeed(stream);
4776 }
4777 
msWriteLayerToString(layerObj * layer)4778 char* msWriteLayerToString(layerObj *layer)
4779 {
4780   msIOContext  context;
4781   msIOBuffer buffer;
4782 
4783   context.label = NULL;
4784   context.write_channel = MS_TRUE;
4785   context.readWriteFunc = msIO_bufferWrite;
4786   context.cbData = &buffer;
4787   buffer.data = NULL;
4788   buffer.data_len = 0;
4789   buffer.data_offset = 0;
4790 
4791   msIO_installHandlers( NULL, &context, NULL );
4792 
4793   writeLayer(stdout, -1, layer);
4794   msIO_bufferWrite( &buffer, "", 1 );
4795 
4796   msIO_installHandlers( NULL, NULL, NULL );
4797 
4798   return (char*)buffer.data;
4799 }
4800 
4801 /*
4802 ** Initialize, load and free a referenceMapObj structure
4803 */
initReferenceMap(referenceMapObj * ref)4804 void initReferenceMap(referenceMapObj *ref)
4805 {
4806   ref->height = ref->width = 0;
4807   ref->extent.minx = ref->extent.miny = ref->extent.maxx = ref->extent.maxy = -1.0;
4808   ref->image = NULL;
4809   MS_INIT_COLOR(ref->color, 255, 0, 0, 255);
4810   MS_INIT_COLOR(ref->outlinecolor, 0, 0, 0, 255);
4811   ref->status = MS_OFF;
4812   ref->marker = 0;
4813   ref->markername = NULL;
4814   ref->markersize = 0;
4815   ref->minboxsize = 3;
4816   ref->maxboxsize = 0;
4817   ref->map = NULL;
4818 }
4819 
freeReferenceMap(referenceMapObj * ref)4820 void freeReferenceMap(referenceMapObj *ref)
4821 {
4822   msFree(ref->image);
4823   msFree(ref->markername);
4824 }
4825 
loadReferenceMap(referenceMapObj * ref,mapObj * map)4826 int loadReferenceMap(referenceMapObj *ref, mapObj *map)
4827 {
4828   int state;
4829 
4830   ref->map = (mapObj *)map;
4831 
4832   for(;;) {
4833     switch(msyylex()) {
4834       case(EOF):
4835         msSetError(MS_EOFERR, NULL, "loadReferenceMap()");
4836         return(-1);
4837       case(END):
4838         if(!ref->image) {
4839           msSetError(MS_MISCERR, "No image defined for the reference map.", "loadReferenceMap()");
4840           return(-1);
4841         }
4842         if(ref->width == 0 || ref->height == 0) {
4843           msSetError(MS_MISCERR, "No image size defined for the reference map.", "loadReferenceMap()");
4844           return(-1);
4845         }
4846         return(0);
4847         break;
4848       case(COLOR):
4849         if(loadColor(&(ref->color), NULL) != MS_SUCCESS) return(-1);
4850         break;
4851       case(EXTENT):
4852         if(getDouble(&(ref->extent.minx)) == -1) return(-1);
4853         if(getDouble(&(ref->extent.miny)) == -1) return(-1);
4854         if(getDouble(&(ref->extent.maxx)) == -1) return(-1);
4855         if(getDouble(&(ref->extent.maxy)) == -1) return(-1);
4856         if (!MS_VALID_EXTENT(ref->extent)) {
4857           msSetError(MS_MISCERR, "Given reference extent is invalid. Check that it " \
4858                      "is in the form: minx, miny, maxx, maxy", "loadReferenceMap()");
4859           return(-1);
4860         }
4861         break;
4862       case(IMAGE):
4863         if(getString(&ref->image) == MS_FAILURE) return(-1);
4864         break;
4865       case(OUTLINECOLOR):
4866         if(loadColor(&(ref->outlinecolor), NULL) != MS_SUCCESS) return(-1);
4867         break;
4868       case(SIZE):
4869         if(getInteger(&(ref->width)) == -1) return(-1);
4870         if(getInteger(&(ref->height)) == -1) return(-1);
4871         break;
4872       case(STATUS):
4873         if((ref->status = getSymbol(2, MS_ON,MS_OFF)) == -1) return(-1);
4874         break;
4875       case(MARKER):
4876         if((state = getSymbol(2, MS_NUMBER,MS_STRING)) == -1) return(-1);
4877 
4878         if(state == MS_NUMBER)
4879           ref->marker = (int) msyynumber;
4880         else {
4881           if (ref->markername != NULL)
4882             msFree(ref->markername);
4883           ref->markername = msStrdup(msyystring_buffer);
4884         }
4885         break;
4886       case(MARKERSIZE):
4887         if(getInteger(&(ref->markersize)) == -1) return(-1);
4888         break;
4889       case(MINBOXSIZE):
4890         if(getInteger(&(ref->minboxsize)) == -1) return(-1);
4891         break;
4892       case(MAXBOXSIZE):
4893         if(getInteger(&(ref->maxboxsize)) == -1) return(-1);
4894         break;
4895       case(REFERENCE):
4896         break; /* for string loads */
4897       default:
4898         if(strlen(msyystring_buffer) > 0) {
4899           msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadReferenceMap()", msyystring_buffer, msyylineno);
4900           return(-1);
4901         } else {
4902           return(0); /* end of a string, not an error */
4903         }
4904     }
4905   } /* next token */
4906 }
4907 
msUpdateReferenceMapFromString(referenceMapObj * ref,char * string,int url_string)4908 int msUpdateReferenceMapFromString(referenceMapObj *ref, char *string, int url_string)
4909 {
4910   if(!ref || !string) return MS_FAILURE;
4911 
4912   msAcquireLock( TLOCK_PARSER );
4913 
4914   if(url_string)
4915     msyystate = MS_TOKENIZE_URL_STRING;
4916   else
4917     msyystate = MS_TOKENIZE_STRING;
4918   msyystring = string;
4919   msyylex(); /* sets things up, but doesn't process any tokens */
4920 
4921   msyylineno = 1; /* start at line 1 */
4922 
4923   if(loadReferenceMap(ref, ref->map) == -1) {
4924     msReleaseLock( TLOCK_PARSER );
4925     return MS_FAILURE; /* parse error */;
4926   }
4927   msReleaseLock( TLOCK_PARSER );
4928 
4929   msyylex_destroy();
4930   return MS_SUCCESS;
4931 }
4932 
writeReferenceMap(FILE * stream,int indent,referenceMapObj * ref)4933 static void writeReferenceMap(FILE *stream, int indent, referenceMapObj *ref)
4934 {
4935   colorObj c;
4936 
4937   if(!ref->image) return;
4938 
4939   indent++;
4940   writeBlockBegin(stream, indent, "REFERENCE");
4941   MS_INIT_COLOR(c,255,0,0,255);
4942   writeColor(stream, indent, "COLOR", &c, &(ref->color));
4943   writeExtent(stream, indent, "EXTENT", ref->extent);
4944   writeString(stream, indent, "IMAGE", NULL, ref->image);
4945   MS_INIT_COLOR(c,0,0,0,255);
4946   writeColor(stream, indent, "OUTLINECOLOR", &c, &(ref->outlinecolor));
4947   writeDimension(stream, indent, "SIZE", ref->width, ref->height, NULL, NULL);
4948   writeKeyword(stream, indent, "STATUS", ref->status, 2, MS_ON, "ON", MS_OFF, "OFF");
4949   writeNumberOrString(stream, indent, "MARKER", 0, ref->marker, ref->markername);
4950   writeNumber(stream, indent, "MARKERSIZE", -1, ref->markersize);
4951   writeNumber(stream, indent, "MAXBOXSIZE", -1, ref->maxboxsize);
4952   writeNumber(stream, indent, "MINBOXSIZE", -1, ref->minboxsize);
4953   writeBlockEnd(stream, indent, "REFERENCE");
4954   writeLineFeed(stream);
4955 }
4956 
msWriteReferenceMapToString(referenceMapObj * ref)4957 char* msWriteReferenceMapToString(referenceMapObj *ref)
4958 {
4959   msIOContext  context;
4960   msIOBuffer buffer;
4961 
4962   context.label = NULL;
4963   context.write_channel = MS_TRUE;
4964   context.readWriteFunc = msIO_bufferWrite;
4965   context.cbData = &buffer;
4966   buffer.data = NULL;
4967   buffer.data_len = 0;
4968   buffer.data_offset = 0;
4969 
4970   msIO_installHandlers( NULL, &context, NULL );
4971 
4972   writeReferenceMap(stdout, -1, ref);
4973   msIO_bufferWrite( &buffer, "", 1 );
4974 
4975   msIO_installHandlers( NULL, NULL, NULL );
4976 
4977   return (char*)buffer.data;
4978 }
4979 
4980 #define MAX_FORMATOPTIONS 100
4981 
loadOutputFormat(mapObj * map)4982 static int loadOutputFormat(mapObj *map)
4983 {
4984   char *name = NULL;
4985   char *mimetype = NULL;
4986   char *driver = NULL;
4987   char *extension = NULL;
4988   int imagemode = MS_NOOVERRIDE;
4989   int transparent = MS_NOOVERRIDE;
4990   char *formatoptions[MAX_FORMATOPTIONS];
4991   int  numformatoptions = 0;
4992   char *value = NULL;
4993 
4994   for(;;) {
4995     switch(msyylex()) {
4996       case(EOF):
4997         msSetError(MS_EOFERR, NULL, "loadOutputFormat()");
4998         goto load_output_error;
4999 
5000       case(END): {
5001         outputFormatObj *format;
5002 
5003         if( driver == NULL ) {
5004           msSetError(MS_MISCERR,
5005                      "OUTPUTFORMAT clause lacks DRIVER keyword near (%s):(%d)",
5006                      "loadOutputFormat()",
5007                      msyystring_buffer, msyylineno );
5008           goto load_output_error;
5009         }
5010 
5011         format = msCreateDefaultOutputFormat( map, driver, name );
5012         if( format == NULL ) {
5013           msSetError(MS_MISCERR,
5014                      "OUTPUTFORMAT (%s) clause references driver (%s), but this driver isn't configured.",
5015                      "loadOutputFormat()", name, driver );
5016           goto load_output_error;
5017         }
5018         msFree( name );
5019         name = NULL;
5020         msFree( driver );
5021         driver = NULL;
5022 
5023         if( transparent != MS_NOOVERRIDE )
5024           format->transparent = transparent;
5025         if( extension != NULL ) {
5026           msFree( format->extension );
5027           format->extension = extension;
5028           extension = NULL;
5029         }
5030         if( mimetype != NULL ) {
5031           msFree( format->mimetype );
5032           format->mimetype = mimetype;
5033           mimetype = NULL;
5034         }
5035         if( imagemode != MS_NOOVERRIDE ) {
5036           if(format->renderer != MS_RENDER_WITH_AGG || imagemode != MS_IMAGEMODE_PC256) {
5037             /* don't force to PC256 with agg, this can happen when using mapfile defined GD
5038              * ouputformats that are now falling back to agg/png8
5039              */
5040             format->imagemode = imagemode;
5041           }
5042 
5043           if( transparent == MS_NOOVERRIDE ) {
5044             if( imagemode == MS_IMAGEMODE_RGB  )
5045               format->transparent = MS_FALSE;
5046             else if( imagemode == MS_IMAGEMODE_RGBA  )
5047               format->transparent = MS_TRUE;
5048           }
5049           if( format->imagemode == MS_IMAGEMODE_INT16
5050               || format->imagemode == MS_IMAGEMODE_FLOAT32
5051               || format->imagemode == MS_IMAGEMODE_BYTE )
5052             format->renderer = MS_RENDER_WITH_RAWDATA;
5053         }
5054         while(numformatoptions--) {
5055           char *key = strchr(formatoptions[numformatoptions],'=');
5056           if(!key || !*(key+1)) {
5057             msSetError(MS_MISCERR,"Failed to parse FORMATOPTION, expecting \"KEY=VALUE\" syntax.","loadOutputFormat()");
5058             goto load_output_error;
5059           }
5060           *key = 0;
5061           key++;
5062           msSetOutputFormatOption(format,formatoptions[numformatoptions],key);
5063           free(formatoptions[numformatoptions]);
5064         }
5065 
5066         format->inmapfile = MS_TRUE;
5067 
5068         msOutputFormatValidate( format, MS_FALSE );
5069         return(0);
5070       }
5071       case(NAME):
5072         msFree( name );
5073         if((name = getToken()) == NULL)
5074           goto load_output_error;
5075         break;
5076       case(MIMETYPE):
5077         if(getString(&mimetype) == MS_FAILURE)
5078           goto load_output_error;
5079         break;
5080       case(DRIVER): {
5081         int s;
5082         if((s = getSymbol(2, MS_STRING, TEMPLATE)) == -1) /* allow the template to be quoted or not in the mapfile */
5083           goto load_output_error;
5084         free(driver);
5085         if(s == MS_STRING)
5086           driver = msStrdup(msyystring_buffer);
5087         else
5088           driver = msStrdup("TEMPLATE");
5089       }
5090       break;
5091       case(EXTENSION):
5092         if(getString(&extension) == MS_FAILURE)
5093           goto load_output_error;
5094         if( extension[0] == '.' ) {
5095           char *temp = msStrdup(extension+1);
5096           free( extension );
5097           extension = temp;
5098         }
5099         break;
5100       case(FORMATOPTION):
5101         if(getString(&value) == MS_FAILURE)
5102           goto load_output_error;
5103         if( numformatoptions < MAX_FORMATOPTIONS )
5104           formatoptions[numformatoptions++] = value;
5105         value=NULL;
5106         break;
5107       case(IMAGEMODE):
5108         value = getToken();
5109         if( strcasecmp(value,"PC256") == 0 )
5110           imagemode = MS_IMAGEMODE_PC256;
5111         else if( strcasecmp(value,"RGB") == 0 )
5112           imagemode = MS_IMAGEMODE_RGB;
5113         else if( strcasecmp(value,"RGBA") == 0)
5114           imagemode = MS_IMAGEMODE_RGBA;
5115         else if( strcasecmp(value,"INT16") == 0)
5116           imagemode = MS_IMAGEMODE_INT16;
5117         else if( strcasecmp(value,"FLOAT32") == 0)
5118           imagemode = MS_IMAGEMODE_FLOAT32;
5119         else if( strcasecmp(value,"BYTE") == 0)
5120           imagemode = MS_IMAGEMODE_BYTE;
5121         else if( strcasecmp(value,"FEATURE") == 0)
5122           imagemode = MS_IMAGEMODE_FEATURE;
5123         else {
5124           msSetError(MS_IDENTERR,
5125                      "Parsing error near (%s):(line %d), expected PC256, RGB, RGBA, FEATURE, BYTE, INT16, or FLOAT32 for IMAGEMODE.", "loadOutputFormat()",
5126                      msyystring_buffer, msyylineno);
5127           goto load_output_error;
5128         }
5129         free(value);
5130         value=NULL;
5131         break;
5132       case(TRANSPARENT):
5133         if((transparent = getSymbol(2, MS_ON,MS_OFF)) == -1)
5134           goto load_output_error;
5135         break;
5136       default:
5137         msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadOutputFormat()",
5138                    msyystring_buffer, msyylineno);
5139         goto load_output_error;
5140     }
5141   } /* next token */
5142 load_output_error:
5143   msFree( driver );
5144   msFree( extension );
5145   msFree( mimetype );
5146   msFree( name );
5147   msFree( value );
5148   return -1;
5149 }
5150 
5151 /*
5152 ** utility function to write an output format structure to file
5153 */
writeOutputformatobject(FILE * stream,int indent,outputFormatObj * outputformat)5154 static void writeOutputformatobject(FILE *stream, int indent, outputFormatObj *outputformat)
5155 {
5156   int i = 0;
5157   if(!outputformat) return;
5158 
5159   indent++;
5160   writeBlockBegin(stream, indent, "OUTPUTFORMAT");
5161   writeString(stream, indent, "NAME", NULL, outputformat->name);
5162   writeString(stream, indent, "MIMETYPE", NULL, outputformat->mimetype);
5163   writeString(stream, indent, "DRIVER", NULL, outputformat->driver);
5164   writeString(stream, indent, "EXTENSION", NULL, outputformat->extension);
5165   writeKeyword(stream, indent, "IMAGEMODE", outputformat->imagemode, 7, MS_IMAGEMODE_PC256, "PC256", MS_IMAGEMODE_RGB, "RGB", MS_IMAGEMODE_RGBA, "RGBA", MS_IMAGEMODE_INT16, "INT16", MS_IMAGEMODE_FLOAT32, "FLOAT32", MS_IMAGEMODE_BYTE, "BYTE", MS_IMAGEMODE_FEATURE, "FEATURE");
5166   writeKeyword(stream, indent, "TRANSPARENT", outputformat->transparent, 2, MS_TRUE, "TRUE", MS_FALSE, "FALSE");
5167   for (i=0; i<outputformat->numformatoptions; i++)
5168     writeString(stream, indent, "FORMATOPTION", NULL, outputformat->formatoptions[i]);
5169   writeBlockEnd(stream, indent, "OUTPUTFORMAT");
5170   writeLineFeed(stream);
5171 }
5172 
5173 
5174 /*
5175 ** Write the output formats to file
5176 */
writeOutputformat(FILE * stream,int indent,mapObj * map)5177 static void writeOutputformat(FILE *stream, int indent, mapObj *map)
5178 {
5179   int i=0;
5180   if(!map->outputformat) return;
5181 
5182   writeOutputformatobject(stream, indent, map->outputformat);
5183   for(i=0; i<map->numoutputformats; i++) {
5184     if(map->outputformatlist[i]->inmapfile == MS_TRUE && strcmp(map->outputformatlist[i]->name, map->outputformat->name) != 0)
5185       writeOutputformatobject(stream, indent, map->outputformatlist[i]);
5186   }
5187 }
5188 
5189 /*
5190 ** Initialize, load and free a legendObj structure
5191 */
initLegend(legendObj * legend)5192 void initLegend(legendObj *legend)
5193 {
5194   legend->height = legend->width = 0;
5195   MS_INIT_COLOR(legend->imagecolor, 255,255,255,255); /* white */
5196   MS_INIT_COLOR(legend->outlinecolor, -1,-1,-1,255);
5197   initLabel(&legend->label);
5198   legend->label.position = MS_XY; /* override */
5199   legend->keysizex = 20;
5200   legend->keysizey = 10;
5201   legend->keyspacingx = 5;
5202   legend->keyspacingy = 5;
5203   legend->status = MS_OFF;
5204   legend->transparent = MS_NOOVERRIDE;
5205   legend->interlace = MS_NOOVERRIDE;
5206   legend->position = MS_LL;
5207   legend->postlabelcache = MS_FALSE; /* draw with labels */
5208   legend->template = NULL;
5209   legend->map = NULL;
5210 }
5211 
freeLegend(legendObj * legend)5212 void freeLegend(legendObj *legend)
5213 {
5214   if (legend->template)
5215     free(legend->template);
5216   freeLabel(&(legend->label));
5217 }
5218 
loadLegend(legendObj * legend,mapObj * map)5219 int loadLegend(legendObj *legend, mapObj *map)
5220 {
5221   legend->map = (mapObj *)map;
5222 
5223   for(;;) {
5224     switch(msyylex()) {
5225       case(EOF):
5226         msSetError(MS_EOFERR, NULL, "loadLegend()");
5227         return(-1);
5228       case(END):
5229         legend->label.position = MS_XY; /* overrides go here */
5230         return(0);
5231         break;
5232       case(IMAGECOLOR):
5233         if(loadColor(&(legend->imagecolor), NULL) != MS_SUCCESS) return(-1);
5234         break;
5235       case(INTERLACE):
5236         if((legend->interlace = getSymbol(2, MS_ON,MS_OFF)) == -1) return(-1);
5237         break;
5238       case(KEYSIZE):
5239         if(getInteger(&(legend->keysizex)) == -1) return(-1);
5240         if(getInteger(&(legend->keysizey)) == -1) return(-1);
5241         break;
5242       case(KEYSPACING):
5243         if(getInteger(&(legend->keyspacingx)) == -1) return(-1);
5244         if(getInteger(&(legend->keyspacingy)) == -1) return(-1);
5245         break;
5246       case(LABEL):
5247         if(loadLabel(&(legend->label)) == -1) return(-1);
5248         legend->label.angle = 0; /* force */
5249         break;
5250       case(LEGEND):
5251         break; /* for string loads */
5252       case(OUTLINECOLOR):
5253         if(loadColor(&(legend->outlinecolor), NULL) != MS_SUCCESS) return(-1);
5254         break;
5255       case(POSITION):
5256         if((legend->position = getSymbol(6, MS_UL,MS_UR,MS_LL,MS_LR,MS_UC,MS_LC)) == -1) return(-1);
5257         break;
5258       case(POSTLABELCACHE):
5259         if((legend->postlabelcache = getSymbol(2, MS_TRUE,MS_FALSE)) == -1) return(-1);
5260         break;
5261       case(STATUS):
5262         if((legend->status = getSymbol(3, MS_ON,MS_OFF,MS_EMBED)) == -1) return(-1);
5263         break;
5264       case(TRANSPARENT):
5265         if((legend->transparent = getSymbol(2, MS_ON,MS_OFF)) == -1) return(-1);
5266         break;
5267       case(TEMPLATE):
5268         if(getString(&legend->template) == MS_FAILURE) return(-1);
5269         break;
5270       default:
5271         if(strlen(msyystring_buffer) > 0) {
5272           msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadLegend()", msyystring_buffer, msyylineno);
5273           return(-1);
5274         } else {
5275           return(0); /* end of a string, not an error */
5276         }
5277     }
5278   } /* next token */
5279 }
5280 
msUpdateLegendFromString(legendObj * legend,char * string,int url_string)5281 int msUpdateLegendFromString(legendObj *legend, char *string, int url_string)
5282 {
5283   if(!legend || !string) return MS_FAILURE;
5284 
5285   msAcquireLock( TLOCK_PARSER );
5286 
5287   if(url_string)
5288     msyystate = MS_TOKENIZE_URL_STRING;
5289   else
5290     msyystate = MS_TOKENIZE_STRING;
5291   msyystring = string;
5292   msyylex(); /* sets things up, but doesn't process any tokens */
5293 
5294   msyylineno = 1; /* start at line 1 */
5295 
5296   if(loadLegend(legend, legend->map) == -1) {
5297     msReleaseLock( TLOCK_PARSER );
5298     return MS_FAILURE; /* parse error */;
5299   }
5300   msReleaseLock( TLOCK_PARSER );
5301 
5302   msyylex_destroy();
5303   return MS_SUCCESS;
5304 }
5305 
writeLegend(FILE * stream,int indent,legendObj * legend)5306 static void writeLegend(FILE *stream, int indent, legendObj *legend)
5307 {
5308   colorObj c;
5309 
5310   indent++;
5311   writeBlockBegin(stream, indent, "LEGEND");
5312   MS_INIT_COLOR(c,255,255,255,255);
5313   writeColor(stream, indent, "IMAGECOLOR", &c, &(legend->imagecolor));
5314   writeKeyword(stream, indent, "INTERLACE", legend->interlace, 2, MS_TRUE, "TRUE", MS_FALSE, "FALSE");
5315   writeDimension(stream, indent, "KEYSIZE", legend->keysizex, legend->keysizey, NULL, NULL);
5316   writeDimension(stream, indent, "KEYSPACING", legend->keyspacingx, legend->keyspacingy, NULL, NULL);
5317   writeLabel(stream, indent, &(legend->label));
5318   writeColor(stream, indent, "OUTLINECOLOR", NULL, &(legend->outlinecolor));
5319   if(legend->status == MS_EMBED) writeKeyword(stream, indent, "POSITION", legend->position, 6, MS_LL, "LL", MS_UL, "UL", MS_UR, "UR", MS_LR, "LR", MS_UC, "UC", MS_LC, "LC");
5320   writeKeyword(stream, indent, "POSTLABELCACHE", legend->postlabelcache, 1, MS_TRUE, "TRUE");
5321   writeKeyword(stream, indent, "STATUS", legend->status, 3, MS_ON, "ON", MS_OFF, "OFF", MS_EMBED, "EMBED");
5322   writeKeyword(stream, indent, "TRANSPARENT", legend->transparent, 2, MS_TRUE, "TRUE", MS_FALSE, "FALSE");
5323   writeString(stream, indent, "TEMPLATE", NULL, legend->template);
5324   writeBlockEnd(stream, indent, "LEGEND");
5325   writeLineFeed(stream);
5326 }
5327 
msWriteLegendToString(legendObj * legend)5328 char* msWriteLegendToString(legendObj *legend)
5329 {
5330   msIOContext  context;
5331   msIOBuffer buffer;
5332 
5333   context.label = NULL;
5334   context.write_channel = MS_TRUE;
5335   context.readWriteFunc = msIO_bufferWrite;
5336   context.cbData = &buffer;
5337   buffer.data = NULL;
5338   buffer.data_len = 0;
5339   buffer.data_offset = 0;
5340 
5341   msIO_installHandlers( NULL, &context, NULL );
5342 
5343   writeLegend(stdout, -1, legend);
5344   msIO_bufferWrite( &buffer, "", 1 );
5345 
5346   msIO_installHandlers( NULL, NULL, NULL );
5347 
5348   return (char*)buffer.data;
5349 }
5350 
5351 /*
5352 ** Initialize, load and free a scalebarObj structure
5353 */
initScalebar(scalebarObj * scalebar)5354 void initScalebar(scalebarObj *scalebar)
5355 {
5356   MS_INIT_COLOR(scalebar->imagecolor, -1,-1,-1,255);
5357   scalebar->width = 200;
5358   scalebar->height = 3;
5359   scalebar->style = 0; /* only 2 styles at this point */
5360   scalebar->intervals = 4;
5361   initLabel(&scalebar->label);
5362   scalebar->label.position = MS_XY; /* override */
5363   MS_INIT_COLOR(scalebar->backgroundcolor, -1,-1,-1,255);  /* if not set, scalebar creation needs to set this to match the background color */
5364   MS_INIT_COLOR(scalebar->color, 0,0,0,255); /* default to black */
5365   MS_INIT_COLOR(scalebar->outlinecolor, -1,-1,-1,255);
5366   scalebar->units = MS_MILES;
5367   scalebar->status = MS_OFF;
5368   scalebar->position = MS_LL;
5369   scalebar->transparent = MS_NOOVERRIDE; /* no transparency */
5370   scalebar->interlace = MS_NOOVERRIDE;
5371   scalebar->postlabelcache = MS_FALSE; /* draw with labels */
5372   scalebar->align = MS_ALIGN_CENTER;
5373   scalebar->offsetx = 0;
5374   scalebar->offsety = 0;
5375 }
5376 
freeScalebar(scalebarObj * scalebar)5377 void freeScalebar(scalebarObj *scalebar)
5378 {
5379   freeLabel(&(scalebar->label));
5380 }
5381 
loadScalebar(scalebarObj * scalebar)5382 int loadScalebar(scalebarObj *scalebar)
5383 {
5384   for(;;) {
5385     switch(msyylex()) {
5386       case(ALIGN):
5387         if((scalebar->align = getSymbol(3, MS_ALIGN_LEFT,MS_ALIGN_CENTER,MS_ALIGN_RIGHT)) == -1) return(-1);
5388         break;
5389       case(BACKGROUNDCOLOR):
5390         if(loadColor(&(scalebar->backgroundcolor), NULL) != MS_SUCCESS) return(-1);
5391         break;
5392       case(COLOR):
5393         if(loadColor(&(scalebar->color), NULL) != MS_SUCCESS) return(-1);
5394         break;
5395       case(EOF):
5396         msSetError(MS_EOFERR, NULL, "loadScalebar()");
5397         return(-1);
5398       case(END):
5399         return(0);
5400         break;
5401       case(IMAGECOLOR):
5402         if(loadColor(&(scalebar->imagecolor), NULL) != MS_SUCCESS) return(-1);
5403         break;
5404       case(INTERLACE):
5405         if((scalebar->interlace = getSymbol(2, MS_ON,MS_OFF)) == -1) return(-1);
5406         break;
5407       case(INTERVALS):
5408         if(getInteger(&(scalebar->intervals)) == -1) return(-1);
5409         break;
5410       case(LABEL):
5411         if(loadLabel(&(scalebar->label)) == -1) return(-1);
5412         scalebar->label.angle = 0;
5413         break;
5414       case(OUTLINECOLOR):
5415         if(loadColor(&(scalebar->outlinecolor), NULL) != MS_SUCCESS) return(-1);
5416         break;
5417       case(POSITION):
5418         if((scalebar->position = getSymbol(6, MS_UL,MS_UR,MS_LL,MS_LR,MS_UC,MS_LC)) == -1)
5419           return(-1);
5420         break;
5421       case(POSTLABELCACHE):
5422         if((scalebar->postlabelcache = getSymbol(2, MS_TRUE,MS_FALSE)) == -1) return(-1);
5423         break;
5424       case(SCALEBAR):
5425         break; /* for string loads */
5426       case(SIZE):
5427         if(getInteger(&(scalebar->width)) == -1) return(-1);
5428         if(getInteger(&(scalebar->height)) == -1) return(-1);
5429         break;
5430       case(STATUS):
5431         if((scalebar->status = getSymbol(3, MS_ON,MS_OFF,MS_EMBED)) == -1) return(-1);
5432         break;
5433       case(STYLE):
5434         if(getInteger(&(scalebar->style)) == -1) return(-1);
5435         break;
5436       case(TRANSPARENT):
5437         if((scalebar->transparent = getSymbol(2, MS_ON,MS_OFF)) == -1) return(-1);
5438         break;
5439       case(UNITS):
5440         if((scalebar->units = getSymbol(6, MS_INCHES,MS_FEET,MS_MILES,MS_METERS,MS_KILOMETERS,MS_NAUTICALMILES)) == -1) return(-1);
5441         break;
5442       case(OFFSET):
5443         if(getInteger(&(scalebar->offsetx)) == -1) return(-1);
5444         if(getInteger(&(scalebar->offsety)) == -1) return(-1);
5445         break;
5446       default:
5447         if(strlen(msyystring_buffer) > 0) {
5448           msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadScalebar()", msyystring_buffer, msyylineno);
5449           return(-1);
5450         } else {
5451           return(0); /* end of a string, not an error */
5452         }
5453     }
5454   } /* next token */
5455 }
5456 
msUpdateScalebarFromString(scalebarObj * scalebar,char * string,int url_string)5457 int msUpdateScalebarFromString(scalebarObj *scalebar, char *string, int url_string)
5458 {
5459   if(!scalebar || !string) return MS_FAILURE;
5460 
5461   msAcquireLock( TLOCK_PARSER );
5462 
5463   if(url_string)
5464     msyystate = MS_TOKENIZE_URL_STRING;
5465   else
5466     msyystate = MS_TOKENIZE_STRING;
5467   msyystring = string;
5468   msyylex(); /* sets things up, but doesn't process any tokens */
5469 
5470   msyylineno = 1; /* start at line 1 */
5471 
5472   if(loadScalebar(scalebar) == -1) {
5473     msReleaseLock( TLOCK_PARSER );
5474     return MS_FAILURE; /* parse error */;
5475   }
5476   msReleaseLock( TLOCK_PARSER );
5477 
5478   msyylex_destroy();
5479   return MS_SUCCESS;
5480 }
5481 
writeScalebar(FILE * stream,int indent,scalebarObj * scalebar)5482 static void writeScalebar(FILE *stream, int indent, scalebarObj *scalebar)
5483 {
5484   colorObj c;
5485 
5486   indent++;
5487   writeBlockBegin(stream, indent, "SCALEBAR");
5488   writeKeyword(stream, indent, "ALIGN", scalebar->align, 2, MS_ALIGN_LEFT, "LEFT", MS_ALIGN_RIGHT, "RIGHT");
5489   writeColor(stream, indent, "BACKGROUNDCOLOR", NULL, &(scalebar->backgroundcolor));
5490   MS_INIT_COLOR(c,0,0,0,255);
5491   writeColor(stream, indent, "COLOR", &c, &(scalebar->color));
5492   writeColor(stream, indent, "IMAGECOLOR", NULL, &(scalebar->imagecolor));
5493   writeKeyword(stream, indent, "INTERLACE", scalebar->interlace, 2, MS_TRUE, "TRUE", MS_FALSE, "FALSE");
5494   writeNumber(stream, indent, "INTERVALS", -1, scalebar->intervals);
5495   writeLabel(stream, indent, &(scalebar->label));
5496   writeColor(stream, indent, "OUTLINECOLOR", NULL, &(scalebar->outlinecolor));
5497   if(scalebar->status == MS_EMBED) writeKeyword(stream, indent, "POSITION", scalebar->position, 6, MS_LL, "LL", MS_UL, "UL", MS_UR, "UR", MS_LR, "LR", MS_UC, "UC", MS_LC, "LC");
5498   writeKeyword(stream, indent, "POSTLABELCACHE", scalebar->postlabelcache, 1, MS_TRUE, "TRUE");
5499   writeDimension(stream, indent, "SIZE", scalebar->width, scalebar->height, NULL, NULL);
5500   writeKeyword(stream, indent, "STATUS", scalebar->status, 3, MS_ON, "ON", MS_OFF, "OFF", MS_EMBED, "EMBED");
5501   writeNumber(stream, indent, "STYLE", 0, scalebar->style);
5502   writeKeyword(stream, indent, "TRANSPARENT", scalebar->transparent, 2, MS_TRUE, "TRUE", MS_FALSE, "FALSE");
5503   writeKeyword(stream, indent, "UNITS", scalebar->units, 6, MS_INCHES, "INCHES", MS_FEET ,"FEET", MS_MILES, "MILES", MS_METERS, "METERS", MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES, "NAUTICALMILES");
5504   writeBlockEnd(stream, indent, "SCALEBAR");
5505   writeLineFeed(stream);
5506 }
5507 
msWriteScalebarToString(scalebarObj * scalebar)5508 char* msWriteScalebarToString(scalebarObj *scalebar)
5509 {
5510   msIOContext  context;
5511   msIOBuffer buffer;
5512 
5513   context.label = NULL;
5514   context.write_channel = MS_TRUE;
5515   context.readWriteFunc = msIO_bufferWrite;
5516   context.cbData = &buffer;
5517   buffer.data = NULL;
5518   buffer.data_len = 0;
5519   buffer.data_offset = 0;
5520 
5521   msIO_installHandlers( NULL, &context, NULL );
5522 
5523   writeScalebar(stdout, -1, scalebar);
5524   msIO_bufferWrite( &buffer, "", 1 );
5525 
5526   msIO_installHandlers( NULL, NULL, NULL );
5527 
5528   return (char*)buffer.data;
5529 }
5530 
5531 /*
5532 ** Initialize a queryMapObj structure
5533 */
initQueryMap(queryMapObj * querymap)5534 void initQueryMap(queryMapObj *querymap)
5535 {
5536   querymap->width = querymap->height = -1;
5537   querymap->style = MS_HILITE;
5538   querymap->status = MS_OFF;
5539   MS_INIT_COLOR(querymap->color, 255,255,0,255); /* yellow */
5540 }
5541 
loadQueryMap(queryMapObj * querymap)5542 int loadQueryMap(queryMapObj *querymap)
5543 {
5544   for(;;) {
5545     switch(msyylex()) {
5546       case(QUERYMAP):
5547         break; /* for string loads */
5548       case(COLOR):
5549         if(loadColor(&(querymap->color), NULL) != MS_SUCCESS) return MS_FAILURE;
5550         break;
5551       case(EOF):
5552         msSetError(MS_EOFERR, NULL, "loadQueryMap()");
5553         return(-1);
5554       case(END):
5555         return(0);
5556         break;
5557       case(SIZE):
5558         if(getInteger(&(querymap->width)) == -1) return(-1);
5559         if(getInteger(&(querymap->height)) == -1) return(-1);
5560         break;
5561       case(STATUS):
5562         if((querymap->status = getSymbol(2, MS_ON,MS_OFF)) == -1) return(-1);
5563         break;
5564       case(STYLE):
5565       case(TYPE):
5566         if((querymap->style = getSymbol(3, MS_NORMAL,MS_HILITE,MS_SELECTED)) == -1) return(-1);
5567         break;
5568       default:
5569         if(strlen(msyystring_buffer) > 0) {
5570           msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadQueryMap()", msyystring_buffer, msyylineno);
5571           return(-1);
5572         } else {
5573           return(0); /* end of a string, not an error */
5574         }
5575     }
5576   }
5577 }
5578 
msUpdateQueryMapFromString(queryMapObj * querymap,char * string,int url_string)5579 int msUpdateQueryMapFromString(queryMapObj *querymap, char *string, int url_string)
5580 {
5581   if(!querymap || !string) return MS_FAILURE;
5582 
5583   msAcquireLock( TLOCK_PARSER );
5584 
5585   if(url_string)
5586     msyystate = MS_TOKENIZE_URL_STRING;
5587   else
5588     msyystate = MS_TOKENIZE_STRING;
5589   msyystring = string;
5590   msyylex(); /* sets things up, but doesn't process any tokens */
5591 
5592   msyylineno = 1; /* start at line 1 */
5593 
5594   if(loadQueryMap(querymap) == -1) {
5595     msReleaseLock( TLOCK_PARSER );
5596     return MS_FAILURE; /* parse error */;
5597   }
5598   msReleaseLock( TLOCK_PARSER );
5599 
5600   msyylex_destroy();
5601   return MS_SUCCESS;
5602 }
5603 
writeQueryMap(FILE * stream,int indent,queryMapObj * querymap)5604 static void writeQueryMap(FILE *stream, int indent, queryMapObj *querymap)
5605 {
5606   colorObj c;
5607 
5608   indent++;
5609   writeBlockBegin(stream, indent, "QUERYMAP");
5610   MS_INIT_COLOR(c,255,255,0,255);
5611   writeColor(stream, indent, "COLOR",  &c, &(querymap->color));
5612   writeDimension(stream, indent, "SIZE", querymap->width, querymap->height, NULL, NULL);
5613   writeKeyword(stream, indent, "STATUS", querymap->status, 2, MS_ON, "ON", MS_OFF, "OFF");
5614   writeKeyword(stream, indent, "STYLE", querymap->style, 3, MS_NORMAL, "NORMAL", MS_HILITE, "HILITE", MS_SELECTED, "SELECTED");
5615   writeBlockEnd(stream, indent, "QUERYMAP");
5616   writeLineFeed(stream);
5617 }
5618 
msWriteQueryMapToString(queryMapObj * querymap)5619 char* msWriteQueryMapToString(queryMapObj *querymap)
5620 {
5621   msIOContext  context;
5622   msIOBuffer buffer;
5623 
5624   context.label = NULL;
5625   context.write_channel = MS_TRUE;
5626   context.readWriteFunc = msIO_bufferWrite;
5627   context.cbData = &buffer;
5628   buffer.data = NULL;
5629   buffer.data_len = 0;
5630   buffer.data_offset = 0;
5631 
5632   msIO_installHandlers( NULL, &context, NULL );
5633 
5634   writeQueryMap(stdout, -1, querymap);
5635   msIO_bufferWrite( &buffer, "", 1 );
5636 
5637   msIO_installHandlers( NULL, NULL, NULL );
5638 
5639   return (char*)buffer.data;
5640 }
5641 
5642 /*
5643 ** Initialize a webObj structure
5644 */
initWeb(webObj * web)5645 void initWeb(webObj *web)
5646 {
5647   web->extent.minx = web->extent.miny = web->extent.maxx = web->extent.maxy = -1.0;
5648   web->template = NULL;
5649   web->header = web->footer = NULL;
5650   web->error =  web->empty = NULL;
5651   web->mintemplate = web->maxtemplate = NULL;
5652   web->minscaledenom = web->maxscaledenom = -1;
5653   web->log = NULL;
5654   web->imagepath = msStrdup("");
5655   web->temppath = NULL;
5656   web->imageurl = msStrdup("");
5657 
5658   initHashTable(&(web->metadata));
5659   initHashTable(&(web->validation));
5660 
5661   web->map = NULL;
5662   web->queryformat = msStrdup("text/html");
5663   web->legendformat = msStrdup("text/html");
5664   web->browseformat = msStrdup("text/html");
5665 }
5666 
freeWeb(webObj * web)5667 void freeWeb(webObj *web)
5668 {
5669   msFree(web->template);
5670   msFree(web->header);
5671   msFree(web->footer);
5672   msFree(web->error);
5673   msFree(web->empty);
5674   msFree(web->maxtemplate);
5675   msFree(web->mintemplate);
5676   msFree(web->log);
5677   msFree(web->imagepath);
5678   msFree(web->temppath);
5679   msFree(web->imageurl);
5680   msFree(web->queryformat);
5681   msFree(web->legendformat);
5682   msFree(web->browseformat);
5683   if(&(web->metadata)) msFreeHashItems(&(web->metadata));
5684   if(&(web->validation)) msFreeHashItems(&(web->validation));
5685 }
5686 
writeWeb(FILE * stream,int indent,webObj * web)5687 static void writeWeb(FILE *stream, int indent, webObj *web)
5688 {
5689   indent++;
5690   writeBlockBegin(stream, indent, "WEB");
5691   writeString(stream, indent, "BROWSEFORMAT", "text/html", web->browseformat);
5692   writeString(stream, indent, "EMPTY", NULL, web->empty);
5693   writeString(stream, indent, "ERROR", NULL, web->error);
5694   writeExtent(stream, indent, "EXTENT", web->extent);
5695   writeString(stream, indent, "FOOTER", NULL, web->footer);
5696   writeString(stream, indent, "HEADER", NULL, web->header);
5697   writeString(stream, indent, "IMAGEPATH", "", web->imagepath);
5698   writeString(stream, indent, "TEMPPATH", NULL, web->temppath);
5699   writeString(stream, indent, "IMAGEURL", "", web->imageurl);
5700   writeString(stream, indent, "LEGENDFORMAT", "text/html", web->legendformat);
5701   writeString(stream, indent, "LOG", NULL, web->log);
5702   writeNumber(stream, indent, "MAXSCALEDENOM", -1, web->maxscaledenom);
5703   writeString(stream, indent, "MAXTEMPLATE", NULL, web->maxtemplate);
5704   writeHashTable(stream, indent, "METADATA", &(web->metadata));
5705   writeNumber(stream, indent, "MINSCALEDENOM", -1, web->minscaledenom);
5706   writeString(stream, indent, "MINTEMPLATE", NULL, web->mintemplate);
5707   writeString(stream, indent, "QUERYFORMAT", "text/html", web->queryformat);
5708   writeString(stream, indent, "TEMPLATE", NULL, web->template);
5709   writeHashTable(stream, indent, "VALIDATION", &(web->validation));
5710   writeBlockEnd(stream, indent, "WEB");
5711   writeLineFeed(stream);
5712 }
5713 
msWriteWebToString(webObj * web)5714 char* msWriteWebToString(webObj *web)
5715 {
5716   msIOContext  context;
5717   msIOBuffer buffer;
5718 
5719   context.label = NULL;
5720   context.write_channel = MS_TRUE;
5721   context.readWriteFunc = msIO_bufferWrite;
5722   context.cbData = &buffer;
5723   buffer.data = NULL;
5724   buffer.data_len = 0;
5725   buffer.data_offset = 0;
5726 
5727   msIO_installHandlers( NULL, &context, NULL );
5728 
5729   writeWeb(stdout, -1, web);
5730   msIO_bufferWrite( &buffer, "", 1 );
5731 
5732   msIO_installHandlers( NULL, NULL, NULL );
5733 
5734   return (char*)buffer.data;
5735 }
5736 
loadWeb(webObj * web,mapObj * map)5737 int loadWeb(webObj *web, mapObj *map)
5738 {
5739   web->map = (mapObj *)map;
5740 
5741   for(;;) {
5742     switch(msyylex()) {
5743       case(BROWSEFORMAT): /* change to use validation in 6.0 */
5744         free(web->browseformat);
5745         web->browseformat = NULL; /* there is a default */
5746         if(getString(&web->browseformat) == MS_FAILURE) return(-1);
5747         break;
5748       case(EMPTY):
5749         if(getString(&web->empty) == MS_FAILURE) return(-1);
5750         break;
5751       case(WEB):
5752         break; /* for string loads */
5753       case(EOF):
5754         msSetError(MS_EOFERR, NULL, "loadWeb()");
5755         return(-1);
5756       case(END):
5757         return(0);
5758         break;
5759       case(ERROR):
5760         if(getString(&web->error) == MS_FAILURE) return(-1);
5761         break;
5762       case(EXTENT):
5763         if(getDouble(&(web->extent.minx)) == -1) return(-1);
5764         if(getDouble(&(web->extent.miny)) == -1) return(-1);
5765         if(getDouble(&(web->extent.maxx)) == -1) return(-1);
5766         if(getDouble(&(web->extent.maxy)) == -1) return(-1);
5767         if (!MS_VALID_EXTENT(web->extent)) {
5768           msSetError(MS_MISCERR, "Given web extent is invalid. Check that it is in the form: minx, miny, maxx, maxy", "loadWeb()");
5769           return(-1);
5770         }
5771         break;
5772       case(FOOTER):
5773         if(getString(&web->footer) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
5774         if(msyysource == MS_URL_TOKENS) {
5775           if(msValidateParameter(web->footer, msLookupHashTable(&(web->validation), "footer"), map->templatepattern, NULL, NULL) != MS_SUCCESS) {
5776             msSetError(MS_MISCERR, "URL-based FOOTER configuration failed pattern validation." , "loadWeb()");
5777             msFree(web->footer);
5778             web->footer=NULL;
5779             return(-1);
5780           }
5781         }
5782         break;
5783       case(HEADER):
5784         if(getString(&web->header) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
5785         if(msyysource == MS_URL_TOKENS) {
5786           if(msValidateParameter(web->header, msLookupHashTable(&(web->validation), "header"), map->templatepattern, NULL, NULL) != MS_SUCCESS) {
5787             msSetError(MS_MISCERR, "URL-based HEADER configuration failed pattern validation." , "loadWeb()");
5788             msFree(web->header);
5789             web->header=NULL;
5790             return(-1);
5791           }
5792         }
5793         break;
5794       case(IMAGEPATH):
5795         if(getString(&web->imagepath) == MS_FAILURE) return(-1);
5796         break;
5797       case(TEMPPATH):
5798         if(getString(&web->temppath) == MS_FAILURE) return(-1);
5799         break;
5800       case(IMAGEURL):
5801         if(getString(&web->imageurl) == MS_FAILURE) return(-1);
5802         break;
5803       case(LEGENDFORMAT): /* change to use validation in 6.0 */
5804         free(web->legendformat);
5805         web->legendformat = NULL; /* there is a default */
5806         if(getString(&web->legendformat) == MS_FAILURE) return(-1);
5807         break;
5808       case(LOG):
5809         if(getString(&web->log) == MS_FAILURE) return(-1);
5810         break;
5811       case(MAXSCALE):
5812       case(MAXSCALEDENOM):
5813         if(getDouble(&web->maxscaledenom) == -1) return(-1);
5814         break;
5815       case(MAXTEMPLATE):
5816         if(getString(&web->maxtemplate) == MS_FAILURE) return(-1);
5817         break;
5818       case(METADATA):
5819         if(loadHashTable(&(web->metadata)) != MS_SUCCESS) return(-1);
5820         break;
5821       case(MINSCALE):
5822       case(MINSCALEDENOM):
5823         if(getDouble(&web->minscaledenom) == -1) return(-1);
5824         break;
5825       case(MINTEMPLATE):
5826         if(getString(&web->mintemplate) == MS_FAILURE) return(-1);
5827         break;
5828       case(QUERYFORMAT): /* change to use validation in 6.0 */
5829         free(web->queryformat);
5830         web->queryformat = NULL; /* there is a default */
5831         if(getString(&web->queryformat) == MS_FAILURE) return(-1);
5832         break;
5833       case(TEMPLATE):
5834         if(getString(&web->template) == MS_FAILURE) return(-1); /* getString() cleans up previously allocated string */
5835         if(msyysource == MS_URL_TOKENS) {
5836           if(msValidateParameter(web->template, msLookupHashTable(&(web->validation), "template"), map->templatepattern, NULL, NULL) != MS_SUCCESS) {
5837             msSetError(MS_MISCERR, "URL-based TEMPLATE configuration failed pattern validation." , "loadWeb()");
5838             msFree(web->template);
5839             web->template=NULL;
5840             return(-1);
5841           }
5842         }
5843         break;
5844       case(VALIDATION):
5845         if(loadHashTable(&(web->validation)) != MS_SUCCESS) return(-1);
5846         break;
5847       default:
5848         if(strlen(msyystring_buffer) > 0) {
5849           msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadWeb()", msyystring_buffer, msyylineno);
5850           return(-1);
5851         } else {
5852           return(0); /* end of a string, not an error */
5853         }
5854     }
5855   }
5856 }
5857 
msUpdateWebFromString(webObj * web,char * string,int url_string)5858 int msUpdateWebFromString(webObj *web, char *string, int url_string)
5859 {
5860   if(!web || !string) return MS_FAILURE;
5861 
5862   msAcquireLock( TLOCK_PARSER );
5863 
5864   if(url_string)
5865     msyystate = MS_TOKENIZE_URL_STRING;
5866   else
5867     msyystate = MS_TOKENIZE_STRING;
5868   msyystring = string;
5869   msyylex(); /* sets things up, but doesn't process any tokens */
5870 
5871   msyylineno = 1; /* start at line 1 */
5872 
5873   if(loadWeb(web, web->map) == -1) {
5874     msReleaseLock( TLOCK_PARSER );
5875     return MS_FAILURE; /* parse error */;
5876   }
5877   msReleaseLock( TLOCK_PARSER );
5878 
5879   msyylex_destroy();
5880   return MS_SUCCESS;
5881 }
5882 
5883 /*
5884 ** Initialize, load and free a mapObj structure
5885 **
5886 ** This really belongs in mapobject.c, but currently it also depends on
5887 ** lots of other init methods in this file.
5888 */
5889 
initMap(mapObj * map)5890 int initMap(mapObj *map)
5891 {
5892   int i=0;
5893   MS_REFCNT_INIT(map);
5894 
5895   map->debug = (int)msGetGlobalDebugLevel();
5896 
5897   /* Set maxlayers = 0, layers[] and layerorder[] will be allocated as needed,
5898    * on the first call to msGrowMapLayers()
5899    */
5900   map->numlayers = 0;
5901   map->maxlayers = 0;
5902   map->layers = NULL;
5903   map->layerorder = NULL; /* used to modify the order in which the layers are drawn */
5904 
5905   map->status = MS_ON;
5906   map->name = msStrdup("MS");
5907   map->extent.minx = map->extent.miny = map->extent.maxx = map->extent.maxy = -1.0;
5908 
5909   map->scaledenom = -1.0;
5910   map->resolution = MS_DEFAULT_RESOLUTION; /* pixels per inch */
5911   map->defresolution = MS_DEFAULT_RESOLUTION; /* pixels per inch */
5912 
5913   map->height = map->width = -1;
5914   map->maxsize = MS_MAXIMAGESIZE_DEFAULT;
5915 
5916   map->gt.need_geotransform = MS_FALSE;
5917   map->gt.rotation_angle = 0.0;
5918 
5919   map->units = MS_METERS;
5920   map->cellsize = 0;
5921   map->shapepath = NULL;
5922   map->mappath = NULL;
5923   map->sldurl = NULL;
5924 
5925   MS_INIT_COLOR(map->imagecolor, 255,255,255,255); /* white */
5926 
5927   map->numoutputformats = 0;
5928   map->outputformatlist = NULL;
5929   map->outputformat = NULL;
5930 
5931   /* map->configoptions = msCreateHashTable();; */
5932   initHashTable(&(map->configoptions));
5933 
5934   map->imagetype = NULL;
5935 
5936   map->palette.numcolors = 0;
5937 
5938   map->transparent = MS_NOOVERRIDE;
5939   map->interlace = MS_NOOVERRIDE;
5940   map->imagequality = MS_NOOVERRIDE;
5941 
5942   for(i=0; i<MS_MAX_LABEL_PRIORITY; i++) {
5943     map->labelcache.slots[i].labels = NULL; /* cache is initialize at draw time */
5944     map->labelcache.slots[i].cachesize = 0;
5945     map->labelcache.slots[i].numlabels = 0;
5946     map->labelcache.slots[i].markers = NULL;
5947     map->labelcache.slots[i].markercachesize = 0;
5948     map->labelcache.slots[i].nummarkers = 0;
5949   }
5950 
5951   map->fontset.filename = NULL;
5952   map->fontset.numfonts = 0;
5953 
5954   /* map->fontset.fonts = NULL; */
5955   initHashTable(&(map->fontset.fonts));
5956 
5957   msInitSymbolSet(&map->symbolset);
5958   map->symbolset.fontset =  &(map->fontset);
5959   map->symbolset.map = map;
5960 
5961   initLegend(&map->legend);
5962   initScalebar(&map->scalebar);
5963   initWeb(&map->web);
5964   initReferenceMap(&map->reference);
5965   initQueryMap(&map->querymap);
5966 
5967   map->projContext = msProjectionContextGetFromPool();
5968 
5969   if(msInitProjection(&(map->projection)) == -1)
5970     return(-1);
5971   if(msInitProjection(&(map->latlon)) == -1)
5972     return(-1);
5973 
5974   msProjectionSetContext(&(map->projection), map->projContext);
5975   msProjectionSetContext(&(map->latlon), map->projContext);
5976 
5977   /* initialize a default "geographic" projection */
5978   map->latlon.numargs = 2;
5979   map->latlon.args[0] = msStrdup("proj=latlong");
5980   map->latlon.args[1] = msStrdup("ellps=WGS84"); /* probably want a different ellipsoid */
5981   if(msProcessProjection(&(map->latlon)) == -1) return(-1);
5982 
5983   map->templatepattern = map->datapattern = NULL;
5984 
5985   /* Encryption key information - see mapcrypto.c */
5986   map->encryption_key_loaded = MS_FALSE;
5987 
5988   msInitQuery(&(map->query));
5989 
5990 #ifdef USE_V8_MAPSCRIPT
5991   map->v8context = NULL;
5992 #endif
5993 
5994   return(0);
5995 }
5996 
5997 /*
5998 ** Ensure there is at least one free entry in the layers and layerorder
5999 ** arrays of this mapObj. Grow the allocated layers/layerorder arrays if
6000 ** necessary and allocate a new layer for layers[numlayers] if there is
6001 ** not already one, setting its contents to all zero bytes (i.e. does not
6002 ** call initLayer() on it).
6003 **
6004 ** This function is safe to use for the initial allocation of the layers[]
6005 ** and layerorder[] arrays as well (i.e. when maxlayers==0 and layers==NULL)
6006 **
6007 ** Returns a reference to the new layerObj on success, NULL on error.
6008 */
msGrowMapLayers(mapObj * map)6009 layerObj *msGrowMapLayers( mapObj *map )
6010 {
6011   /* Do we need to increase the size of layers/layerorder by
6012    * MS_LAYER_ALLOCSIZE?
6013    */
6014   if (map->numlayers == map->maxlayers) {
6015     layerObj **newLayersPtr;
6016     int *newLayerorderPtr;
6017     int i, newsize;
6018 
6019     newsize = map->maxlayers + MS_LAYER_ALLOCSIZE;
6020 
6021     /* Alloc/realloc layers */
6022     newLayersPtr = (layerObj**)realloc(map->layers,
6023                                        newsize*sizeof(layerObj*));
6024     MS_CHECK_ALLOC(newLayersPtr, newsize*sizeof(layerObj*), NULL);
6025 
6026     map->layers = newLayersPtr;
6027 
6028     /* Alloc/realloc layerorder */
6029     newLayerorderPtr = (int *)realloc(map->layerorder,
6030                                       newsize*sizeof(int));
6031     MS_CHECK_ALLOC(newLayerorderPtr, newsize*sizeof(int), NULL);
6032 
6033     map->layerorder = newLayerorderPtr;
6034 
6035     map->maxlayers = newsize;
6036     for(i=map->numlayers; i<map->maxlayers; i++) {
6037       map->layers[i] = NULL;
6038       map->layerorder[i] = 0;
6039     }
6040   }
6041 
6042   if (map->layers[map->numlayers]==NULL) {
6043     map->layers[map->numlayers]=(layerObj*)calloc(1,sizeof(layerObj));
6044     MS_CHECK_ALLOC(map->layers[map->numlayers], sizeof(layerObj), NULL);
6045   }
6046 
6047   return map->layers[map->numlayers];
6048 }
6049 
6050 
msFreeLabelCacheSlot(labelCacheSlotObj * cacheslot)6051 int msFreeLabelCacheSlot(labelCacheSlotObj *cacheslot)
6052 {
6053   int i, j;
6054 
6055   /* free the labels */
6056   if (cacheslot->labels) {
6057     for(i=0; i<cacheslot->numlabels; i++) {
6058 
6059       for(j=0; j<cacheslot->labels[i].numtextsymbols; j++) {
6060         freeTextSymbol(cacheslot->labels[i].textsymbols[j]);
6061         free(cacheslot->labels[i].textsymbols[j]);
6062       }
6063       msFree(cacheslot->labels[i].textsymbols);
6064 
6065 #ifdef include_deprecated
6066       for(j=0; j<cacheslot->labels[i].numstyles; j++) freeStyle(&(cacheslot->labels[i].styles[j]));
6067       msFree(cacheslot->labels[i].styles);
6068 #endif
6069       if(cacheslot->labels[i].leaderline) {
6070         msFree(cacheslot->labels[i].leaderline->point);
6071         msFree(cacheslot->labels[i].leaderline);
6072         msFree(cacheslot->labels[i].leaderbbox);
6073       }
6074     }
6075   }
6076   msFree(cacheslot->labels);
6077   cacheslot->labels = NULL;
6078   cacheslot->cachesize = 0;
6079   cacheslot->numlabels = 0;
6080 
6081   msFree(cacheslot->markers);
6082   cacheslot->markers = NULL;
6083   cacheslot->markercachesize = 0;
6084   cacheslot->nummarkers = 0;
6085 
6086   return(MS_SUCCESS);
6087 }
6088 
msFreeLabelCache(labelCacheObj * cache)6089 int msFreeLabelCache(labelCacheObj *cache)
6090 {
6091   int p;
6092 
6093   for(p=0; p<MS_MAX_LABEL_PRIORITY; p++) {
6094     if (msFreeLabelCacheSlot(&(cache->slots[p])) != MS_SUCCESS)
6095       return MS_FAILURE;
6096   }
6097 
6098   cache->num_allocated_rendered_members = cache->num_rendered_members = 0;
6099   msFree(cache->rendered_text_symbols);
6100 
6101   return MS_SUCCESS;
6102 }
6103 
msInitLabelCacheSlot(labelCacheSlotObj * cacheslot)6104 int msInitLabelCacheSlot(labelCacheSlotObj *cacheslot)
6105 {
6106 
6107   if(cacheslot->labels || cacheslot->markers)
6108     msFreeLabelCacheSlot(cacheslot);
6109 
6110   cacheslot->labels = (labelCacheMemberObj *)malloc(sizeof(labelCacheMemberObj)*MS_LABELCACHEINITSIZE);
6111   MS_CHECK_ALLOC(cacheslot->labels, sizeof(labelCacheMemberObj)*MS_LABELCACHEINITSIZE, MS_FAILURE);
6112 
6113   cacheslot->cachesize = MS_LABELCACHEINITSIZE;
6114   cacheslot->numlabels = 0;
6115 
6116   cacheslot->markers = (markerCacheMemberObj *)malloc(sizeof(markerCacheMemberObj)*MS_LABELCACHEINITSIZE);
6117   MS_CHECK_ALLOC(cacheslot->markers, sizeof(markerCacheMemberObj)*MS_LABELCACHEINITSIZE, MS_FAILURE);
6118 
6119   cacheslot->markercachesize = MS_LABELCACHEINITSIZE;
6120   cacheslot->nummarkers = 0;
6121 
6122   return(MS_SUCCESS);
6123 }
6124 
msInitLabelCache(labelCacheObj * cache)6125 int msInitLabelCache(labelCacheObj *cache)
6126 {
6127   int p;
6128 
6129   for(p=0; p<MS_MAX_LABEL_PRIORITY; p++) {
6130     if (msInitLabelCacheSlot(&(cache->slots[p])) != MS_SUCCESS)
6131       return MS_FAILURE;
6132   }
6133   cache->gutter = 0;
6134   cache->num_allocated_rendered_members = cache->num_rendered_members = 0;
6135   cache->rendered_text_symbols = NULL;
6136 
6137   return MS_SUCCESS;
6138 }
6139 
writeMap(FILE * stream,int indent,mapObj * map)6140 static void writeMap(FILE *stream, int indent, mapObj *map)
6141 {
6142   int i;
6143   colorObj c;
6144 
6145   writeBlockBegin(stream, indent, "MAP");
6146   writeNumber(stream, indent, "ANGLE", 0, map->gt.rotation_angle);
6147   writeHashTableInline(stream, indent, "CONFIG", &(map->configoptions));
6148   writeString(stream, indent, "DATAPATTERN", NULL, map->datapattern); /* depricated */
6149   writeNumber(stream, indent, "DEBUG", 0, map->debug);
6150   writeNumber(stream, indent, "DEFRESOLUTION", 72.0, map->defresolution);
6151   writeExtent(stream, indent, "EXTENT", map->extent);
6152   writeString(stream, indent, "FONTSET", NULL, map->fontset.filename);
6153   MS_INIT_COLOR(c,255,255,255,255);
6154   writeColor(stream, indent, "IMAGECOLOR", &c, &(map->imagecolor));
6155   writeString(stream, indent, "IMAGETYPE", NULL, map->imagetype);
6156   writeKeyword(stream, indent, "INTERLACE", map->interlace, 2, MS_TRUE, "TRUE", MS_FALSE, "FALSE");
6157   writeNumber(stream, indent, "MAXSIZE", MS_MAXIMAGESIZE_DEFAULT, map->maxsize);
6158   writeString(stream, indent, "NAME", NULL, map->name);
6159   writeNumber(stream, indent, "RESOLUTION", 72.0, map->resolution);
6160   writeString(stream, indent, "SHAPEPATH", NULL, map->shapepath);
6161   writeDimension(stream, indent, "SIZE", map->width, map->height, NULL, NULL);
6162   writeKeyword(stream, indent, "STATUS", map->status, 2, MS_ON, "ON", MS_OFF, "OFF");
6163   writeString(stream, indent, "SYMBOLSET", NULL, map->symbolset.filename);
6164   writeString(stream, indent, "TEMPLATEPATTERN", NULL, map->templatepattern); /* depricated */
6165   writeKeyword(stream, indent, "TRANSPARENT", map->transparent, 2, MS_TRUE, "TRUE", MS_FALSE, "FALSE");
6166   writeKeyword(stream, indent, "UNITS", map->units, 7, MS_INCHES, "INCHES", MS_FEET ,"FEET", MS_MILES, "MILES", MS_METERS, "METERS", MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES, "NAUTICALMILES", MS_DD, "DD");
6167   writeLineFeed(stream);
6168 
6169   writeOutputformat(stream, indent, map);
6170 
6171   /* write symbol with INLINE tag in mapfile */
6172   for(i=0; i<map->symbolset.numsymbols; i++) {
6173     if(map->symbolset.symbol[i]->inmapfile) writeSymbol(map->symbolset.symbol[i], stream);
6174   }
6175 
6176   writeProjection(stream, indent, &(map->projection));
6177 
6178   writeLegend(stream, indent, &(map->legend));
6179   writeQueryMap(stream, indent, &(map->querymap));
6180   writeReferenceMap(stream, indent, &(map->reference));
6181   writeScalebar(stream, indent, &(map->scalebar));
6182   writeWeb(stream, indent, &(map->web));
6183 
6184   for(i=0; i<map->numlayers; i++)
6185     writeLayer(stream, indent, GET_LAYER(map, map->layerorder[i]));
6186 
6187   writeBlockEnd(stream, indent, "MAP");
6188 }
6189 
msWriteMapToString(mapObj * map)6190 char* msWriteMapToString(mapObj *map)
6191 {
6192   msIOContext  context;
6193   msIOBuffer buffer;
6194 
6195   context.label = NULL;
6196   context.write_channel = MS_TRUE;
6197   context.readWriteFunc = msIO_bufferWrite;
6198   context.cbData = &buffer;
6199   buffer.data = NULL;
6200   buffer.data_len = 0;
6201   buffer.data_offset = 0;
6202 
6203   msIO_installHandlers( NULL, &context, NULL );
6204 
6205   writeMap(stdout, 0, map);
6206   msIO_bufferWrite( &buffer, "", 1 );
6207 
6208   msIO_installHandlers( NULL, NULL, NULL );
6209 
6210   return (char*)buffer.data;
6211 }
6212 
msSaveMap(mapObj * map,char * filename)6213 int msSaveMap(mapObj *map, char *filename)
6214 {
6215   FILE *stream;
6216   char szPath[MS_MAXPATHLEN];
6217 
6218   if(!map) {
6219     msSetError(MS_MISCERR, "Map is undefined.", "msSaveMap()");
6220     return(-1);
6221   }
6222 
6223   if(!filename) {
6224     msSetError(MS_MISCERR, "Filename is undefined.", "msSaveMap()");
6225     return(-1);
6226   }
6227 
6228   stream = fopen(msBuildPath(szPath, map->mappath, filename), "w");
6229   if(!stream) {
6230     msSetError(MS_IOERR, "(%s)", "msSaveMap()", filename);
6231     return(-1);
6232   }
6233 
6234   writeMap(stream, 0, map);
6235   fclose(stream);
6236 
6237   return(0);
6238 }
6239 
loadMapInternal(mapObj * map)6240 static int loadMapInternal(mapObj *map)
6241 {
6242   int foundMapToken=MS_FALSE;
6243   int foundBomToken = MS_FALSE;
6244   int token;
6245 
6246   for(;;) {
6247 
6248     token = msyylex();
6249 
6250     if(!foundBomToken && token == BOM) {
6251       foundBomToken = MS_TRUE;
6252       if(!foundMapToken) {
6253         continue; /*skip a leading bom*/
6254       }
6255     }
6256     if(!foundMapToken && token != MAP) {
6257       msSetError(MS_IDENTERR, "First token must be MAP, this doesn't look like a mapfile.", "msLoadMap()");
6258       return(MS_FAILURE);
6259     }
6260 
6261     switch(token) {
6262 
6263       case(CONFIG): {
6264         char *key=NULL, *value=NULL;
6265 
6266         if( getString(&key) == MS_FAILURE )
6267           return MS_FAILURE;
6268 
6269         if( getString(&value) == MS_FAILURE ) {
6270           free(key);
6271           return MS_FAILURE;
6272         }
6273 
6274         if (msSetConfigOption( map, key, value ) == MS_FAILURE) {
6275           free(key);
6276           free(value);
6277           return MS_FAILURE;
6278         }
6279 
6280         free( key );
6281         free( value );
6282       }
6283       break;
6284 
6285       case(DATAPATTERN):
6286         if(getString(&map->datapattern) == MS_FAILURE) return MS_FAILURE;
6287         break;
6288       case(DEBUG):
6289         if((map->debug = getSymbol(3, MS_ON,MS_OFF, MS_NUMBER)) == -1) return MS_FAILURE;
6290         if(map->debug == MS_NUMBER) map->debug = (int) msyynumber;
6291         break;
6292       case(END):
6293         if(msyyin) {
6294           fclose(msyyin);
6295           msyyin = NULL;
6296         }
6297 
6298         /*** Make config options current ***/
6299         msApplyMapConfigOptions( map );
6300 
6301         /*** Compute rotated extent info if applicable ***/
6302         msMapComputeGeotransform( map );
6303 
6304         /*** OUTPUTFORMAT related setup ***/
6305         if( msPostMapParseOutputFormatSetup( map ) == MS_FAILURE )
6306           return MS_FAILURE;
6307 
6308         if(loadSymbolSet(&(map->symbolset), map) == -1) return MS_FAILURE;
6309 
6310         if (resolveSymbolNames(map) == MS_FAILURE) return MS_FAILURE;
6311 
6312 
6313         if(msLoadFontSet(&(map->fontset), map) == -1) return MS_FAILURE;
6314 
6315         return MS_SUCCESS;
6316         break;
6317       case(EOF):
6318         msSetError(MS_EOFERR, NULL, "msLoadMap()");
6319         return MS_FAILURE;
6320       case(EXTENT): {
6321         if(getDouble(&(map->extent.minx)) == -1) return MS_FAILURE;
6322         if(getDouble(&(map->extent.miny)) == -1) return MS_FAILURE;
6323         if(getDouble(&(map->extent.maxx)) == -1) return MS_FAILURE;
6324         if(getDouble(&(map->extent.maxy)) == -1) return MS_FAILURE;
6325         if (!MS_VALID_EXTENT(map->extent)) {
6326           msSetError(MS_MISCERR, "Given map extent is invalid. Check that it " \
6327                      "is in the form: minx, miny, maxx, maxy", "loadMapInternal()");
6328           return MS_FAILURE;
6329         }
6330       }
6331       break;
6332       case(ANGLE): {
6333         double rotation_angle;
6334         if(getDouble(&(rotation_angle)) == -1) return MS_FAILURE;
6335         msMapSetRotation( map, rotation_angle );
6336       }
6337       break;
6338       case(TEMPLATEPATTERN):
6339         if(getString(&map->templatepattern) == MS_FAILURE) return MS_FAILURE;
6340         break;
6341       case(FONTSET):
6342         if(getString(&map->fontset.filename) == MS_FAILURE) return MS_FAILURE;
6343         break;
6344       case(IMAGECOLOR):
6345         if(loadColor(&(map->imagecolor), NULL) != MS_SUCCESS) return MS_FAILURE;
6346         break;
6347       case(IMAGEQUALITY):
6348         if(getInteger(&(map->imagequality)) == -1) return MS_FAILURE;
6349         break;
6350       case(IMAGETYPE):
6351         msFree(map->imagetype);
6352         map->imagetype = getToken();
6353         break;
6354       case(INTERLACE):
6355         if((map->interlace = getSymbol(2, MS_ON,MS_OFF)) == -1) return MS_FAILURE;
6356         break;
6357       case(LATLON):
6358         msFreeProjectionExceptContext(&map->latlon);
6359         if(loadProjection(&map->latlon) == -1) return MS_FAILURE;
6360         break;
6361       case(LAYER):
6362         if(msGrowMapLayers(map) == NULL)
6363           return MS_FAILURE;
6364         if(initLayer((GET_LAYER(map, map->numlayers)), map) == -1) return MS_FAILURE;
6365         if(loadLayer((GET_LAYER(map, map->numlayers)), map) == -1) return MS_FAILURE;
6366         GET_LAYER(map, map->numlayers)->index = map->numlayers; /* save the index */
6367         /* Update the layer order list with the layer's index. */
6368         map->layerorder[map->numlayers] = map->numlayers;
6369         map->numlayers++;
6370         break;
6371       case(OUTPUTFORMAT):
6372         if(loadOutputFormat(map) == -1) return MS_FAILURE;
6373         break;
6374       case(LEGEND):
6375         if(loadLegend(&(map->legend), map) == -1) return MS_FAILURE;
6376         break;
6377       case(MAP):
6378         foundMapToken = MS_TRUE;
6379         break;
6380       case(MAXSIZE):
6381         if(getInteger(&(map->maxsize)) == -1) return MS_FAILURE;
6382         break;
6383       case(NAME):
6384         free(map->name);
6385         map->name = NULL; /* erase default */
6386         if(getString(&map->name) == MS_FAILURE) return MS_FAILURE;
6387         break;
6388       case(PROJECTION):
6389         if(loadProjection(&map->projection) == -1) return MS_FAILURE;
6390         break;
6391       case(QUERYMAP):
6392         if(loadQueryMap(&(map->querymap)) == -1) return MS_FAILURE;
6393         break;
6394       case(REFERENCE):
6395         if(loadReferenceMap(&(map->reference), map) == -1) return MS_FAILURE;
6396         break;
6397       case(RESOLUTION):
6398         if(getDouble(&(map->resolution)) == -1) return MS_FAILURE;
6399         break;
6400       case(DEFRESOLUTION):
6401         if(getDouble(&(map->defresolution)) == -1) return MS_FAILURE;
6402         break;
6403       case(SCALE):
6404       case(SCALEDENOM):
6405         if(getDouble(&(map->scaledenom)) == -1) return MS_FAILURE;
6406         break;
6407       case(SCALEBAR):
6408         if(loadScalebar(&(map->scalebar)) == -1) return MS_FAILURE;
6409         break;
6410       case(SHAPEPATH):
6411         if(getString(&map->shapepath) == MS_FAILURE) return MS_FAILURE;
6412         break;
6413       case(SIZE):
6414         if(getInteger(&(map->width)) == -1) return MS_FAILURE;
6415         if(getInteger(&(map->height)) == -1) return MS_FAILURE;
6416         break;
6417       case(STATUS):
6418         if((map->status = getSymbol(2, MS_ON,MS_OFF)) == -1) return MS_FAILURE;
6419         break;
6420       case(SYMBOL):
6421         if(msGrowSymbolSet(&(map->symbolset)) == NULL)
6422           return MS_FAILURE;
6423         if((loadSymbol(map->symbolset.symbol[map->symbolset.numsymbols], map->mappath) == -1)) return MS_FAILURE;
6424         map->symbolset.symbol[map->symbolset.numsymbols]->inmapfile = MS_TRUE;
6425         map->symbolset.numsymbols++;
6426         break;
6427       case(SYMBOLSET):
6428         if(getString(&map->symbolset.filename) == MS_FAILURE) return MS_FAILURE;
6429         break;
6430       case(TRANSPARENT):
6431         if((map->transparent = getSymbol(2, MS_ON,MS_OFF)) == -1) return MS_FAILURE;
6432         break;
6433       case(UNITS):
6434         if((int)(map->units = getSymbol(7, MS_INCHES,MS_FEET,MS_MILES,MS_METERS,MS_KILOMETERS,MS_NAUTICALMILES,MS_DD)) == -1) return MS_FAILURE;
6435         break;
6436       case(WEB):
6437         if(loadWeb(&(map->web), map) == -1) return MS_FAILURE;
6438         break;
6439       default:
6440         msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "msLoadMap()", msyystring_buffer, msyylineno);
6441         return MS_FAILURE;
6442     }
6443   } /* next token */
6444 }
6445 
6446 /*
6447 ** Sets up string-based mapfile loading and calls loadMapInternal to do the work.
6448 */
msLoadMapFromString(char * buffer,char * new_mappath)6449 mapObj *msLoadMapFromString(char *buffer, char *new_mappath)
6450 {
6451   mapObj *map;
6452   struct mstimeval starttime = {0}, endtime = {0};
6453   char szPath[MS_MAXPATHLEN], szCWDPath[MS_MAXPATHLEN];
6454   char *mappath=NULL;
6455   int debuglevel;
6456 
6457   debuglevel = (int)msGetGlobalDebugLevel();
6458 
6459   if (debuglevel >= MS_DEBUGLEVEL_TUNING) {
6460     /* In debug mode, track time spent loading/parsing mapfile. */
6461     msGettimeofday(&starttime, NULL);
6462   }
6463 
6464   if(!buffer) {
6465     msSetError(MS_MISCERR, "No buffer to load.", "msLoadMapFromString()");
6466     return(NULL);
6467   }
6468 
6469   /*
6470   ** Allocate mapObj structure
6471   */
6472   map = (mapObj *)calloc(sizeof(mapObj),1);
6473   MS_CHECK_ALLOC(map, sizeof(mapObj), NULL);
6474 
6475   if(initMap(map) == -1) { /* initialize this map */
6476     msFreeMap(map);
6477     return(NULL);
6478   }
6479 
6480   msAcquireLock( TLOCK_PARSER ); /* might need to move this lock a bit higher, yup (bug 2108) */
6481 
6482   msyystate = MS_TOKENIZE_STRING;
6483   msyystring = buffer;
6484   msyylex(); /* sets things up, but doesn't process any tokens */
6485 
6486   msyylineno = 1; /* start at line 1 (do lines mean anything here?) */
6487 
6488   /* If new_mappath is provided then use it, otherwise use the CWD */
6489   if(NULL == getcwd(szCWDPath, MS_MAXPATHLEN)) {
6490     msSetError(MS_MISCERR, "getcwd() returned a too long path", "msLoadMapFromString()");
6491     msFreeMap(map);
6492     msReleaseLock( TLOCK_PARSER );
6493   }
6494   if (new_mappath) {
6495     mappath = msStrdup(new_mappath);
6496     map->mappath = msStrdup(msBuildPath(szPath, szCWDPath, mappath));
6497   } else
6498     map->mappath = msStrdup(szCWDPath);
6499 
6500   msyybasepath = map->mappath; /* for INCLUDEs */
6501 
6502   if(loadMapInternal(map) != MS_SUCCESS) {
6503     msFreeMap(map);
6504     msReleaseLock( TLOCK_PARSER );
6505     if(mappath != NULL) free(mappath);
6506     return NULL;
6507   }
6508 
6509   if (mappath != NULL) free(mappath);
6510   msyylex_destroy();
6511 
6512   msReleaseLock( TLOCK_PARSER );
6513 
6514   if (debuglevel >= MS_DEBUGLEVEL_TUNING) {
6515     /* In debug mode, report time spent loading/parsing mapfile. */
6516     msGettimeofday(&endtime, NULL);
6517     msDebug("msLoadMap(): %.3fs\n",
6518             (endtime.tv_sec+endtime.tv_usec/1.0e6)-
6519             (starttime.tv_sec+starttime.tv_usec/1.0e6) );
6520   }
6521 
6522   if (resolveSymbolNames(map) == MS_FAILURE) return NULL;
6523 
6524   return map;
6525 }
6526 
6527 /*
6528 ** Sets up file-based mapfile loading and calls loadMapInternal to do the work.
6529 */
msLoadMap(const char * filename,const char * new_mappath)6530 mapObj *msLoadMap(const char *filename, const char *new_mappath)
6531 {
6532   mapObj *map;
6533   struct mstimeval starttime={0}, endtime={0};
6534   char szPath[MS_MAXPATHLEN], szCWDPath[MS_MAXPATHLEN];
6535   int debuglevel;
6536 
6537   debuglevel = (int)msGetGlobalDebugLevel();
6538 
6539   if (debuglevel >= MS_DEBUGLEVEL_TUNING) {
6540     /* In debug mode, track time spent loading/parsing mapfile. */
6541     msGettimeofday(&starttime, NULL);
6542   }
6543 
6544   if(!filename) {
6545     msSetError(MS_MISCERR, "Filename is undefined.", "msLoadMap()");
6546     return(NULL);
6547   }
6548 
6549   if(getenv("MS_MAPFILE_PATTERN")) { /* user override */
6550     if(msEvalRegex(getenv("MS_MAPFILE_PATTERN"), filename) != MS_TRUE) {
6551       msSetError(MS_REGEXERR, "MS_MAPFILE_PATTERN validation failed." , "msLoadMap()");
6552       return(NULL);
6553     }
6554   } else { /* check the default */
6555     if(msEvalRegex(MS_DEFAULT_MAPFILE_PATTERN, filename) != MS_TRUE) {
6556       msSetError(MS_REGEXERR, "MS_DEFAULT_MAPFILE_PATTERN validation failed." , "msLoadMap()");
6557       return(NULL);
6558     }
6559   }
6560 
6561   /*
6562   ** Allocate mapObj structure
6563   */
6564   map = (mapObj *)calloc(sizeof(mapObj),1);
6565   MS_CHECK_ALLOC(map, sizeof(mapObj), NULL);
6566 
6567   if(initMap(map) == -1) { /* initialize this map */
6568     msFreeMap(map);
6569     return(NULL);
6570   }
6571 
6572   msAcquireLock( TLOCK_PARSER );  /* Steve: might need to move this lock a bit higher; Umberto: done */
6573 
6574 #ifdef USE_XMLMAPFILE
6575   /* If the mapfile is an xml mapfile, transform it */
6576   if ((getenv("MS_XMLMAPFILE_XSLT")) &&
6577       (msEvalRegex(MS_DEFAULT_XMLMAPFILE_PATTERN, filename) == MS_TRUE)) {
6578 
6579     msyyin = tmpfile();
6580     if (msyyin == NULL) {
6581       msSetError(MS_IOERR, "tmpfile() failed to create temporary file", "msLoadMap()");
6582       msReleaseLock( TLOCK_PARSER );
6583     }
6584 
6585     if (msTransformXmlMapfile(getenv("MS_XMLMAPFILE_XSLT"), filename, msyyin) != MS_SUCCESS) {
6586       fclose(msyyin);
6587       return NULL;
6588     }
6589     fseek ( msyyin , 0 , SEEK_SET );
6590   } else {
6591 #endif
6592     if((msyyin = fopen(filename,"r")) == NULL) {
6593       msSetError(MS_IOERR, "(%s)", "msLoadMap()", filename);
6594       msReleaseLock( TLOCK_PARSER );
6595       return NULL;
6596     }
6597 #ifdef USE_XMLMAPFILE
6598   }
6599 #endif
6600 
6601   msyystate = MS_TOKENIZE_FILE;
6602   msyylex(); /* sets things up, but doesn't process any tokens */
6603 
6604   msyyrestart(msyyin); /* start at line begining, line 1 */
6605   msyylineno = 1;
6606 
6607   /* If new_mappath is provided then use it, otherwise use the location */
6608   /* of the mapfile as the default path */
6609   if(NULL == getcwd(szCWDPath, MS_MAXPATHLEN)) {
6610     msSetError(MS_MISCERR, "getcwd() returned a too long path", "msLoadMap()");
6611     msFreeMap(map);
6612     msReleaseLock( TLOCK_PARSER );
6613   }
6614 
6615   if (new_mappath)
6616     map->mappath = msStrdup(msBuildPath(szPath, szCWDPath, new_mappath));
6617   else {
6618     char *path = msGetPath(filename);
6619     map->mappath = msStrdup(msBuildPath(szPath, szCWDPath, path));
6620     free( path );
6621   }
6622 
6623   msyybasepath = map->mappath; /* for INCLUDEs */
6624 
6625   if(loadMapInternal(map) != MS_SUCCESS) {
6626     msFreeMap(map);
6627     msReleaseLock( TLOCK_PARSER );
6628     if( msyyin ) {
6629       fclose(msyyin);
6630       msyyin = NULL;
6631     }
6632     return NULL;
6633   }
6634   msReleaseLock( TLOCK_PARSER );
6635 
6636   if (debuglevel >= MS_DEBUGLEVEL_TUNING) {
6637     /* In debug mode, report time spent loading/parsing mapfile. */
6638     msGettimeofday(&endtime, NULL);
6639     msDebug("msLoadMap(): %.3fs\n",
6640             (endtime.tv_sec+endtime.tv_usec/1.0e6)-
6641             (starttime.tv_sec+starttime.tv_usec/1.0e6) );
6642   }
6643 
6644   return map;
6645 }
6646 
6647 /*
6648 ** Loads mapfile snippets via a URL (only via the CGI so don't worry about thread locks)
6649 */
msUpdateMapFromURL(mapObj * map,char * variable,char * string)6650 int msUpdateMapFromURL(mapObj *map, char *variable, char *string)
6651 {
6652   int i, j, k, s;
6653   errorObj *ms_error;
6654 
6655   /* make sure this configuration can be modified */
6656   if(msLookupHashTable(&(map->web.validation), "immutable"))
6657     return(MS_SUCCESS); /* fail silently */
6658 
6659   msyystate = MS_TOKENIZE_URL_VARIABLE; /* set lexer state and input to tokenize */
6660   msyystring = variable;
6661   msyylineno = 1;
6662 
6663   ms_error = msGetErrorObj();
6664   ms_error->code = MS_NOERR; /* init error code */
6665 
6666   switch(msyylex()) {
6667     case(MAP):
6668       switch(msyylex()) {
6669         case(EXTENT):
6670           msyystate = MS_TOKENIZE_URL_STRING;
6671           msyystring = string;
6672           msyylex();
6673 
6674           if(getDouble(&(map->extent.minx)) == -1) break;
6675           if(getDouble(&(map->extent.miny)) == -1) break;
6676           if(getDouble(&(map->extent.maxx)) == -1) break;
6677           if(getDouble(&(map->extent.maxy)) == -1) break;
6678           if (!MS_VALID_EXTENT(map->extent)) {
6679             msSetError(MS_MISCERR, "Given map extent is invalid. Check that it is in the form: minx, miny, maxx, maxy", "msLoadMapParameterFromUrl()");
6680             break;
6681           }
6682           msMapComputeGeotransform( map );
6683           break;
6684         case(ANGLE): {
6685           double rotation_angle;
6686           msyystate = MS_TOKENIZE_URL_STRING;
6687           msyystring = string;
6688           msyylex();
6689 
6690           if(getDouble(&(rotation_angle)) == -1) break;
6691           msMapSetRotation( map, rotation_angle );
6692         }
6693         break;
6694         case(IMAGECOLOR):
6695           msyystate = MS_TOKENIZE_URL_STRING;
6696           msyystring = string;
6697           msyylex();
6698 
6699           if(loadColor(&(map->imagecolor), NULL) != MS_SUCCESS) break;
6700           break;
6701         case(IMAGETYPE):
6702           msyystate = MS_TOKENIZE_URL_STRING;
6703           msyystring = string;
6704           msyylex();
6705 
6706           /* TODO: should validate or does msPostMapParseOutputFormatSetup() do enough? */
6707 
6708           msFree(map->imagetype);
6709           map->imagetype = getToken();
6710           msPostMapParseOutputFormatSetup( map );
6711           break;
6712         case(LAYER):
6713           if((s = getSymbol(2, MS_NUMBER, MS_STRING)) == -1) {
6714             return MS_FAILURE;
6715           }
6716           if(s == MS_STRING)
6717             i = msGetLayerIndex(map, msyystring_buffer);
6718           else
6719             i = (int) msyynumber;
6720 
6721           if(i>=map->numlayers || i<0) {
6722             msSetError(MS_MISCERR, "Layer to be modified not valid.", "msUpdateMapFromURL()");
6723             return MS_FAILURE;
6724           }
6725 
6726           /* make sure this layer can be modified */
6727           if(msLookupHashTable(&(GET_LAYER(map, i)->validation), "immutable"))
6728             return(MS_SUCCESS); /* fail silently */
6729 
6730           if(msyylex() == CLASS) {
6731             if((s = getSymbol(2, MS_NUMBER, MS_STRING)) == -1) return MS_FAILURE;
6732             if(s == MS_STRING)
6733               j = msGetClassIndex(GET_LAYER(map, i), msyystring_buffer);
6734             else
6735               j = (int) msyynumber;
6736 
6737             if(j>=GET_LAYER(map, i)->numclasses || j<0) {
6738               msSetError(MS_MISCERR, "Class to be modified not valid.", "msUpdateMapFromURL()");
6739               return MS_FAILURE;
6740             }
6741 
6742             /* make sure this class can be modified */
6743             if(msLookupHashTable(&(GET_LAYER(map, i)->class[j]->validation), "immutable"))
6744               return(MS_SUCCESS); /* fail silently */
6745 
6746             switch(msyylex()) {
6747               case STYLE:
6748                 if(getInteger(&k) == -1) return MS_FAILURE;
6749                 if(k>=GET_LAYER(map, i)->class[j]->numstyles || k<0) {
6750                   msSetError(MS_MISCERR, "Style to be modified not valid.", "msUpdateMapFromURL()");
6751                   return MS_FAILURE;
6752                 }
6753                 if(msUpdateStyleFromString((GET_LAYER(map, i))->class[j]->styles[k], string, MS_TRUE) != MS_SUCCESS) return MS_FAILURE;
6754                 break;
6755               case LABEL:
6756                 if(getInteger(&k) == -1) return MS_FAILURE;
6757                 if(k>=GET_LAYER(map, i)->class[j]->numlabels || k<0) {
6758                   msSetError(MS_MISCERR, "Label to be modified not valid.", "msUpdateMapFromURL()");
6759                   return MS_FAILURE;
6760                 }
6761                 if(msUpdateLabelFromString((GET_LAYER(map, i))->class[j]->labels[k], string, MS_TRUE) != MS_SUCCESS) return MS_FAILURE;
6762                 break;
6763               default:
6764                 if(msUpdateClassFromString((GET_LAYER(map, i))->class[j], string, MS_TRUE) != MS_SUCCESS) return MS_FAILURE;
6765             }
6766           } else {
6767             if(msUpdateLayerFromString((GET_LAYER(map, i)), string, MS_TRUE) != MS_SUCCESS) return MS_FAILURE;
6768           }
6769 
6770           // make sure symbols are resolved
6771           if (resolveSymbolNames(map) == MS_FAILURE) return MS_FAILURE;
6772 
6773           break;
6774         case(LEGEND):
6775           if(msyylex() == LABEL) {
6776             return msUpdateLabelFromString(&map->legend.label, string, MS_TRUE);
6777           } else {
6778             return msUpdateLegendFromString(&(map->legend), string, MS_TRUE);
6779           }
6780         case(PROJECTION):
6781           msLoadProjectionString(&(map->projection), string);
6782           break;
6783         case(QUERYMAP):
6784           return msUpdateQueryMapFromString(&(map->querymap), string, MS_TRUE);
6785         case(REFERENCE):
6786           return msUpdateReferenceMapFromString(&(map->reference), string, MS_TRUE);
6787         case(RESOLUTION):
6788           msyystate = MS_TOKENIZE_URL_STRING;
6789           msyystring = string;
6790           msyylex();
6791 
6792           if(getDouble(&(map->resolution)) == -1) break;
6793           break;
6794         case(DEFRESOLUTION):
6795           msyystate = MS_TOKENIZE_URL_STRING;
6796           msyystring = string;
6797           msyylex();
6798 
6799           if(getDouble(&(map->defresolution)) == -1) break;
6800           break;
6801         case(SCALEBAR):
6802           return msUpdateScalebarFromString(&(map->scalebar), string, MS_TRUE);
6803         case(SIZE):
6804           msyystate = MS_TOKENIZE_URL_STRING;
6805           msyystring = string;
6806           msyylex();
6807 
6808           if(getInteger(&(map->width)) == -1) break;
6809           if(getInteger(&(map->height)) == -1) break;
6810 
6811           if(map->width > map->maxsize || map->height > map->maxsize || map->width < 0 || map->height < 0) {
6812             msSetError(MS_WEBERR, "Image size out of range.", "msUpdateMapFromURL()");
6813             break;
6814           }
6815           msMapComputeGeotransform( map );
6816           break;
6817         case(TRANSPARENT):
6818           msyystate = MS_TOKENIZE_URL_STRING;
6819           msyystring = string;
6820           msyylex();
6821 
6822           if((map->transparent = getSymbol(2, MS_ON,MS_OFF)) == -1) break;
6823           msPostMapParseOutputFormatSetup( map );
6824           break;
6825         case(UNITS):
6826           msyystate = MS_TOKENIZE_URL_STRING;
6827           msyystring = string;
6828           msyylex();
6829 
6830           if((int)(map->units = getSymbol(7, MS_INCHES,MS_FEET,MS_MILES,MS_METERS,MS_KILOMETERS,MS_NAUTICALMILES,MS_DD)) == -1) break;
6831           break;
6832         case(WEB):
6833           return msUpdateWebFromString(&(map->web), string, MS_TRUE);
6834         default:
6835           break; /* malformed string */
6836       }
6837       break;
6838     default:
6839       break;
6840   }
6841 
6842   /* msyystate = 3; */ /* restore lexer state */
6843   /* msyylex(); */
6844 
6845   if(ms_error->code != MS_NOERR) return(MS_FAILURE);
6846 
6847   return(MS_SUCCESS);
6848 }
6849 
hashTableSubstituteString(hashTableObj * hash,const char * from,const char * to)6850 static void hashTableSubstituteString(hashTableObj *hash, const char *from, const char *to) {
6851   const char *key, *val;
6852   char *new_val;
6853   key = msFirstKeyFromHashTable(hash);
6854   while(key != NULL) {
6855     val = msLookupHashTable(hash, key);
6856     if(strcasestr(val, from)) {
6857       new_val = msCaseReplaceSubstring(msStrdup(val), from, to);
6858       msInsertHashTable(hash, key, new_val);
6859       msFree(new_val);
6860     }
6861     key = msNextKeyFromHashTable(hash, key);
6862   }
6863 }
6864 
classSubstituteString(classObj * class,const char * from,const char * to)6865 static void classSubstituteString(classObj *class, const char *from, const char *to) {
6866   if(class->expression.string) class->expression.string = msCaseReplaceSubstring(class->expression.string, from, to);
6867   if(class->text.string) class->text.string = msCaseReplaceSubstring(class->text.string, from, to);
6868   if(class->title) class->title = msCaseReplaceSubstring(class->title, from, to);
6869 }
6870 
6871 
layerSubstituteString(layerObj * layer,const char * from,const char * to)6872 static void layerSubstituteString(layerObj *layer, const char *from, const char *to)
6873 {
6874   int c;
6875   if(layer->data) layer->data = msCaseReplaceSubstring(layer->data, from, to);
6876   if(layer->tileindex) layer->tileindex = msCaseReplaceSubstring(layer->tileindex, from, to);
6877   if(layer->connection) layer->connection = msCaseReplaceSubstring(layer->connection, from, to);
6878   if(layer->filter.string) layer->filter.string = msCaseReplaceSubstring(layer->filter.string, from, to);
6879 
6880   /* The bindvalues are most useful when able to substitute values from the URL */
6881   hashTableSubstituteString(&layer->bindvals, from, to);
6882   hashTableSubstituteString(&layer->metadata, from, to);
6883   msLayerSubstituteProcessing( layer, from, to );
6884   for(c=0; c<layer->numclasses;c++) {
6885     classSubstituteString(layer->class[c], from, to);
6886   }
6887 }
6888 
mapSubstituteString(mapObj * map,const char * from,const char * to)6889 static void mapSubstituteString(mapObj *map, const char *from, const char *to) {
6890   int l;
6891   for(l=0;l<map->numlayers; l++) {
6892     layerSubstituteString(GET_LAYER(map,l), from, to);
6893   }
6894   /* output formats (#3751) */
6895   for(l=0; l<map->numoutputformats; l++) {
6896     int o;
6897     for(o=0; o<map->outputformatlist[l]->numformatoptions; o++) {
6898       map->outputformatlist[l]->formatoptions[o] = msCaseReplaceSubstring(map->outputformatlist[l]->formatoptions[o], from, to);
6899     }
6900   }
6901   hashTableSubstituteString(&map->web.metadata, from, to);
6902 }
6903 
applyOutputFormatDefaultSubstitutions(outputFormatObj * format,const char * option,hashTableObj * table)6904 static void applyOutputFormatDefaultSubstitutions(outputFormatObj *format, const char *option, hashTableObj *table)
6905 {
6906   const char *filename;
6907 
6908   filename = msGetOutputFormatOption(format, option, NULL);
6909   if(filename && strlen(filename)>0) {
6910     char *tmpfilename = msStrdup(filename);
6911     const char *default_key = msFirstKeyFromHashTable(table);
6912     while(default_key) {
6913       if(!strncasecmp(default_key,"default_",8)) {
6914         char *new_filename = NULL;
6915         size_t buffer_size = (strlen(default_key)-5);
6916         char *tag = (char *)msSmallMalloc(buffer_size);
6917         snprintf(tag, buffer_size, "%%%s%%", &(default_key[8]));
6918 
6919         new_filename = msStrdup(tmpfilename);
6920         new_filename = msCaseReplaceSubstring(new_filename, tag, msLookupHashTable(table, default_key));
6921         free(tag);
6922 
6923         msSetOutputFormatOption(format, option, new_filename);
6924         free(new_filename);
6925       }
6926       default_key = msNextKeyFromHashTable(table, default_key);
6927     }
6928     msFree(tmpfilename);
6929   }
6930   return;
6931 }
6932 
applyClassDefaultSubstitutions(classObj * class,hashTableObj * table)6933 static void applyClassDefaultSubstitutions(classObj *class, hashTableObj *table)
6934 {
6935   const char *default_key = msFirstKeyFromHashTable(table);
6936   while(default_key) {
6937     if(!strncasecmp(default_key,"default_",8)) {
6938       size_t buffer_size = (strlen(default_key)-5);
6939       char *tag = (char *)msSmallMalloc(buffer_size);
6940       snprintf(tag, buffer_size, "%%%s%%", &(default_key[8]));
6941 
6942 
6943       classSubstituteString(class, tag, msLookupHashTable(table, default_key));
6944       free(tag);
6945     }
6946     default_key = msNextKeyFromHashTable(table, default_key);
6947   }
6948   return;
6949 }
6950 
applyLayerDefaultSubstitutions(layerObj * layer,hashTableObj * table)6951 static void applyLayerDefaultSubstitutions(layerObj *layer, hashTableObj *table)
6952 {
6953   int i;
6954   const char *default_key = msFirstKeyFromHashTable(table);
6955   while(default_key) {
6956     if(!strncasecmp(default_key,"default_",8)) {
6957       size_t buffer_size = (strlen(default_key)-5);
6958       const char *to = msLookupHashTable(table, default_key);
6959       char *tag = (char *)msSmallMalloc(buffer_size);
6960       snprintf(tag, buffer_size, "%%%s%%", &(default_key[8]));
6961 
6962       for(i=0; i<layer->numclasses; i++) {
6963         classSubstituteString(layer->class[i], tag, to);
6964       }
6965       layerSubstituteString(layer, tag, to);
6966       free(tag);
6967     }
6968     default_key = msNextKeyFromHashTable(table, default_key);
6969   }
6970   return;
6971 }
6972 
applyHashTableDefaultSubstitutions(hashTableObj * hashTab,hashTableObj * table)6973 static void applyHashTableDefaultSubstitutions(hashTableObj *hashTab, hashTableObj *table)
6974 {
6975 	const char *default_key = msFirstKeyFromHashTable(table);
6976 	while (default_key) {
6977 		if (!strncasecmp(default_key, "default_", 8)) {
6978 			size_t buffer_size = (strlen(default_key) - 5);
6979 			const char *to = msLookupHashTable(table, default_key);
6980 			char *tag = (char *)msSmallMalloc(buffer_size);
6981 			snprintf(tag, buffer_size, "%%%s%%", &(default_key[8]));
6982 
6983 			hashTableSubstituteString(hashTab, tag, to);
6984 			free(tag);
6985 		}
6986 		default_key = msNextKeyFromHashTable(table, default_key);
6987 	}
6988 	return;
6989 }
6990 
6991 /*
6992 ** Loop through layer metadata for keys that have a default_%key% pattern to replace
6993 ** remaining %key% entries by their default value.
6994 */
msApplyDefaultSubstitutions(mapObj * map)6995 void msApplyDefaultSubstitutions(mapObj *map)
6996 {
6997   int i,j;
6998 
6999   /* output formats (#3751) */
7000   for(i=0; i<map->numoutputformats; i++) {
7001     applyOutputFormatDefaultSubstitutions(map->outputformatlist[i], "filename", &(map->web.validation));
7002     applyOutputFormatDefaultSubstitutions(map->outputformatlist[i], "JSONP", &(map->web.validation));
7003   }
7004 
7005   for(i=0; i<map->numlayers; i++) {
7006     layerObj *layer = GET_LAYER(map, i);
7007 
7008     for(j=0; j<layer->numclasses; j++) {    /* class settings take precedence...  */
7009       classObj *class = GET_CLASS(map, i, j);
7010       applyClassDefaultSubstitutions(class, &(class->validation));
7011     }
7012 
7013     applyLayerDefaultSubstitutions(layer, &(layer->validation)); /* ...then layer settings... */
7014     applyLayerDefaultSubstitutions(layer, &(map->web.validation)); /* ...and finally web settings */
7015   }
7016   applyHashTableDefaultSubstitutions(&map->web.metadata, &(map->web.validation));
7017 }
7018 
_get_param_value(const char * key,char ** names,char ** values,int npairs)7019 char *_get_param_value(const char *key, char **names, char **values, int npairs) {
7020 
7021   if(getenv(key)) { /* envirronment override */
7022     return getenv(key);
7023   }
7024   while(npairs) {
7025     npairs--;
7026     if(strcasecmp(key, names[npairs]) == 0) {
7027       return values[npairs];
7028     }
7029   }
7030   return NULL;
7031 }
7032 
msApplySubstitutions(mapObj * map,char ** names,char ** values,int npairs)7033 void msApplySubstitutions(mapObj *map, char **names, char **values, int npairs)
7034 {
7035   int l;
7036   const char *key, *value, *validation;
7037   char *tag;
7038   for(l=0; l<map->numlayers; l++) {
7039     int c;
7040     layerObj *lp = GET_LAYER(map,l);
7041     for(c=0; c<lp->numclasses; c++) {
7042       classObj *cp = lp->class[c];
7043       key = NULL;
7044       while( (key = msNextKeyFromHashTable(&cp->validation, key)) ) {
7045         value = _get_param_value(key,names,values,npairs);
7046         if(!value) continue; /*parameter was not in url*/
7047         validation = msLookupHashTable(&cp->validation, key);
7048         if(msEvalRegex(validation, value)) {
7049           /* we've found a substitution and it validates correctly, now let's apply it */
7050           tag = msSmallMalloc(strlen(key)+3);
7051           sprintf(tag,"%%%s%%",key);
7052           classSubstituteString(cp,tag,value);
7053           free(tag);
7054         } else {
7055           msSetError(MS_REGEXERR, "Parameter pattern validation failed." , "msApplySubstitutions()");
7056           if(map->debug || lp->debug) {
7057             msDebug("layer (%s), class %d: failed to validate (%s=%s) for regex (%s)\n", lp->name, c, key, value, validation);
7058           }
7059         }
7060 
7061       }
7062     }
7063     key = NULL;
7064     while( (key = msNextKeyFromHashTable(&lp->validation, key)) ) {
7065       value = _get_param_value(key,names,values,npairs);
7066       if(!value) continue; /*parameter was not in url*/
7067       validation = msLookupHashTable(&lp->validation, key);
7068       if(msEvalRegex(validation, value)) {
7069         /* we've found a substitution and it validates correctly, now let's apply it */
7070         tag = msSmallMalloc(strlen(key)+3);
7071         sprintf(tag,"%%%s%%",key);
7072         layerSubstituteString(lp,tag,value);
7073         free(tag);
7074       } else {
7075         msSetError(MS_REGEXERR, "Parameter pattern validation failed." , "msApplySubstitutions()");
7076         if(map->debug || lp->debug) {
7077           msDebug("layer (%s): failed to validate (%s=%s) for regex (%s)\n", lp->name, key, value, validation);
7078         }
7079       }
7080 
7081     }
7082   }
7083   key = NULL;
7084   while( (key = msNextKeyFromHashTable(&map->web.validation, key)) ) {
7085     value = _get_param_value(key,names,values,npairs);
7086     if(!value) continue; /*parameter was not in url*/
7087     validation = msLookupHashTable(&map->web.validation, key);
7088     if(msEvalRegex(validation, value)) {
7089       /* we've found a substitution and it validates correctly, now let's apply it */
7090       tag = msSmallMalloc(strlen(key)+3);
7091       sprintf(tag,"%%%s%%",key);
7092       mapSubstituteString(map,tag,value);
7093       free(tag);
7094     } else {
7095       msSetError(MS_REGEXERR, "Parameter pattern validation failed." , "msApplySubstitutions()");
7096       if(map->debug) {
7097         msDebug("failed to validate (%s=%s) for regex (%s)\n", key, value, validation);
7098       }
7099     }
7100 
7101   }
7102 }
7103 
7104 /*
7105 ** Returns an array with one entry per mapfile token.  Useful to manipulate
7106 ** mapfiles in MapScript.
7107 **
7108 ** The returned array should be freed using msFreeCharArray().
7109 */
tokenizeMapInternal(char * filename,int * ret_numtokens)7110 static char **tokenizeMapInternal(char *filename, int *ret_numtokens)
7111 {
7112   char **tokens = NULL;
7113   int  numtokens=0, numtokens_allocated=0;
7114   size_t buffer_size = 0;
7115 
7116   *ret_numtokens = 0;
7117 
7118   if(!filename) {
7119     msSetError(MS_MISCERR, "Filename is undefined.", "msTokenizeMap()");
7120     return NULL;
7121   }
7122 
7123   /*
7124   ** Check map filename to make sure it's legal
7125   */
7126   if(getenv("MS_MAPFILE_PATTERN")) { /* user override */
7127     if(msEvalRegex(getenv("MS_MAPFILE_PATTERN"), filename) != MS_TRUE) {
7128       msSetError(MS_REGEXERR, "MS_MAPFILE_PATTERN validation failed." , "msLoadMap()");
7129       return(NULL);
7130     }
7131   } else { /* check the default */
7132     if(msEvalRegex(MS_DEFAULT_MAPFILE_PATTERN, filename) != MS_TRUE) {
7133       msSetError(MS_REGEXERR, "MS_DEFAULT_MAPFILE_PATTERN validation failed." , "msLoadMap()");
7134       return(NULL);
7135     }
7136   }
7137 
7138   if((msyyin = fopen(filename,"r")) == NULL) {
7139     msSetError(MS_IOERR, "(%s)", "msTokenizeMap()", filename);
7140     return NULL;
7141   }
7142 
7143   msyystate = MS_TOKENIZE_FILE; /* restore lexer state to INITIAL, and do return comments */
7144   msyylex();
7145   msyyreturncomments = 1; /* want all tokens, including comments */
7146 
7147   msyyrestart(msyyin); /* start at line begining, line 1 */
7148   msyylineno = 1;
7149 
7150   numtokens = 0;
7151   numtokens_allocated = 256;
7152   tokens = (char **) malloc(numtokens_allocated*sizeof(char*));
7153   if(tokens == NULL) {
7154     msSetError(MS_MEMERR, NULL, "msTokenizeMap()");
7155     fclose(msyyin);
7156     return NULL;
7157   }
7158 
7159   for(;;) {
7160 
7161     if(numtokens_allocated <= numtokens) {
7162       numtokens_allocated *= 2; /* double size of the array every time we reach the limit */
7163       tokens = (char **)realloc(tokens, numtokens_allocated*sizeof(char*));
7164       if(tokens == NULL) {
7165         msSetError(MS_MEMERR, "Realloc() error.", "msTokenizeMap()");
7166         fclose(msyyin);
7167         return NULL;
7168       }
7169     }
7170 
7171     switch(msyylex()) {
7172       case(EOF): /* This is the normal way out... cleanup and exit */
7173         fclose(msyyin);
7174         *ret_numtokens = numtokens;
7175         return(tokens);
7176         break;
7177       case(MS_STRING):
7178         buffer_size = strlen(msyystring_buffer)+2+1;
7179         tokens[numtokens] = (char*) msSmallMalloc(buffer_size);
7180         snprintf(tokens[numtokens], buffer_size, "\"%s\"", msyystring_buffer);
7181         break;
7182       case(MS_EXPRESSION):
7183         buffer_size = strlen(msyystring_buffer)+2+1;
7184         tokens[numtokens] = (char*) msSmallMalloc(buffer_size);
7185         snprintf(tokens[numtokens], buffer_size, "(%s)", msyystring_buffer);
7186         break;
7187       case(MS_REGEX):
7188         buffer_size = strlen(msyystring_buffer)+2+1;
7189         tokens[numtokens] = (char*) msSmallMalloc(buffer_size);
7190         snprintf(tokens[numtokens], buffer_size, "/%s/", msyystring_buffer);
7191         break;
7192       default:
7193         tokens[numtokens] = msStrdup(msyystring_buffer);
7194         break;
7195     }
7196 
7197     if(tokens[numtokens] == NULL) {
7198       int i;
7199       msSetError(MS_MEMERR, NULL, "msTokenizeMap()");
7200       fclose(msyyin);
7201       for(i=0; i<numtokens; i++)
7202         msFree(tokens[i]);
7203       msFree(tokens);
7204       return NULL;
7205     }
7206 
7207     numtokens++;
7208   }
7209 
7210   return NULL;   /* should never get here */
7211 }
7212 
7213 /*
7214 ** Wraps tokenizeMapInternal
7215 */
msTokenizeMap(char * filename,int * numtokens)7216 char **msTokenizeMap(char *filename, int *numtokens)
7217 {
7218   char **tokens;
7219 
7220   msAcquireLock( TLOCK_PARSER );
7221   tokens = tokenizeMapInternal( filename, numtokens );
7222   msReleaseLock( TLOCK_PARSER );
7223 
7224   return tokens;
7225 }
7226 
msCloseConnections(mapObj * map)7227 void msCloseConnections(mapObj *map)
7228 {
7229   int i;
7230   layerObj *lp;
7231 
7232   for (i=0; i<map->numlayers; i++) {
7233     lp = (GET_LAYER(map, i));
7234 
7235     /* If the vtable is null, then the layer is never accessed or used -> skip it
7236      */
7237     if (lp->vtable) {
7238       lp->vtable->LayerCloseConnection(lp);
7239     }
7240   }
7241 }
7242 
initResultCache(resultCacheObj * resultcache)7243 void initResultCache(resultCacheObj *resultcache)
7244 {
7245   if (resultcache) {
7246     resultcache->results = NULL;
7247     resultcache->numresults = 0;
7248     resultcache->cachesize = 0;
7249     resultcache->bounds.minx = resultcache->bounds.miny = resultcache->bounds.maxx = resultcache->bounds.maxy = -1;
7250     resultcache->previousBounds = resultcache->bounds;
7251     resultcache->usegetshape = MS_FALSE;
7252   }
7253 }
7254 
cleanupResultCache(resultCacheObj * resultcache)7255 void cleanupResultCache(resultCacheObj *resultcache)
7256 {
7257   if(resultcache) {
7258     if(resultcache->results)
7259     {
7260         int i;
7261         for( i = 0; i < resultcache->numresults; i++ )
7262         {
7263             if( resultcache->results[i].shape )
7264             {
7265                 msFreeShape( resultcache->results[i].shape );
7266                 msFree( resultcache->results[i].shape );
7267             }
7268         }
7269         free(resultcache->results);
7270     }
7271     resultcache->results = NULL;
7272     initResultCache(resultcache);
7273   }
7274 }
7275 
7276 
resolveSymbolNames(mapObj * map)7277 static int resolveSymbolNames(mapObj* map)
7278 {
7279   int i, j;
7280 
7281   /* step through layers and classes to resolve symbol names */
7282   for(i=0; i<map->numlayers; i++) {
7283     for(j=0; j<GET_LAYER(map, i)->numclasses; j++) {
7284       if(classResolveSymbolNames(GET_LAYER(map, i)->class[j]) != MS_SUCCESS) return MS_FAILURE;
7285     }
7286   }
7287 
7288   return MS_SUCCESS;
7289 }
7290