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