• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geographika / mapserver / 12180102655

05 Dec 2024 12:50PM UTC coverage: 40.361% (+0.08%) from 40.281%
12180102655

push

github

geographika
Add back all Python versions

58368 of 144616 relevant lines covered (40.36%)

25464.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.04
/src/mapfile.c
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 <stdbool.h>
36
#include <assert.h>
37
#include <ctype.h>
38
#include <float.h>
39

40
#include "mapserver.h"
41
#include "mapfile.h"
42
#include "mapthread.h"
43
#include "maptime.h"
44
#include "mapogcsld.h"
45

46
#include "cpl_conv.h"
47
#include "cpl_port.h"
48
#include "cpl_string.h"
49

50
extern int msyylex(void);
51
extern void msyyrestart(FILE *);
52
extern int msyylex_destroy(void);
53
extern void msyycleanup_includes();
54

55
extern double msyynumber;
56
extern int msyylineno;
57
extern FILE *msyyin;
58

59
extern int msyysource;
60
extern int msyystate;
61
extern const char *msyystring;
62
extern char *msyybasepath;
63
extern int msyyreturncomments;
64
extern char *msyystring_buffer;
65
extern int msyystring_icase;
66

67
extern int loadSymbol(symbolObj *s, char *symbolpath); /* in mapsymbol.c */
68
extern void writeSymbol(symbolObj *s, FILE *stream);   /* in mapsymbol.c */
69
static int loadGrid(layerObj *pLayer);
70
static int loadStyle(styleObj *style);
71
static void writeStyle(FILE *stream, int indent, styleObj *style);
72
static int resolveSymbolNames(mapObj *map);
73
static int loadExpression(expressionObj *exp);
74
static void writeExpression(FILE *stream, int indent, const char *name,
75
                            expressionObj *exp);
76

77
/*
78
** Symbol to string static arrays needed for writing map files.
79
** Must be kept in sync with enumerations and defines found in mapserver.h.
80
*/
81
/* static char *msUnits[9]={"INCHES", "FEET", "MILES", "METERS", "KILOMETERS",
82
 * "DD", "PIXELS", "PERCENTAGES", "NAUTICALMILES"}; */
83
/* static char *msLayerTypes[10]={"POINT", "LINE", "POLYGON", "RASTER",
84
 * "ANNOTATION", "QUERY", "CIRCLE", "TILEINDEX","CHART"}; */
85
char *msPositionsText[MS_POSITIONS_LENGTH] = {
86
    "UL", "LR", "UR",   "LL", "CR",    "CL", "UC",
87
    "LC", "CC", "AUTO", "XY", "FOLLOW"}; /* msLabelPositions[] also used in
88
                                            mapsymbols.c (not static) */
89
/* static char *msBitmapFontSizes[5]={"TINY", "SMALL", "MEDIUM", "LARGE",
90
 * "GIANT"}; */
91
/* static char *msQueryMapStyles[4]={"NORMAL", "HILITE", "SELECTED",
92
 * "INVERTED"}; */
93
/* static char *msStatus[4]={"OFF", "ON", "DEFAULT", "EMBED"}; */
94
/* static char *msOnOff[2]={"OFF", "ON"}; */
95
/* static char *msTrueFalse[2]={"FALSE", "TRUE"}; */
96
/* static char *msYesNo[2]={"NO", "YES"}; */
97
/* static char *msJoinType[2]={"ONE-TO-ONE", "ONE-TO-MANY"}; */
98
/* static char *msAlignValue[3]={"LEFT","CENTER","RIGHT"}; */
99

100
/*
101
** Validates a string (value) against a series of patterns. We support up to
102
*four to allow cascading from classObj to
103
** layerObj to webObj plus a legacy pattern like TEMPLATEPATTERN.
104
*/
105
int msValidateParameter(const char *value, const char *pattern1,
25✔
106
                        const char *pattern2, const char *pattern3,
107
                        const char *pattern4) {
108
  if (msEvalRegex(pattern1, value) == MS_TRUE)
25✔
109
    return MS_SUCCESS;
110
  if (msEvalRegex(pattern2, value) == MS_TRUE)
3✔
111
    return MS_SUCCESS;
112
  if (msEvalRegex(pattern3, value) == MS_TRUE)
3✔
113
    return MS_SUCCESS;
114
  if (msEvalRegex(pattern4, value) == MS_TRUE)
3✔
115
    return MS_SUCCESS;
×
116

117
  return (MS_FAILURE);
118
}
119

120
int msIsValidRegex(const char *e) {
1,787✔
121
  ms_regex_t re;
122
  int errcode = ms_regcomp(&re, e, MS_REG_EXTENDED | MS_REG_NOSUB);
1,787✔
123
  if (errcode != 0) {
1,787✔
124
    char szErrbuf[256];
125
    ms_regerror(errcode, &re, szErrbuf, sizeof(szErrbuf));
×
126
    msSetError(MS_REGEXERR, "Failed to compile expression (%s): %s.",
×
127
               "msIsValidRegex()", e, szErrbuf);
128
    return (MS_FALSE);
129
  }
130
  ms_regfree(&re);
1,787✔
131
  return MS_TRUE;
1,787✔
132
}
133

134
int msEvalRegex(const char *e, const char *s) {
6,934✔
135
  ms_regex_t re;
136

137
  if (!e || !s)
6,934✔
138
    return (MS_FALSE);
139

140
  int errcode = ms_regcomp(&re, e, MS_REG_EXTENDED | MS_REG_NOSUB);
6,924✔
141
  if (errcode != 0) {
6,924✔
142
    char szErrbuf[256];
143
    ms_regerror(errcode, &re, szErrbuf, sizeof(szErrbuf));
1✔
144
    msSetError(MS_REGEXERR, "Failed to compile expression (%s): %s.",
1✔
145
               "msEvalRegex()", e, szErrbuf);
146
    return (MS_FALSE);
147
  }
148

149
  if (ms_regexec(&re, s, 0, NULL, 0) != 0) { /* no match */
6,923✔
150
    ms_regfree(&re);
1,794✔
151
    return (MS_FALSE);
1,794✔
152
  }
153
  ms_regfree(&re);
5,129✔
154

155
  return (MS_TRUE);
5,129✔
156
}
157

158
int msCaseEvalRegex(const char *e, const char *s) {
×
159
  ms_regex_t re;
160

161
  if (!e || !s)
×
162
    return (MS_FALSE);
163

164
  if (ms_regcomp(&re, e, MS_REG_EXTENDED | MS_REG_ICASE | MS_REG_NOSUB) != 0) {
×
165
    msSetError(MS_REGEXERR, "Failed to compile expression (%s).",
×
166
               "msEvalRegex()", e);
167
    return (MS_FALSE);
×
168
  }
169

170
  if (ms_regexec(&re, s, 0, NULL, 0) != 0) { /* no match */
×
171
    ms_regfree(&re);
×
172
    return (MS_FALSE);
×
173
  }
174
  ms_regfree(&re);
×
175

176
  return (MS_TRUE);
×
177
}
178

179
#ifdef USE_MSFREE
180
void msFree(void *p) {
181
  if (p)
182
    free(p);
183
}
184
#endif
185

186
/*
187
** Free memory allocated for a character array
188
*/
189
void msFreeCharArray(char **array, int num_items) {
127,939✔
190
  int i;
191
  if (!array)
127,939✔
192
    return;
193
  for (i = 0; i < num_items; i++)
503,588✔
194
    msFree(array[i]);
391,638✔
195
  msFree(array);
111,950✔
196
}
197

198
/*
199
** Checks symbol from lexer against variable length list of
200
** legal symbols.
201
*/
202
int getSymbol(int n, ...) {
116,626✔
203
  int symbol;
204
  va_list argp;
205
  int i = 0;
206

207
  symbol = msyylex();
116,626✔
208

209
  va_start(argp, n);
116,626✔
210
  while (i < n) { /* check each symbol in the list */
185,247✔
211
    if (symbol == va_arg(argp, int)) {
185,247✔
212
      va_end(argp);
116,626✔
213
      return (symbol);
116,626✔
214
    }
215
    i++;
68,621✔
216
  }
217

218
  va_end(argp);
×
219

220
  msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getSymbol()",
×
221
             msyystring_buffer, msyylineno);
222
  return (-1);
×
223
}
224

225
/*
226
** Same as getSymbol, except no error message is set on failure
227
*/
228
int getSymbol2(int n, ...) {
2,784✔
229
  int symbol;
230
  va_list argp;
231
  int i = 0;
232

233
  symbol = msyylex();
2,784✔
234

235
  va_start(argp, n);
2,784✔
236
  while (i < n) { /* check each symbol in the list */
2,886✔
237
    if (symbol == va_arg(argp, int)) {
2,867✔
238
      va_end(argp);
2,765✔
239
      return (symbol);
2,765✔
240
    }
241
    i++;
102✔
242
  }
243

244
  va_end(argp);
19✔
245
  return (-1);
19✔
246
}
247

248
/*
249
** Get a string or symbol as a string.   Operates like getString(), but also
250
** supports symbols.
251
*/
252
static char *getToken(void) {
253
  msyylex();
752✔
254
  return msStrdup(msyystring_buffer);
3,424✔
255
}
256

257
/*
258
** Load a string from the map file. A "string" is defined in lexer.l.
259
*/
260
int getString(char **s) {
165,290✔
261
  /* if (*s)
262
    msSetError(MS_SYMERR, "Duplicate item (%s):(line %d)", "getString()",
263
  msyystring_buffer, msyylineno); return(MS_FAILURE); } else */
264
  if (msyylex() == MS_STRING) {
165,290✔
265
    if (*s)
165,290✔
266
      free(*s); /* avoid leak */
3,039✔
267
    *s = msStrdup(msyystring_buffer);
165,290✔
268
    return (MS_SUCCESS);
165,290✔
269
  }
270

271
  msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getString()",
×
272
             msyystring_buffer, msyylineno);
273
  return (MS_FAILURE);
×
274
}
275

276
int msCheckNumber(double number, int num_check_type, double value1,
147,910✔
277
                  double value2) {
278
  if (num_check_type == MS_NUM_CHECK_NONE) {
147,910✔
279
    return MS_SUCCESS;
280
  } else if (num_check_type == MS_NUM_CHECK_RANGE && number >= value1 &&
76,673✔
281
             number <= value2) {
282
    return MS_SUCCESS;
283
  } else if (num_check_type == MS_NUM_CHECK_GT && number > value1) {
17,108✔
284
    return MS_SUCCESS;
285
  } else if (num_check_type == MS_NUM_CHECK_GTE && number >= value1) {
8,471✔
286
    return MS_SUCCESS;
8,471✔
287
  }
288

289
  return MS_FAILURE;
290
}
291

292
/*
293
** Load a floating point number from the map file. (see lexer.l)
294
*/
295
int getDouble(double *d, int num_check_type, double value1, double value2) {
71,472✔
296
  if (msyylex() == MS_NUMBER) {
71,472✔
297
    if (msCheckNumber(msyynumber, num_check_type, value1, value2) ==
71,472✔
298
        MS_SUCCESS) {
299
      *d = msyynumber;
71,472✔
300
      return (0);
71,472✔
301
    }
302
  }
303

304
  msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getDouble()",
×
305
             msyystring_buffer, msyylineno);
306
  return (-1);
×
307
}
308

309
/*
310
** Load a integer from the map file. (see lexer.l)
311
*/
312
int getInteger(int *i, int num_check_type, int value1, int value2) {
60,138✔
313
  if (msyylex() == MS_NUMBER) {
60,138✔
314
    if (msCheckNumber(msyynumber, num_check_type, value1, value2) ==
60,138✔
315
        MS_SUCCESS) {
316
      *i = (int)msyynumber;
60,138✔
317
      return (0);
60,138✔
318
    }
319
  }
320

321
  msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getInteger()",
×
322
             msyystring_buffer, msyylineno);
323
  return (-1);
×
324
}
325

326
int getCharacter(char *c) {
257✔
327
  if (msyylex() == MS_STRING) {
257✔
328
    *c = msyystring_buffer[0];
257✔
329
    return (0);
257✔
330
  }
331

332
  msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)", "getCharacter()",
×
333
             msyystring_buffer, msyylineno);
334
  return (-1);
×
335
}
336

337
/*
338
** Try to load as an integer, then try as a named symbol.
339
** Part of work on bug 490.
340
*/
341
int getIntegerOrSymbol(int *i, int n, ...) {
×
342
  int symbol;
343
  va_list argp;
344
  int j = 0;
345

346
  symbol = msyylex();
×
347

348
  if (symbol == MS_NUMBER) {
×
349
    *i = (int)msyynumber;
×
350
    return MS_SUCCESS; /* success */
×
351
  }
352

353
  va_start(argp, n);
×
354
  while (j < n) { /* check each symbol in the list */
×
355
    if (symbol == va_arg(argp, int)) {
×
356
      va_end(argp);
×
357
      *i = symbol;
×
358
      return MS_SUCCESS;
×
359
    }
360
    j++;
×
361
  }
362
  va_end(argp);
×
363

364
  msSetError(MS_SYMERR, "Parsing error near (%s):(line %d)",
×
365
             "getIntegerOrSymbol()", msyystring_buffer, msyylineno);
366
  return (-1);
×
367
}
368

369
/*
370
** msBuildPluginLibraryPath
371
**
372
** This function builds a path to be used dynamically to load plugin library.
373
*/
374
int msBuildPluginLibraryPath(char **dest, const char *lib_str, mapObj *map) {
×
375
  char szLibPath[MS_MAXPATHLEN] = {'\0'};
×
376
  char szLibPathExt[MS_MAXPATHLEN] = {'\0'};
×
377
  const char *plugin_dir = NULL;
378

379
  if (map)
×
380
    plugin_dir = msLookupHashTable(&(map->configoptions), "MS_PLUGIN_DIR");
×
381

382
    /* do nothing on windows, filename without .dll will be loaded by default*/
383
#if !defined(_WIN32)
384
  if (lib_str) {
×
385
    size_t len = strlen(lib_str);
×
386
    if (3 < len && strcmp(lib_str + len - 3, ".so")) {
×
387
      strlcpy(szLibPathExt, lib_str, MS_MAXPATHLEN);
×
388
      strlcat(szLibPathExt, ".so", MS_MAXPATHLEN);
×
389
      lib_str = szLibPathExt;
390
    }
391
  }
392
#endif /* !defined(_WIN32) */
393
  if (NULL == msBuildPath(szLibPath, plugin_dir, lib_str)) {
×
394
    return MS_FAILURE;
395
  }
396
  msFree(*dest);
×
397
  *dest = msStrdup(szLibPath);
×
398

399
  return MS_SUCCESS;
×
400
}
401

402
/*
403
** Returns the index of specified symbol or -1 if not found.
404
**
405
** If try_addimage_if_notfound==MS_TRUE then msAddImageSymbol() will be called
406
** to try to allocate the symbol as an image symbol.
407
*/
408
int msGetSymbolIndex(symbolSetObj *symbols, const char *name,
3,148✔
409
                     int try_addimage_if_notfound) {
410
  int i;
411

412
  if (!symbols || !name)
3,148✔
413
    return (-1);
414

415
  /* symbol 0 has no name */
416
  for (i = 1; i < symbols->numsymbols; i++) {
8,718✔
417
    if (symbols->symbol[i]->name)
8,418✔
418
      if (strcasecmp(symbols->symbol[i]->name, name) == 0)
8,253✔
419
        return (i);
2,848✔
420
  }
421

422
  if (try_addimage_if_notfound)
300✔
423
    return (
424
        msAddImageSymbol(symbols, name)); /* make sure it's not a filename */
46✔
425

426
  return (-1);
427
}
428

429
/*
430
** Return the index number for a given layer based on its name.
431
*/
432
int msGetLayerIndex(mapObj *map, const char *name) {
1,080✔
433
  int i;
434

435
  if (!name)
1,080✔
436
    return (-1);
437

438
  for (i = 0; i < map->numlayers; i++) {
3,774✔
439
    if (!GET_LAYER(map, i)->name) /* skip it */
3,370✔
440
      continue;
1✔
441
    if (strcmp(name, GET_LAYER(map, i)->name) == 0)
3,369✔
442
      return (i);
654✔
443
  }
444
  return (-1);
445
}
446

447
int loadColor(colorObj *color, attributeBindingObj *binding) {
24,245✔
448
  int symbol;
449
  char hex[2];
450

451
  /*
452
  ** Note that negative color values can be used to suppress or change behavior.
453
  *For example, referenceObj uses
454
  ** a negative color component to suppress rectangle fills.
455
  */
456

457
  if (binding) {
24,245✔
458
    if ((symbol = getSymbol(3, MS_NUMBER, MS_BINDING, MS_STRING)) == -1)
20,275✔
459
      return MS_FAILURE;
460
  } else {
461
    if ((symbol = getSymbol(2, MS_NUMBER, MS_STRING)) == -1)
3,970✔
462
      return MS_FAILURE;
463
  }
464

465
  color->alpha = 255;
24,245✔
466
  if (symbol == MS_NUMBER) {
24,245✔
467
    if (msyynumber >= -255 && msyynumber <= 255) {
23,867✔
468
      color->red = (int)msyynumber;
23,867✔
469
    } else {
470
      return MS_FAILURE;
471
    }
472
    if (getInteger(&(color->green), MS_NUM_CHECK_RANGE, -255, 255) == -1)
23,867✔
473
      return MS_FAILURE;
474
    if (getInteger(&(color->blue), MS_NUM_CHECK_RANGE, -255, 255) == -1)
23,867✔
475
      return MS_FAILURE;
×
476
  } else if (symbol == MS_STRING) {
378✔
477
    int len = strlen(msyystring_buffer);
360✔
478
    if (msyystring_buffer[0] == '#' &&
360✔
479
        (len == 7 || len == 9)) { /* got a hex color w/optional alpha */
360✔
480
      hex[0] = msyystring_buffer[1];
360✔
481
      hex[1] = msyystring_buffer[2];
360✔
482
      color->red = msHexToInt(hex);
360✔
483
      hex[0] = msyystring_buffer[3];
360✔
484
      hex[1] = msyystring_buffer[4];
360✔
485
      color->green = msHexToInt(hex);
360✔
486
      hex[0] = msyystring_buffer[5];
360✔
487
      hex[1] = msyystring_buffer[6];
360✔
488
      color->blue = msHexToInt(hex);
360✔
489
      if (len == 9) {
360✔
490
        hex[0] = msyystring_buffer[7];
29✔
491
        hex[1] = msyystring_buffer[8];
29✔
492
        color->alpha = msHexToInt(hex);
29✔
493
      }
494
    } else {
495
      /* TODO: consider named colors here */
496
      msSetError(MS_SYMERR, "Invalid hex color (%s):(line %d)", "loadColor()",
×
497
                 msyystring_buffer, msyylineno);
498
      return MS_FAILURE;
×
499
    }
500
  } else {
501
    assert(binding);
502
    msFree(binding->item);
18✔
503
    binding->item = msStrdup(msyystring_buffer);
18✔
504
    binding->index = -1;
18✔
505
  }
506

507
  return MS_SUCCESS;
508
}
509

510
#if ALPHACOLOR_ENABLED
511
int loadColorWithAlpha(colorObj *color) {
512
  char hex[2];
513

514
  /*
515
  ** Note that negative color values can be used to suppress or change behavior.
516
  *For example, referenceObj uses
517
  ** a negative color component to suppress rectangle fills.
518
  */
519

520
  if (getInteger(&(color->red), MS_NUM_CHECK_RANGE, -255, 255) == -1) {
521
    if (msyystring_buffer[0] == '#' &&
522
        strlen(msyystring_buffer) == 7) { /* got a hex color */
523
      hex[0] = msyystring_buffer[1];
524
      hex[1] = msyystring_buffer[2];
525
      color->red = msHexToInt(hex);
526
      hex[0] = msyystring_buffer[3];
527
      hex[1] = msyystring_buffer[4];
528
      color->green = msHexToInt(hex);
529
      hex[0] = msyystring_buffer[5];
530
      hex[1] = msyystring_buffer[6];
531
      color->blue = msHexToInt(hex);
532
      color->alpha = 0;
533

534
      return (MS_SUCCESS);
535
    } else if (msyystring_buffer[0] == '#' &&
536
               strlen(msyystring_buffer) ==
537
                   9) { /* got a hex color with alpha */
538
      hex[0] = msyystring_buffer[1];
539
      hex[1] = msyystring_buffer[2];
540
      color->red = msHexToInt(hex);
541
      hex[0] = msyystring_buffer[3];
542
      hex[1] = msyystring_buffer[4];
543
      color->green = msHexToInt(hex);
544
      hex[0] = msyystring_buffer[5];
545
      hex[1] = msyystring_buffer[6];
546
      color->blue = msHexToInt(hex);
547
      hex[0] = msyystring_buffer[7];
548
      hex[1] = msyystring_buffer[8];
549
      color->alpha = msHexToInt(hex);
550
      return (MS_SUCCESS);
551
    }
552
    return (MS_FAILURE);
553
  }
554
  if (getInteger(&(color->green), MS_NUM_CHECK_RANGE, -255, 255) == -1)
555
    return (MS_FAILURE);
556
  if (getInteger(&(color->blue), MS_NUM_CHECK_RANGE, -255, 255) == -1)
557
    return (MS_FAILURE);
558
  if (getInteger(&(color->alpha), MS_NUM_CHECK_RANGE, 0, 255) == -1)
559
    return (MS_FAILURE);
560

561
  return (MS_SUCCESS);
562
}
563
#endif
564

565
/*
566
** Helper functions for writing mapfiles.
567
*/
568
static void writeLineFeed(FILE *stream) { msIO_fprintf(stream, "\n"); }
85✔
569

570
static void writeIndent(FILE *stream, int indent) {
571
  const char *str = "  "; /* change this string to define the indent */
572
  int i;
573
  for (i = 0; i < indent; i++)
967✔
574
    msIO_fprintf(stream, "%s", str);
680✔
575
}
576

577
static void writeBlockBegin(FILE *stream, int indent, const char *name) {
58✔
578
  writeIndent(stream, indent);
579
  msIO_fprintf(stream, "%s\n", name);
58✔
580
}
58✔
581

582
static void writeBlockEnd(FILE *stream, int indent, const char *name) {
58✔
583
  writeIndent(stream, indent);
584
  msIO_fprintf(stream, "END # %s\n", name);
58✔
585
}
58✔
586

587
static void writeKeyword(FILE *stream, int indent, const char *name, int value,
112✔
588
                         int size, ...) {
589
  va_list argp;
590
  int i, j = 0;
591
  const char *s;
592

593
  va_start(argp, size);
112✔
594
  while (j < size) { /* check each value/keyword mapping in the list, values
505✔
595
                        with no match are ignored */
596
    i = va_arg(argp, int);
432✔
597
    s = va_arg(argp, const char *);
432✔
598
    if (value == i) {
432✔
599
      writeIndent(stream, ++indent);
600
      msIO_fprintf(stream, "%s %s\n", name, s);
39✔
601
      va_end(argp);
39✔
602
      return;
39✔
603
    }
604
    j++;
393✔
605
  }
606
  va_end(argp);
73✔
607
}
608

609
static void writeDimension(FILE *stream, int indent, const char *name, double x,
17✔
610
                           double y, char *bind_x, char *bind_y) {
611
  writeIndent(stream, ++indent);
612
  if (bind_x)
17✔
613
    msIO_fprintf(stream, "%s [%s] ", name, bind_x);
×
614
  else
615
    msIO_fprintf(stream, "%s %.15g ", name, x);
17✔
616
  if (bind_y)
17✔
617
    msIO_fprintf(stream, "[%s]\n", bind_y);
×
618
  else
619
    msIO_fprintf(stream, "%.15g\n", y);
17✔
620
}
17✔
621

622
static void writeDoubleRange(FILE *stream, int indent, const char *name,
×
623
                             double x, double y) {
624
  writeIndent(stream, ++indent);
625
  msIO_fprintf(stream, "%s %f %f\n", name, x, y);
×
626
}
×
627

628
static void writeExtent(FILE *stream, int indent, const char *name,
8✔
629
                        rectObj extent) {
630
  if (!MS_VALID_EXTENT(extent))
8✔
631
    return;
632
  writeIndent(stream, ++indent);
633
  msIO_fprintf(stream, "%s %.15g %.15g %.15g %.15g\n", name, extent.minx,
2✔
634
               extent.miny, extent.maxx, extent.maxy);
635
}
636

637
static void writeNumber(FILE *stream, int indent, const char *name,
370✔
638
                        double defaultNumber, double number) {
639
  if (number == defaultNumber)
370✔
640
    return; /* don't output default */
641
  writeIndent(stream, ++indent);
642
  msIO_fprintf(stream, "%s %.15g\n", name, number);
25✔
643
}
644

645
static void writeCharacter(FILE *stream, int indent, const char *name,
6✔
646
                           const char defaultCharacter, char character) {
647
  if (defaultCharacter == character)
6✔
648
    return;
649
  writeIndent(stream, ++indent);
650
  msIO_fprintf(stream, "%s '%c'\n", name, character);
×
651
}
652

653
static void writeStringElement(FILE *stream, const char *string) {
85✔
654
  char *string_to_free = NULL;
655
  const char *string_escaped;
656

657
  if (strchr(string, '\\')) {
85✔
658
    string_to_free = msStrdup(string);
×
659
    string_to_free = msReplaceSubstring(string_to_free, "\\", "\\\\");
×
660
    string_escaped = string_to_free;
661
  } else {
662
    string_escaped = string;
663
  }
664
  if ((strchr(string_escaped, '\'') == NULL) &&
85✔
665
      (strchr(string_escaped, '\"') == NULL))
85✔
666
    msIO_fprintf(stream, "\"%s\"", string_escaped);
85✔
667
  else if ((strchr(string_escaped, '\"') != NULL) &&
×
668
           (strchr(string_escaped, '\'') == NULL))
669
    msIO_fprintf(stream, "'%s'", string_escaped);
×
670
  else if ((strchr(string_escaped, '\'') != NULL) &&
×
671
           (strchr(string_escaped, '\"') == NULL))
672
    msIO_fprintf(stream, "\"%s\"", string_escaped);
×
673
  else {
674
    char *string_tmp = msStringEscape(string_escaped);
×
675
    msIO_fprintf(stream, "\"%s\"", string_tmp);
×
676
    if (string_escaped != string_tmp)
×
677
      free(string_tmp);
×
678
  }
679
  if (string_to_free)
85✔
680
    free(string_to_free);
×
681
}
85✔
682

683
static void writeString(FILE *stream, int indent, const char *name,
253✔
684
                        const char *defaultString, const char *string) {
685
  if (!string)
253✔
686
    return;
687
  if (defaultString && strcmp(string, defaultString) == 0)
58✔
688
    return;
689
  writeIndent(stream, ++indent);
690
  if (name)
53✔
691
    msIO_fprintf(stream, "%s ", name);
45✔
692
  writeStringElement(stream, string);
53✔
693
  writeLineFeed(stream);
694
}
695

696
static void writeNumberOrString(FILE *stream, int indent, const char *name,
11✔
697
                                double defaultNumber, double number,
698
                                char *string) {
699
  if (string)
11✔
700
    writeString(stream, indent, name, NULL, string);
2✔
701
  else
702
    writeNumber(stream, indent, name, defaultNumber, number);
9✔
703
}
11✔
704

705
static void writeNumberOrKeyword(FILE *stream, int indent, const char *name,
23✔
706
                                 double defaultNumber, double number, int value,
707
                                 int size, ...) {
708
  va_list argp;
709
  int i, j = 0;
710
  const char *s;
711

712
  va_start(argp, size);
23✔
713
  while (j < size) { /* check each value/keyword mapping in the list */
52✔
714
    i = va_arg(argp, int);
29✔
715
    s = va_arg(argp, const char *);
29✔
716
    if (value == i) {
29✔
717
      writeIndent(stream, ++indent);
718
      msIO_fprintf(stream, "%s %s\n", name, s);
×
719
      va_end(argp);
×
720
      return;
×
721
    }
722
    j++;
29✔
723
  }
724
  va_end(argp);
23✔
725

726
  writeNumber(stream, indent, name, defaultNumber, number);
23✔
727
}
728

729
static void writeNameValuePair(FILE *stream, int indent, const char *name,
14✔
730
                               const char *value) {
731
  if (!name || !value)
14✔
732
    return;
733
  writeIndent(stream, ++indent);
734

735
  writeStringElement(stream, (char *)name);
14✔
736
  msIO_fprintf(stream, "\t");
14✔
737
  writeStringElement(stream, (char *)value);
14✔
738
  writeLineFeed(stream);
739
}
740

741
static void writeAttributeBinding(FILE *stream, int indent, const char *name,
×
742
                                  attributeBindingObj *binding) {
743
  if (!binding || !binding->item)
×
744
    return;
745
  writeIndent(stream, ++indent);
746
  msIO_fprintf(stream, "%s [%s]\n", name, binding->item);
×
747
}
748

749
static void writeColor(FILE *stream, int indent, const char *name,
55✔
750
                       colorObj *defaultColor, colorObj *color) {
751
  if (!defaultColor && !MS_VALID_COLOR(*color))
55✔
752
    return;
753
  else if (defaultColor && MS_COMPARE_COLOR(*defaultColor, *color))
23✔
754
    return; /* if defaultColor has the same value than the color, return.*/
755

756
  writeIndent(stream, ++indent);
757
#if ALPHACOLOR_ENABLED
758
  msIO_fprintf(stream, "%s %d %d %d\n", name, color->red, color->green,
759
               color->blue, color->alpha);
760
#else
761
  if (color->alpha != 255) {
13✔
762
    char buffer[9];
763
    sprintf(buffer, "%02x", color->red);
×
764
    sprintf(buffer + 2, "%02x", color->green);
×
765
    sprintf(buffer + 4, "%02x", color->blue);
×
766
    sprintf(buffer + 6, "%02x", color->alpha);
×
767
    *(buffer + 8) = 0;
×
768
    msIO_fprintf(stream, "%s \"#%s\"\n", name, buffer);
×
769
  } else {
770
    msIO_fprintf(stream, "%s %d %d %d\n", name, color->red, color->green,
13✔
771
                 color->blue);
772
  }
773
#endif
774
}
775

776
/* todo: deal with alpha's... */
777
static void writeColorRange(FILE *stream, int indent, const char *name,
×
778
                            colorObj *mincolor, colorObj *maxcolor) {
779
  if (!MS_VALID_COLOR(*mincolor) || !MS_VALID_COLOR(*maxcolor))
×
780
    return;
781
  writeIndent(stream, ++indent);
782
  msIO_fprintf(stream, "%s %d %d %d  %d %d %d\n", name, mincolor->red,
×
783
               mincolor->green, mincolor->blue, maxcolor->red, maxcolor->green,
784
               maxcolor->blue);
785
}
786

787
/*
788
** Initialize, load and free a single join
789
*/
790
void initJoin(joinObj *join) {
×
791
  join->numitems = 0;
×
792

793
  join->name = NULL; /* unique join name, used for variable substitution */
×
794

795
  join->items = NULL;  /* array to hold item names for the joined table */
×
796
  join->values = NULL; /* arrays of strings to holds one record worth of data */
×
797

798
  join->table = NULL;
×
799

800
  join->joininfo = NULL;
×
801

802
  join->from = NULL; /* join items */
×
803
  join->to = NULL;
×
804

805
  join->header = NULL;
×
806
  join->template = NULL; /* only html type templates are supported */
×
807
  join->footer = NULL;
×
808

809
  join->type = MS_JOIN_ONE_TO_ONE;
×
810

811
  join->connection = NULL;
×
812
  join->connectiontype = MS_DB_XBASE;
×
813
}
×
814

815
void freeJoin(joinObj *join) {
×
816
  msFree(join->name);
×
817
  msFree(join->table);
×
818
  msFree(join->from);
×
819
  msFree(join->to);
×
820

821
  msFree(join->header);
×
822
  msFree(join->template);
×
823
  msFree(join->footer);
×
824

825
  msFreeCharArray(join->items,
×
826
                  join->numitems); /* these may have been free'd elsewhere */
827
  msFreeCharArray(join->values, join->numitems);
×
828
  join->numitems = 0;
×
829

830
  msJoinClose(join);
×
831
  msFree(join->connection);
×
832
}
×
833

834
int loadJoin(joinObj *join) {
×
835
  int nTmp;
836
  initJoin(join);
×
837

838
  for (;;) {
839
    switch (msyylex()) {
×
840
    case (CONNECTION):
×
841
      if (getString(&join->connection) == MS_FAILURE)
×
842
        return (-1);
843
      break;
844
    case (CONNECTIONTYPE):
×
845
      if ((nTmp = getSymbol(5, MS_DB_XBASE, MS_DB_MYSQL, MS_DB_ORACLE,
×
846
                            MS_DB_POSTGRES, MS_DB_CSV)) == -1)
847
        return (-1);
848
      join->connectiontype = nTmp;
×
849
      break;
×
850
    case (EOF):
×
851
      msSetError(MS_EOFERR, NULL, "loadJoin()");
×
852
      return (-1);
×
853
    case (END):
×
854
      if ((join->from == NULL) || (join->to == NULL) || (join->table == NULL)) {
×
855
        msSetError(MS_EOFERR,
×
856
                   "Join must define table, name, from and to properties.",
857
                   "loadJoin()");
858
        return (-1);
×
859
      }
860
      if ((join->type == MS_MULTIPLE) &&
×
861
          ((join->template == NULL) || (join->name == NULL))) {
×
862
        msSetError(
×
863
            MS_EOFERR,
864
            "One-to-many joins must define template and name properties.",
865
            "loadJoin()");
866
        return (-1);
×
867
      }
868
      return (0);
869
    case (FOOTER):
×
870
      if (getString(&join->footer) == MS_FAILURE)
×
871
        return (-1);
872
      break;
873
    case (FROM):
×
874
      if (getString(&join->from) == MS_FAILURE)
×
875
        return (-1);
876
      break;
877
    case (HEADER):
×
878
      if (getString(&join->header) == MS_FAILURE)
×
879
        return (-1);
880
      break;
881
    case (JOIN):
882
      break; /* for string loads */
883
    case (NAME):
×
884
      if (getString(&join->name) == MS_FAILURE)
×
885
        return (-1);
886
      break;
887
    case (TABLE):
×
888
      if (getString(&join->table) == MS_FAILURE)
×
889
        return (-1);
890
      break;
891
    case (TEMPLATE):
×
892
      if (getString(&join->template) == MS_FAILURE)
×
893
        return (-1);
894
      break;
895
    case (TO):
×
896
      if (getString(&join->to) == MS_FAILURE)
×
897
        return (-1);
898
      break;
899
    case (TYPE):
×
900
      if ((nTmp = getSymbol(2, MS_JOIN_ONE_TO_ONE, MS_JOIN_ONE_TO_MANY)) == -1)
×
901
        return (-1);
902
      join->type = nTmp;
×
903
      break;
×
904
    default:
×
905
      msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadJoin()",
×
906
                 msyystring_buffer, msyylineno);
907
      return (-1);
×
908
    }
909
  } /* next token */
910
}
911

912
static void writeScaleToken(FILE *stream, int indent, scaleTokenObj *token) {
×
913
  int i;
914
  indent++;
×
915
  writeBlockBegin(stream, indent, "SCALETOKEN");
×
916
  writeString(stream, indent, "NAME", NULL, token->name);
×
917
  indent++;
×
918
  writeBlockBegin(stream, indent, "VALUES");
×
919
  for (i = 0; i < token->n_entries; i++) {
×
920
    char minscale[32];
921
    sprintf(minscale, "%g", token->tokens[i].minscale);
×
922
    writeNameValuePair(stream, indent, minscale, token->tokens[i].value);
×
923
  }
924
  writeBlockEnd(stream, indent, "VALUES");
×
925
  indent--;
926
  writeBlockEnd(stream, indent, "SCALETOKEN");
×
927
}
×
928

929
static void writeJoin(FILE *stream, int indent, joinObj *join) {
×
930
  indent++;
×
931
  writeBlockBegin(stream, indent, "JOIN");
×
932
  writeString(stream, indent, "FOOTER", NULL, join->footer);
×
933
  writeString(stream, indent, "FROM", NULL, join->from);
×
934
  writeString(stream, indent, "HEADER", NULL, join->header);
×
935
  writeString(stream, indent, "NAME", NULL, join->name);
×
936
  writeString(stream, indent, "TABLE", NULL, join->table);
×
937
  writeString(stream, indent, "TEMPLATE", NULL, join->template);
×
938
  writeString(stream, indent, "TO", NULL, join->to);
×
939
  writeKeyword(stream, indent, "CONNECTIONTYPE", join->connectiontype, 3,
×
940
               MS_DB_CSV, "CSV", MS_DB_POSTGRES, "POSTGRESQL", MS_DB_MYSQL,
941
               "MYSQL");
942
  writeKeyword(stream, indent, "TYPE", join->type, 1, MS_JOIN_ONE_TO_MANY,
×
943
               "ONE-TO-MANY");
944
  writeBlockEnd(stream, indent, "JOIN");
×
945
}
×
946

947
/* inserts a feature at the end of the list, can create a new list */
948
featureListNodeObjPtr insertFeatureList(featureListNodeObjPtr *list,
3,162✔
949
                                        shapeObj *shape) {
950
  featureListNodeObjPtr node;
951

952
  node = (featureListNodeObjPtr)msSmallMalloc(sizeof(featureListNodeObj));
3,162✔
953

954
  msInitShape(&(node->shape));
3,162✔
955
  if (msCopyShape(shape, &(node->shape)) == -1) {
3,162✔
956
    msFree(node);
×
957
    return (NULL);
×
958
  }
959

960
  /* AJS - alans@wunderground.com O(n^2) -> O(n) conversion, keep a pointer to
961
   * the end */
962

963
  /* set the tailifhead to NULL, since it is only set for the head of the list
964
   */
965
  node->tailifhead = NULL;
3,162✔
966
  node->next = NULL;
3,162✔
967

968
  /* if we are at the head of the list, we need to set the list to node, before
969
   * pointing tailifhead somewhere  */
970
  if (*list == NULL) {
3,162✔
971
    *list = node;
2,471✔
972
  } else {
973
    if ((*list)->tailifhead !=
691✔
974
        NULL) /* this should never be NULL, but just in case */
975
      (*list)->tailifhead->next =
691✔
976
          node; /* put the node at the end of the list */
977
  }
978

979
  /* repoint the head of the list to the end  - our new element
980
     this causes a loop if we are at the head, be careful not to
981
     walk in a loop */
982
  (*list)->tailifhead = node;
3,162✔
983

984
  return (node); /* a pointer to last object in the list */
3,162✔
985
}
986

987
void freeFeatureList(featureListNodeObjPtr list) {
2,454✔
988
  featureListNodeObjPtr listNext = NULL;
989
  while (list != NULL) {
5,599✔
990
    listNext = list->next;
3,145✔
991
    msFreeShape(&(list->shape));
3,145✔
992
    msFree(list);
3,145✔
993
    list = listNext;
994
  }
995
}
2,454✔
996

997
/* lineObj = multipointObj */
998
static int loadFeaturePoints(lineObj *points) {
999
  int ret = -1;
1000
  int buffer_size = 0;
1001

1002
  points->point = (pointObj *)malloc(sizeof(pointObj) * MS_FEATUREINITSIZE);
1003
  MS_CHECK_ALLOC(points->point, sizeof(pointObj) * MS_FEATUREINITSIZE,
1004
                 MS_FAILURE);
1005
  points->numpoints = 0;
1006
  buffer_size = MS_FEATUREINITSIZE;
1007

1008
  while (ret < 0) {
1009
    switch (msyylex()) {
1010
    case (EOF):
1011
      msSetError(MS_EOFERR, NULL, "loadFeaturePoints()");
1012
      ret = MS_FAILURE;
1013
      break;
1014
    case (END):
1015
      ret = MS_SUCCESS;
1016
      break;
1017
    case (MS_NUMBER):
1018
      if (points->numpoints == buffer_size) { /* just add it to the end */
1019
        pointObj *newPoints = (pointObj *)realloc(
1020
            points->point,
1021
            sizeof(pointObj) * (buffer_size + MS_FEATUREINCREMENT));
1022
        if (newPoints == NULL) {
1023
          msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n",
1024
                     __FUNCTION__, __FILE__, __LINE__,
1025
                     (unsigned int)(sizeof(pointObj) *
1026
                                    (buffer_size + MS_FEATUREINCREMENT)));
1027
          ret = MS_FAILURE;
1028
          break;
1029
        }
1030
        points->point = newPoints;
1031
        buffer_size += MS_FEATUREINCREMENT;
1032
      }
1033

1034
      points->point[points->numpoints].x = atof(msyystring_buffer);
1035
      if (getDouble(&(points->point[points->numpoints].y), MS_NUM_CHECK_NONE,
1036
                    -1, -1) == -1) {
1037
        ret = MS_FAILURE;
1038
        break;
1039
      }
1040
      points->numpoints++;
1041
      break;
1042
    default:
1043
      msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
1044
                 "loadFeaturePoints()", msyystring_buffer, msyylineno);
1045
      ret = MS_FAILURE;
1046
      break;
1047
    }
1048
  }
1049

1050
  if (ret == MS_FAILURE) {
1051
    msFree(points->point); /* clean up */
1052
    points->point = NULL;
1053
    points->numpoints = 0;
1054
  }
1055
  return ret;
1056
}
1057

1058
static int loadFeature(layerObj *player, int type) {
2,798✔
1059
  int status = MS_SUCCESS;
1060
  featureListNodeObjPtr *list = &(player->features);
2,798✔
1061
  multipointObj points = {0, NULL};
2,798✔
1062
  shapeObj *shape = NULL;
1063

1064
  shape = (shapeObj *)malloc(sizeof(shapeObj));
2,798✔
1065
  MS_CHECK_ALLOC(shape, sizeof(shapeObj), MS_FAILURE);
2,798✔
1066

1067
  msInitShape(shape);
2,798✔
1068
  shape->type = type;
2,798✔
1069

1070
  for (;;) {
1071
    switch (msyylex()) {
6,732✔
1072
    case (EOF):
×
1073
      msSetError(MS_EOFERR, NULL, "loadFeature()");
×
1074
      msFreeShape(shape); /* clean up */
×
1075
      msFree(shape);
×
1076
      return (MS_FAILURE);
×
1077
    case (END):
2,798✔
1078
      if (player->features != NULL && player->features->tailifhead != NULL)
2,798✔
1079
        shape->index = player->features->tailifhead->shape.index + 1;
446✔
1080
      else
1081
        shape->index = 0;
2,352✔
1082
      if (insertFeatureList(list, shape) == NULL)
2,798✔
1083
        status = MS_FAILURE;
1084

1085
      msFreeShape(shape); /* clean up */
2,798✔
1086
      msFree(shape);
2,798✔
1087

1088
      return (status);
2,798✔
1089
    case (FEATURE):
1090
      break; /* for string loads */
1091
    case (POINTS):
2,786✔
1092
      if (loadFeaturePoints(&points) == MS_FAILURE) {
2,786✔
1093
        msFreeShape(shape); /* clean up */
×
1094
        msFree(shape);
×
1095
        return (MS_FAILURE);
×
1096
      }
1097
      status = msAddLine(shape, &points);
2,786✔
1098

1099
      msFree(points.point); /* clean up */
2,786✔
1100
      points.numpoints = 0;
2,786✔
1101

1102
      if (status == MS_FAILURE) {
2,786✔
1103
        msFreeShape(shape); /* clean up */
×
1104
        msFree(shape);
×
1105
        return (MS_FAILURE);
×
1106
      }
1107
      break;
1108
    case (ITEMS): {
73✔
1109
      char *string = NULL;
73✔
1110
      if (getString(&string) == MS_FAILURE) {
73✔
1111
        msFreeShape(shape); /* clean up */
×
1112
        msFree(shape);
×
1113
        return (MS_FAILURE);
×
1114
      }
1115
      if (string) {
73✔
1116
        if (shape->values)
73✔
1117
          msFreeCharArray(shape->values, shape->numvalues);
×
1118
        shape->values = msStringSplitComplex(string, ";", &shape->numvalues,
73✔
1119
                                             MS_ALLOWEMPTYTOKENS);
1120
        msFree(string); /* clean up */
73✔
1121
      }
1122
      break;
73✔
1123
    }
1124
    case (TEXT):
1,059✔
1125
      if (getString(&shape->text) == MS_FAILURE) {
1,059✔
1126
        msFreeShape(shape); /* clean up */
×
1127
        msFree(shape);
×
1128
        return (MS_FAILURE);
×
1129
      }
1130
      break;
1131
    case (WKT): {
16✔
1132
      char *string = NULL;
16✔
1133

1134
      /* todo, what do we do with multiple WKT property occurrences? */
1135

1136
      msFreeShape(shape);
16✔
1137
      msFree(shape);
16✔
1138
      if (getString(&string) == MS_FAILURE)
16✔
1139
        return (MS_FAILURE);
×
1140

1141
      if ((shape = msShapeFromWKT(string)) == NULL)
16✔
1142
        status = MS_FAILURE;
1143

1144
      msFree(string); /* clean up */
16✔
1145

1146
      if (status == MS_FAILURE) {
16✔
1147
        msFreeShape(shape); /* clean up */
×
1148
        msFree(shape);
×
1149
        return (MS_FAILURE);
×
1150
      }
1151
      break;
16✔
1152
    }
1153
    default:
×
1154
      msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
1155
                 "loadfeature()", msyystring_buffer, msyylineno);
1156
      msFreeShape(shape); /* clean up */
×
1157
      msFree(shape);
×
1158
      return (MS_FAILURE);
×
1159
    }
1160
  } /* next token */
1161
}
1162

1163
static void writeFeature(FILE *stream, int indent, shapeObj *feature) {
3✔
1164
  int i, j;
1165

1166
  indent++;
3✔
1167
  writeBlockBegin(stream, indent, "FEATURE");
3✔
1168

1169
  indent++;
3✔
1170
  for (i = 0; i < feature->numlines; i++) {
6✔
1171
    writeBlockBegin(stream, indent, "POINTS");
3✔
1172
    for (j = 0; j < feature->line[i].numpoints; j++) {
6✔
1173
      writeIndent(stream, indent);
1174
      msIO_fprintf(stream, "%.15g %.15g\n", feature->line[i].point[j].x,
3✔
1175
                   feature->line[i].point[j].y);
3✔
1176
    }
1177
    writeBlockEnd(stream, indent, "POINTS");
3✔
1178
  }
1179
  indent--;
1180

1181
  if (feature->numvalues) {
3✔
1182
    writeIndent(stream, indent);
1183
    msIO_fprintf(stream, "ITEMS \"");
×
1184
    for (i = 0; i < feature->numvalues; i++) {
×
1185
      if (i == 0)
×
1186
        msIO_fprintf(stream, "%s", feature->values[i]);
×
1187
      else
1188
        msIO_fprintf(stream, ";%s", feature->values[i]);
×
1189
    }
1190
    msIO_fprintf(stream, "\"\n");
×
1191
  }
1192

1193
  writeString(stream, indent, "TEXT", NULL, feature->text);
3✔
1194
  writeBlockEnd(stream, indent, "FEATURE");
3✔
1195
}
3✔
1196

1197
void initGrid(graticuleObj *pGraticule) {
8✔
1198
  memset(pGraticule, 0, sizeof(graticuleObj));
1199
}
8✔
1200

1201
void freeGrid(graticuleObj *pGraticule) {
8✔
1202
  msFree(pGraticule->labelformat);
8✔
1203
  msFree(pGraticule->pboundingpoints);
8✔
1204
  msFree(pGraticule->pboundinglines);
8✔
1205
}
8✔
1206

1207
static int loadGrid(layerObj *pLayer) {
1208
  for (;;) {
1209
    switch (msyylex()) {
1210
    case (EOF):
1211
      msSetError(MS_EOFERR, NULL, "loadGrid()");
1212
      return (-1);
1213
    case (END):
1214
      return (0);
1215
    case (GRID):
1216
      break; /* for string loads */
1217
    case (LABELFORMAT):
1218
      if (getString(&(pLayer->grid->labelformat)) == MS_FAILURE) {
1219
        if (strcasecmp(msyystring_buffer, "DD") ==
1220
            0) /* DD triggers a symbol to be returned instead of a string so
1221
                  check for this special case */
1222
        {
1223
          msFree(pLayer->grid->labelformat);
1224
          pLayer->grid->labelformat = msStrdup("DD");
1225
        } else
1226
          return (-1);
1227
      }
1228
      break;
1229
    case (MINARCS):
1230
      if (getDouble(&(pLayer->grid->minarcs), MS_NUM_CHECK_GT, 0, -1) == -1)
1231
        return (-1);
1232
      break;
1233
    case (MAXARCS):
1234
      if (getDouble(&(pLayer->grid->maxarcs), MS_NUM_CHECK_GT, 0, -1) == -1)
1235
        return (-1);
1236
      break;
1237
    case (MININTERVAL):
1238
      if (getDouble(&(pLayer->grid->minincrement), MS_NUM_CHECK_GT, 0, -1) ==
1239
          -1)
1240
        return (-1);
1241
      break;
1242
    case (MAXINTERVAL):
1243
      if (getDouble(&(pLayer->grid->maxincrement), MS_NUM_CHECK_GT, 0, -1) ==
1244
          -1)
1245
        return (-1);
1246
      break;
1247
    case (MINSUBDIVIDE):
1248
      if (getDouble(&(pLayer->grid->minsubdivides), MS_NUM_CHECK_GT, 0, -1) ==
1249
          -1)
1250
        return (-1);
1251
      break;
1252
    case (MAXSUBDIVIDE):
1253
      if (getDouble(&(pLayer->grid->maxsubdivides), MS_NUM_CHECK_GT, 0, -1) ==
1254
          -1)
1255
        return (-1);
1256
      break;
1257
    default:
1258
      msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)", "loadGrid()",
1259
                 msyystring_buffer, msyylineno);
1260
      return (-1);
1261
    }
1262
  }
1263
}
1264

1265
static void writeGrid(FILE *stream, int indent, graticuleObj *pGraticule) {
×
1266
  if (!pGraticule)
×
1267
    return;
1268

1269
  indent++;
×
1270
  writeBlockBegin(stream, indent, "GRID");
×
1271
  writeString(stream, indent, "LABELFORMAT", NULL, pGraticule->labelformat);
×
1272
  writeNumber(stream, indent, "MAXARCS", 0, pGraticule->maxarcs);
×
1273
  writeNumber(stream, indent, "MAXSUBDIVIDE", 0, pGraticule->maxsubdivides);
×
1274
  writeNumber(stream, indent, "MAXINTERVAL", 0, pGraticule->maxincrement);
×
1275
  writeNumber(stream, indent, "MINARCS", 0, pGraticule->minarcs);
×
1276
  writeNumber(stream, indent, "MININTERVAL", 0, pGraticule->minincrement);
×
1277
  writeNumber(stream, indent, "MINSUBDIVIDE", 0, pGraticule->minsubdivides);
×
1278
  writeBlockEnd(stream, indent, "GRID");
×
1279
}
1280

1281
static int loadProjection(projectionObj *p) {
11,002✔
1282
  p->gt.need_geotransform = MS_FALSE;
11,002✔
1283

1284
  if (p->proj != NULL || p->numargs != 0) {
11,002✔
1285
    msSetError(MS_MISCERR,
×
1286
               "Projection is already initialized. Multiple projection "
1287
               "definitions are not allowed in this object. (line %d)",
1288
               "loadProjection()", msyylineno);
1289
    return (-1);
×
1290
  }
1291

1292
  for (;;) {
1293
    switch (msyylex()) {
22,313✔
1294
    case (EOF):
×
1295
      msSetError(MS_EOFERR, NULL, "loadProjection()");
×
1296
      return (-1);
×
1297
    case (END):
11,002✔
1298
      if (p->numargs == 1 && strstr(p->args[0], "+") != NULL) {
11,002✔
1299
        char *one_line_def = p->args[0];
1300
        int result;
1301

1302
        p->args[0] = NULL;
515✔
1303
        p->numargs = 0;
515✔
1304
        result = msLoadProjectionString(p, one_line_def);
515✔
1305
        free(one_line_def);
515✔
1306
        return result;
515✔
1307
      } else {
1308
        if (p->numargs != 0)
10,487✔
1309
          return msProcessProjection(p);
10,487✔
1310
        else
1311
          return 0;
1312
      }
1313
      break;
1314
    case (MS_STRING):
11,311✔
1315
    case (MS_AUTO):
1316
      if (p->numargs == MS_MAXPROJARGS) {
11,311✔
1317
        msSetError(MS_MISCERR,
×
1318
                   "Parsing error near (%s):(line %d): Too many arguments in "
1319
                   "projection string",
1320
                   "loadProjection()", msyystring_buffer, msyylineno);
1321
        return -1;
×
1322
      }
1323
      p->args[p->numargs] = msStrdup(msyystring_buffer);
11,311✔
1324
      p->numargs++;
11,311✔
1325
      break;
1326
    default:
×
1327
      msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
1328
                 "loadProjection()", msyystring_buffer, msyylineno);
1329
      return (-1);
×
1330
    }
1331
  } /* next token */
1332
}
1333

1334
/************************************************************************/
1335
/*                     msLoadProjectionStringEPSGLike                   */
1336
/************************************************************************/
1337

1338
static int msLoadProjectionStringEPSGLike(projectionObj *p, const char *value,
1339
                                          const char *pszPrefix,
1340
                                          int bFollowEPSGAxisOrder) {
1341
  size_t buffer_size = 0;
1342
  char *init_string = NULL;
1343
  const char *code;
1344
  const char *next_sep;
1345
  size_t prefix_len;
1346

1347
  prefix_len = strlen(pszPrefix);
1348
  if (strncasecmp(value, pszPrefix, prefix_len) != 0)
1349
    return -1;
1350

1351
  code = value + prefix_len;
1352
  next_sep = strchr(code, pszPrefix[prefix_len - 1]);
1353
  if (next_sep != NULL)
1354
    code = next_sep + 1;
1355

1356
  buffer_size = 10 + strlen(code) + 1;
1357
  init_string = (char *)msSmallMalloc(buffer_size);
1358

1359
  /* translate into PROJ.4 format. */
1360
  snprintf(init_string, buffer_size, "init=epsg:%s", code);
1361

1362
  p->args = (char **)msSmallMalloc(sizeof(char *) * 2);
1363
  p->args[0] = init_string;
1364
  p->numargs = 1;
1365

1366
  if (bFollowEPSGAxisOrder && msIsAxisInverted(atoi(code))) {
1367
    p->args[1] = msStrdup("+epsgaxis=ne");
1368
    p->numargs = 2;
1369
  }
1370

1371
  return 0;
1372
}
1373

1374
/************************************************************************/
1375
/*                     msLoadProjectionStringCRSLike                    */
1376
/************************************************************************/
1377

1378
static int msLoadProjectionStringCRSLike(projectionObj *p, const char *value,
1379
                                         const char *pszPrefix) {
1380
  char init_string[100];
1381
  const char *id;
1382
  const char *next_sep;
1383
  size_t prefix_len;
1384

1385
  prefix_len = strlen(pszPrefix);
1386
  if (strncasecmp(value, pszPrefix, prefix_len) != 0)
1387
    return -1;
1388

1389
  id = value + prefix_len;
1390
  next_sep = strchr(id, pszPrefix[prefix_len - 1]);
1391
  if (next_sep != NULL)
1392
    id = next_sep + 1;
1393

1394
  init_string[0] = '\0';
1395

1396
  if (strcasecmp(id, "84") == 0 || strcasecmp(id, "CRS84") == 0)
1397
    strncpy(init_string, "init=epsg:4326", sizeof(init_string));
1398
  else if (strcasecmp(id, "83") == 0 || strcasecmp(id, "CRS83") == 0)
1399
    strncpy(init_string, "init=epsg:4269", sizeof(init_string));
1400
  else if (strcasecmp(id, "27") == 0 || strcasecmp(id, "CRS27") == 0)
1401
    strncpy(init_string, "init=epsg:4267", sizeof(init_string));
1402
  else {
1403
    msSetError(MS_PROJERR, "Unrecognised OGC CRS def '%s'.",
1404
               "msLoadProjectionString()", value);
1405
    return -1;
1406
  }
1407

1408
  p->args = (char **)msSmallMalloc(sizeof(char *) * 2);
1409
  p->args[0] = msStrdup(init_string);
1410
  p->numargs = 1;
1411

1412
  return 0;
1413
}
1414

1415
/************************************************************************/
1416
/*                         msLoadProjectionStringEPSG                   */
1417
/*                                                                      */
1418
/*      Checks for EPSG type projection and set the axes for a          */
1419
/*      certain code ranges.                                            */
1420
/*      Use for now in WMS 1.3.0 and WFS >= 1.1.0                       */
1421
/************************************************************************/
1422
int msLoadProjectionStringEPSG(projectionObj *p, const char *value) {
3,236✔
1423
  assert(p);
1424

1425
  msFreeProjectionExceptContext(p);
3,236✔
1426

1427
  p->gt.need_geotransform = MS_FALSE;
3,236✔
1428
#ifdef USE_PROJ_FASTPATHS
1429
  if (strcasestr(value, "epsg:4326")) {
1430
    p->wellknownprojection = wkp_lonlat;
1431
  } else if (strcasestr(value, "epsg:3857")) {
1432
    p->wellknownprojection = wkp_gmerc;
1433
  } else {
1434
    p->wellknownprojection = wkp_none;
1435
  }
1436
#endif
1437

1438
  if (msLoadProjectionStringEPSGLike(p, value, "EPSG:", MS_TRUE) == 0) {
3,236✔
1439
    return msProcessProjection(p);
3,198✔
1440
  }
1441

1442
  return msLoadProjectionString(p, value);
38✔
1443
}
1444

1445
int msLoadProjectionCodeString(projectionObj *p, const char *value) {
72✔
1446

1447
  int num_params = 0;
72✔
1448

1449
  // exit if init= is already at the start of the string e.g. from
1450
  // msOGRSpatialRef2ProjectionObj
1451
  if (strncasecmp(value, "init=", 5) == 0) {
72✔
1452
    return -1;
1453
  }
1454

1455
  if (!strchr(value, ':')) {
11✔
1456
    return -1;
1457
  }
1458

1459
  char **papszList = msStringSplit(value, ':', &(num_params));
10✔
1460

1461
  if (num_params != 2) {
10✔
1462
    msFreeCharArray(papszList, num_params);
×
1463
    return -1;
×
1464
  }
1465

1466
  const size_t buffer_size = 5 + strlen(value) + 1;
10✔
1467
  char *init_string = (char *)msSmallMalloc(buffer_size);
10✔
1468

1469
  /* translate into PROJ format. */
1470
  snprintf(init_string, buffer_size, "init=%s:%s", papszList[0], papszList[1]);
10✔
1471

1472
  p->args = (char **)msSmallMalloc(sizeof(char *));
10✔
1473
  p->args[0] = init_string;
10✔
1474
  p->numargs = 1;
10✔
1475

1476
  msFreeCharArray(papszList, num_params);
10✔
1477

1478
  return 0;
10✔
1479
}
1480

1481
int msLoadProjectionString(projectionObj *p, const char *value) {
2,873✔
1482
  assert(p);
1483
  p->gt.need_geotransform = MS_FALSE;
2,873✔
1484

1485
  msFreeProjectionExceptContext(p);
2,873✔
1486

1487
  /*
1488
   * Handle new style definitions, the same as they would be given to
1489
   * the proj program.
1490
   * eg.
1491
   *    "+proj=utm +zone=11 +ellps=WGS84"
1492
   */
1493
  if (value[0] == '+') {
2,873✔
1494
    char *trimmed;
1495
    int i, i_out = 0;
1496

1497
    trimmed = msStrdup(value + 1);
1,059✔
1498
    for (i = 1; value[i] != '\0'; i++) {
36,189✔
1499
      if (!isspace(value[i]))
35,130✔
1500
        trimmed[i_out++] = value[i];
33,101✔
1501
    }
1502
    trimmed[i_out] = '\0';
1,059✔
1503

1504
    p->args = msStringSplit(trimmed, '+', &p->numargs);
1,059✔
1505
    free(trimmed);
1,059✔
1506
  } else if (strncasecmp(value, "AUTO:", 5) == 0 ||
1,814✔
1507
             strncasecmp(value, "AUTO2:", 6) == 0) {
1,814✔
1508
    /* WMS/WFS AUTO projection: "AUTO:proj_id,units_id,lon0,lat0" */
1509
    /* WMS 1.3.0 projection: "AUTO2:auto_crs_id,factor,lon0,lat0"*/
1510
    /* Keep the projection defn into a single token for writeProjection() */
1511
    /* to work fine. */
1512
    p->args = (char **)msSmallMalloc(sizeof(char *));
×
1513
    p->args[0] = msStrdup(value);
×
1514
    p->numargs = 1;
×
1515
  } else if (msLoadProjectionStringEPSGLike(p, value, "EPSG:", MS_FALSE) == 0) {
1,814✔
1516
    /* Assume long/lat ordering. Use msLoadProjectionStringEPSG() if wanting to
1517
     * follow EPSG axis */
1518
  } else if (msLoadProjectionStringEPSGLike(
198✔
1519
                 p, value, "urn:ogc:def:crs:EPSG:", MS_TRUE) == 0) {
1520
  } else if (msLoadProjectionStringEPSGLike(
119✔
1521
                 p, value, "urn:EPSG:geographicCRS:", MS_TRUE) == 0) {
1522
  } else if (msLoadProjectionStringEPSGLike(
115✔
1523
                 p, value, "urn:x-ogc:def:crs:EPSG:", MS_TRUE) == 0) {
1524
    /*this case is to account for OGC CITE tests where x-ogc was used
1525
      before the ogc name became an official NID. Note also we also account
1526
      for the fact that a space for the version of the espg is not used with
1527
      CITE tests. (Syntax used could be urn:ogc:def:objectType:authority:code)*/
1528
  } else if (msLoadProjectionStringCRSLike(p, value, "urn:ogc:def:crs:OGC:") ==
115✔
1529
             0) {
1530
  } else if (msLoadProjectionStringEPSGLike(
109✔
1531
                 p, value, "http://www.opengis.net/def/crs/EPSG/", MS_TRUE) ==
1532
             0) {
1533
    /* URI projection support */
1534
  } else if (msLoadProjectionStringCRSLike(
83✔
1535
                 p, value, "http://www.opengis.net/def/crs/OGC/") == 0) {
1536
    /* Mandatory support for this URI format specified in WFS1.1 (also in 1.0?)
1537
     */
1538
  } else if (msLoadProjectionStringEPSGLike(
83✔
1539
                 p, value, "http://www.opengis.net/gml/srs/epsg.xml#",
1540
                 MS_FALSE) == 0) {
1541
    /* We assume always long/lat ordering, as that is what GeoServer does... */
1542
  } else if (msLoadProjectionStringCRSLike(p, value, "CRS:") == 0) {
80✔
1543
  } else if (msLoadProjectionCodeString(p, value) == 0) {
72✔
1544
    /* allow strings in the form AUTH:XXXX */
1545
  }
1546
  /*
1547
   * Handle old style comma delimited.  eg. "proj=utm,zone=11,ellps=WGS84".
1548
   */
1549
  else {
1550
    p->args = msStringSplit(value, ',', &p->numargs);
62✔
1551
  }
1552

1553
  return msProcessProjection(p);
2,873✔
1554
}
1555

1556
static void writeProjection(FILE *stream, int indent, projectionObj *p) {
8✔
1557
  int i;
1558

1559
  if (!p || p->numargs <= 0)
8✔
1560
    return;
1561
  indent++;
8✔
1562
  writeBlockBegin(stream, indent, "PROJECTION");
8✔
1563
  for (i = 0; i < p->numargs; i++)
16✔
1564
    writeString(stream, indent, NULL, NULL, p->args[i]);
8✔
1565
  writeBlockEnd(stream, indent, "PROJECTION");
8✔
1566
}
1567

1568
void initLeader(labelLeaderObj *leader) {
16✔
1569
  leader->gridstep = 5;
16✔
1570
  leader->maxdistance = 0;
16✔
1571

1572
  /* Set maxstyles = 0, styles[] will be allocated as needed on first call
1573
   * to msGrowLabelLeaderStyles()
1574
   */
1575
  leader->numstyles = leader->maxstyles = 0;
16✔
1576
  leader->styles = NULL;
16✔
1577
}
16✔
1578

1579
/*
1580
** Initialize, load and free a labelObj structure
1581
*/
1582
void initLabel(labelObj *label) {
18,585✔
1583
  int i;
1584

1585
  MS_REFCNT_INIT(label);
18,585✔
1586

1587
  label->align = MS_ALIGN_DEFAULT;
18,585✔
1588
  MS_INIT_COLOR(label->color, 0, 0, 0, 255);
18,585✔
1589
  MS_INIT_COLOR(label->outlinecolor, -1, -1, -1, 255); /* don't use it */
18,585✔
1590
  label->outlinewidth = 1;
18,585✔
1591

1592
  MS_INIT_COLOR(label->shadowcolor, -1, -1, -1, 255); /* don't use it */
18,585✔
1593
  label->shadowsizex = label->shadowsizey = 1;
18,585✔
1594

1595
  label->font = NULL;
18,585✔
1596
  label->size = MS_MEDIUM;
18,585✔
1597

1598
  label->position = MS_CC;
18,585✔
1599
  label->angle = 0;
18,585✔
1600
  label->anglemode = MS_NONE;
18,585✔
1601
  label->minsize = MS_MINFONTSIZE;
18,585✔
1602
  label->maxsize = MS_MAXFONTSIZE;
18,585✔
1603
  label->buffer = 0;
18,585✔
1604
  label->offsetx = label->offsety = 0;
18,585✔
1605
  label->minscaledenom = -1;
18,585✔
1606
  label->maxscaledenom = -1;
18,585✔
1607
  label->minfeaturesize = -1; /* no limit */
18,585✔
1608
  label->autominfeaturesize = MS_FALSE;
18,585✔
1609
  label->mindistance = -1;       /* no limit */
18,585✔
1610
  label->repeatdistance = 0;     /* no repeat */
18,585✔
1611
  label->maxoverlapangle = 22.5; /* default max overlap angle */
18,585✔
1612
  label->partials = MS_FALSE;
18,585✔
1613
  label->wrap = '\0';
18,585✔
1614
  label->maxlength = 0;
18,585✔
1615
  label->space_size_10 = 0.0;
18,585✔
1616

1617
  label->encoding = NULL;
18,585✔
1618

1619
  label->force = MS_OFF;
18,585✔
1620
  label->priority = MS_DEFAULT_LABEL_PRIORITY;
18,585✔
1621

1622
  /* Set maxstyles = 0, styles[] will be allocated as needed on first call
1623
   * to msGrowLabelStyles()
1624
   */
1625
  label->numstyles = label->maxstyles = 0;
18,585✔
1626
  label->styles = NULL;
18,585✔
1627

1628
  label->numbindings = 0;
18,585✔
1629
  label->nexprbindings = 0;
18,585✔
1630
  for (i = 0; i < MS_LABEL_BINDING_LENGTH; i++) {
241,605✔
1631
    label->bindings[i].item = NULL;
223,020✔
1632
    label->bindings[i].index = -1;
223,020✔
1633
    msInitExpression(&(label->exprBindings[i]));
223,020✔
1634
  }
1635

1636
  msInitExpression(&(label->expression));
18,585✔
1637
  msInitExpression(&(label->text));
18,585✔
1638

1639
  label->leader = NULL;
18,585✔
1640

1641
  label->sizeunits = MS_INHERIT;
18,585✔
1642
  label->scalefactor = 1.0;
18,585✔
1643

1644
  return;
18,585✔
1645
}
1646

1647
int freeLabelLeader(labelLeaderObj *leader) {
16✔
1648
  int i;
1649
  for (i = 0; i < leader->numstyles; i++) {
32✔
1650
    if (freeStyle(leader->styles[i]) == MS_SUCCESS) {
16✔
1651
      msFree(leader->styles[i]);
16✔
1652
    }
1653
  }
1654
  msFree(leader->styles);
16✔
1655

1656
  return MS_SUCCESS;
16✔
1657
}
1658
int freeLabel(labelObj *label) {
22,074✔
1659
  int i;
1660

1661
  if (MS_REFCNT_DECR_IS_NOT_ZERO(label)) {
22,074✔
1662
    return MS_FAILURE;
1663
  }
1664

1665
  msFree(label->font);
18,508✔
1666
  msFree(label->encoding);
18,508✔
1667

1668
  for (i = 0; i < label->numstyles; i++) { /* each style */
24,320✔
1669
    if (label->styles[i] != NULL) {
5,812✔
1670
      if (freeStyle(label->styles[i]) == MS_SUCCESS) {
5,812✔
1671
        msFree(label->styles[i]);
5,808✔
1672
      }
1673
    }
1674
  }
1675
  msFree(label->styles);
18,508✔
1676

1677
  for (i = 0; i < MS_LABEL_BINDING_LENGTH; i++) {
240,604✔
1678
    msFree(label->bindings[i].item);
222,096✔
1679
    msFreeExpression(&(label->exprBindings[i]));
222,096✔
1680
  }
1681

1682
  msFreeExpression(&(label->expression));
18,508✔
1683
  msFreeExpression(&(label->text));
18,508✔
1684

1685
  if (label->leader) {
18,508✔
1686
    freeLabelLeader(label->leader);
×
1687
    msFree(label->leader);
×
1688
    label->leader = NULL;
×
1689
  }
1690

1691
  return MS_SUCCESS;
1692
}
1693

1694
static int loadLeader(labelLeaderObj *leader) {
15✔
1695
  for (;;) {
1696
    switch (msyylex()) {
53✔
1697
    case (END):
1698
      return (0);
1699
      break;
1700
    case (EOF):
×
1701
      msSetError(MS_EOFERR, NULL, "loadLeader()");
×
1702
      return (-1);
×
1703
    case GRIDSTEP:
8✔
1704
      if (getInteger(&(leader->gridstep), MS_NUM_CHECK_GT, 0, -1) == -1)
8✔
1705
        return (-1);
1706
      break;
1707
    case MAXDISTANCE:
15✔
1708
      if (getInteger(&(leader->maxdistance), MS_NUM_CHECK_GT, 0, -1) == -1)
15✔
1709
        return (-1);
1710
      break;
1711
    case STYLE:
15✔
1712
      if (msGrowLeaderStyles(leader) == NULL)
15✔
1713
        return (-1);
1714
      initStyle(leader->styles[leader->numstyles]);
15✔
1715
      if (loadStyle(leader->styles[leader->numstyles]) != MS_SUCCESS) {
15✔
1716
        freeStyle(leader->styles[leader->numstyles]);
×
1717
        free(leader->styles[leader->numstyles]);
×
1718
        leader->styles[leader->numstyles] = NULL;
×
1719
        return -1;
×
1720
      }
1721
      leader->numstyles++;
15✔
1722
      break;
15✔
1723
    default:
×
1724
      if (strlen(msyystring_buffer) > 0) {
×
1725
        msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
1726
                   "loadLeader()", msyystring_buffer, msyylineno);
1727
        return (-1);
×
1728
      } else {
1729
        return (0); /* end of a string, not an error */
1730
      }
1731
    }
1732
  }
1733
}
1734

1735
static int loadLabel(labelObj *label) {
3,582✔
1736
  int symbol;
1737

1738
  for (;;) {
1739
    switch (msyylex()) {
20,796✔
1740
    case (ANGLE):
380✔
1741
      if ((symbol = getSymbol(5, MS_NUMBER, MS_AUTO, MS_AUTO2, MS_FOLLOW,
380✔
1742
                              MS_BINDING)) == -1)
1743
        return (-1);
1744

1745
      if (symbol == MS_NUMBER) {
380✔
1746
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, -360.0, 360.0) ==
290✔
1747
            MS_FAILURE) {
1748
          msSetError(MS_MISCERR,
×
1749
                     "Invalid ANGLE, must be between -360 and 360 (line %d)",
1750
                     "loadLabel()", msyylineno);
1751
          return (MS_FAILURE);
×
1752
        }
1753
        label->angle = (double)msyynumber;
290✔
1754
      } else if (symbol == MS_BINDING) {
90✔
1755
        if (label->bindings[MS_LABEL_BINDING_ANGLE].item != NULL)
×
1756
          msFree(label->bindings[MS_LABEL_BINDING_ANGLE].item);
×
1757
        label->bindings[MS_LABEL_BINDING_ANGLE].item =
×
1758
            msStrdup(msyystring_buffer);
×
1759
        label->numbindings++;
×
1760
      } else {
1761
        label->anglemode = symbol;
90✔
1762
      }
1763
      break;
1764
    case (ALIGN):
196✔
1765
      if ((symbol = getSymbol(4, MS_ALIGN_LEFT, MS_ALIGN_CENTER, MS_ALIGN_RIGHT,
196✔
1766
                              MS_BINDING)) == -1)
1767
        return (-1);
1768
      if ((symbol == MS_ALIGN_LEFT) || (symbol == MS_ALIGN_CENTER) ||
196✔
1769
          (symbol == MS_ALIGN_RIGHT)) {
1770
        label->align = symbol;
194✔
1771
      } else {
1772
        if (label->bindings[MS_LABEL_BINDING_ALIGN].item != NULL)
2✔
1773
          msFree(label->bindings[MS_LABEL_BINDING_ALIGN].item);
×
1774
        label->bindings[MS_LABEL_BINDING_ALIGN].item =
2✔
1775
            msStrdup(msyystring_buffer);
2✔
1776
        label->numbindings++;
2✔
1777
      }
1778
      break;
1779
    case (ANTIALIAS): /*ignore*/
4✔
1780
      msyylex();
4✔
1781
      break;
4✔
1782
    case (BUFFER):
677✔
1783
      if (getInteger(&(label->buffer), MS_NUM_CHECK_NONE, -1, -1) == -1)
677✔
1784
        return (-1);
1785
      break;
1786
    case (COLOR):
3,436✔
1787
      if (loadColor(&(label->color),
3,436✔
1788
                    &(label->bindings[MS_LABEL_BINDING_COLOR])) != MS_SUCCESS)
1789
        return (-1);
1790
      if (label->bindings[MS_LABEL_BINDING_COLOR].item)
3,436✔
1791
        label->numbindings++;
2✔
1792
      break;
1793
    case (ENCODING):
4✔
1794
      if ((getString(&label->encoding)) == MS_FAILURE)
4✔
1795
        return (-1);
1796
      break;
1797
    case (END):
1798
      return (0);
1799
      break;
1800
    case (EOF):
×
1801
      msSetError(MS_EOFERR, NULL, "loadLabel()");
×
1802
      return (-1);
×
1803
    case (EXPRESSION):
112✔
1804
      if (loadExpression(&(label->expression)) == -1)
112✔
1805
        return (-1); /* loadExpression() cleans up previously allocated
1806
                        expression */
1807
      break;
1808
    case (FONT):
2,044✔
1809
      if ((symbol = getSymbol(2, MS_STRING, MS_BINDING)) == -1)
2,044✔
1810
        return (-1);
1811

1812
      if (symbol == MS_STRING) {
2,044✔
1813
        if (label->font != NULL)
2,044✔
1814
          msFree(label->font);
×
1815
        label->font = msStrdup(msyystring_buffer);
2,044✔
1816
      } else {
1817
        if (label->bindings[MS_LABEL_BINDING_FONT].item != NULL)
×
1818
          msFree(label->bindings[MS_LABEL_BINDING_FONT].item);
×
1819
        label->bindings[MS_LABEL_BINDING_FONT].item =
×
1820
            msStrdup(msyystring_buffer);
×
1821
        label->numbindings++;
×
1822
      }
1823
      break;
1824
    case (FORCE):
200✔
1825
      switch (msyylex()) {
200✔
1826
      case MS_ON:
72✔
1827
        label->force = MS_ON;
72✔
1828
        break;
72✔
1829
      case MS_OFF:
×
1830
        label->force = MS_OFF;
×
1831
        break;
×
1832
      case GROUP:
128✔
1833
        label->force = MS_LABEL_FORCE_GROUP;
128✔
1834
        break;
128✔
1835
      default:
×
1836
        msSetError(MS_MISCERR,
×
1837
                   "Invalid FORCE, must be ON,OFF,or GROUP (line %d)",
1838
                   "loadLabel()", msyylineno);
1839
        return (-1);
×
1840
      }
1841
      break;
1842
    case (LABEL):
1843
      break; /* for string loads */
1844
    case (LEADER):
×
1845
      msSetError(MS_MISCERR,
×
1846
                 "LABEL LEADER not implemented. LEADER goes at the CLASS level "
1847
                 "(line %d)",
1848
                 "loadLabel()", msyylineno);
1849
      return (-1);
×
1850
    case (MAXSIZE):
×
1851
      if (getInteger(&(label->maxsize), MS_NUM_CHECK_GT, 0, -1) == -1)
×
1852
        return (-1);
1853
      break;
1854
    case (MAXSCALEDENOM):
×
1855
      if (getDouble(&(label->maxscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1)
×
1856
        return (-1);
1857
      break;
1858
    case (MAXLENGTH):
248✔
1859
      if (getInteger(&(label->maxlength), MS_NUM_CHECK_GT, 0, -1) == -1)
248✔
1860
        return (-1);
1861
      break;
1862
    case (MINDISTANCE):
20✔
1863
      if (getInteger(&(label->mindistance), MS_NUM_CHECK_GT, 0, -1) == -1)
20✔
1864
        return (-1);
1865
      break;
1866
    case (REPEATDISTANCE):
12✔
1867
      if (getInteger(&(label->repeatdistance), MS_NUM_CHECK_GT, 0, -1) == -1)
12✔
1868
        return (-1);
1869
      break;
1870
    case (MAXOVERLAPANGLE):
43✔
1871
      if (getDouble(&(label->maxoverlapangle), MS_NUM_CHECK_RANGE, 0, 360) ==
43✔
1872
          -1)
1873
        return (-1);
1874
      break;
1875
    case (MINFEATURESIZE):
×
1876
      if ((symbol = getSymbol(2, MS_NUMBER, MS_AUTO)) == -1)
×
1877
        return (-1);
1878
      if (symbol == MS_NUMBER) {
×
1879
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_GT, 0, -1) == MS_FAILURE) {
×
1880
          msSetError(MS_MISCERR,
×
1881
                     "Invalid MINFEATURESIZE, must be greater than 0 (line %d)",
1882
                     "loadLabel()", msyylineno);
1883
          return (MS_FAILURE);
×
1884
        }
1885
        label->minfeaturesize = (int)msyynumber;
×
1886
      } else
1887
        label->autominfeaturesize = MS_TRUE;
×
1888
      break;
1889
    case (MINSCALEDENOM):
×
1890
      if (getDouble(&(label->minscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1)
×
1891
        return (-1);
1892
      break;
1893
    case (MINSIZE):
×
1894
      if (getInteger(&(label->minsize), MS_NUM_CHECK_GT, 0, -1) == -1)
×
1895
        return (-1);
1896
      break;
1897
    case (OFFSET):
98✔
1898
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
98✔
1899
        return (MS_FAILURE);
1900
      if (symbol == MS_NUMBER)
98✔
1901
        label->offsetx = (int)msyynumber; // any integer ok
96✔
1902
      else {
1903
        if (label->bindings[MS_LABEL_BINDING_OFFSET_X].item != NULL)
2✔
1904
          msFree(label->bindings[MS_LABEL_BINDING_OFFSET_X].item);
×
1905
        label->bindings[MS_LABEL_BINDING_OFFSET_X].item =
2✔
1906
            msStrdup(msyystring_buffer);
2✔
1907
        label->numbindings++;
2✔
1908
      }
1909

1910
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
98✔
1911
        return (MS_FAILURE);
1912
      if (symbol == MS_NUMBER)
98✔
1913
        label->offsety = (int)msyynumber; // any integer ok
96✔
1914
      else {
1915
        if (label->bindings[MS_LABEL_BINDING_OFFSET_Y].item != NULL)
2✔
1916
          msFree(label->bindings[MS_LABEL_BINDING_OFFSET_Y].item);
×
1917
        label->bindings[MS_LABEL_BINDING_OFFSET_Y].item =
2✔
1918
            msStrdup(msyystring_buffer);
2✔
1919
        label->numbindings++;
2✔
1920
      }
1921
      break;
1922
    case (OUTLINECOLOR):
578✔
1923
      if (loadColor(&(label->outlinecolor),
578✔
1924
                    &(label->bindings[MS_LABEL_BINDING_OUTLINECOLOR])) !=
1925
          MS_SUCCESS)
1926
        return (-1);
1927
      if (label->bindings[MS_LABEL_BINDING_OUTLINECOLOR].item)
578✔
1928
        label->numbindings++;
×
1929
      break;
1930
    case (OUTLINEWIDTH):
142✔
1931
      if (getInteger(&(label->outlinewidth), MS_NUM_CHECK_GT, 0, -1) == -1)
142✔
1932
        return (-1);
1933
      break;
1934
    case (PARTIALS):
627✔
1935
      if ((label->partials = getSymbol(2, MS_TRUE, MS_FALSE)) == -1)
627✔
1936
        return (-1);
1937
      break;
1938
    case (POSITION):
1,465✔
1939
      if ((label->position =
1,465✔
1940
               getSymbol(11, MS_UL, MS_UC, MS_UR, MS_CL, MS_CC, MS_CR, MS_LL,
1,465✔
1941
                         MS_LC, MS_LR, MS_AUTO, MS_BINDING)) == -1)
1942
        return (-1);
1943
      if (label->position == MS_BINDING) {
1,465✔
1944
        if (label->bindings[MS_LABEL_BINDING_POSITION].item != NULL)
×
1945
          msFree(label->bindings[MS_LABEL_BINDING_POSITION].item);
×
1946
        label->bindings[MS_LABEL_BINDING_POSITION].item =
×
1947
            msStrdup(msyystring_buffer);
×
1948
        label->numbindings++;
×
1949
      }
1950
      break;
1951
    case (PRIORITY):
20✔
1952
      if (label->exprBindings[MS_LABEL_BINDING_PRIORITY].string) {
20✔
1953
        msFreeExpression(&label->exprBindings[MS_LABEL_BINDING_PRIORITY]);
3✔
1954
        label->nexprbindings--;
3✔
1955
      }
1956

1957
      if ((symbol = getSymbol(3, MS_EXPRESSION, MS_NUMBER, MS_BINDING)) == -1)
20✔
1958
        return (-1);
1959
      if (symbol == MS_NUMBER) {
20✔
1960
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, 1,
11✔
1961
                          MS_MAX_LABEL_PRIORITY) == MS_FAILURE) {
1962
          msSetError(
×
1963
              MS_MISCERR,
1964
              "Invalid PRIORITY, must be an integer between 1 and %d (line %d)",
1965
              "loadLabel()", MS_MAX_LABEL_PRIORITY, msyylineno);
1966
          return (-1);
×
1967
        }
1968
        label->priority = (int)msyynumber;
11✔
1969
      } else if (symbol == MS_EXPRESSION) {
9✔
1970
        msFree(label->exprBindings[MS_LABEL_BINDING_PRIORITY].string);
6✔
1971
        label->exprBindings[MS_LABEL_BINDING_PRIORITY].string =
6✔
1972
            msStrdup(msyystring_buffer);
6✔
1973
        label->exprBindings[MS_LABEL_BINDING_PRIORITY].type = MS_EXPRESSION;
6✔
1974
        label->nexprbindings++;
6✔
1975
      } else {
1976
        if (label->bindings[MS_LABEL_BINDING_PRIORITY].item != NULL)
3✔
1977
          msFree(label->bindings[MS_LABEL_BINDING_PRIORITY].item);
×
1978
        label->bindings[MS_LABEL_BINDING_PRIORITY].item =
3✔
1979
            msStrdup(msyystring_buffer);
3✔
1980
        label->numbindings++;
3✔
1981
      }
1982
      break;
1983
    case (SHADOWCOLOR):
×
1984
      if (loadColor(&(label->shadowcolor), NULL) != MS_SUCCESS)
×
1985
        return (-1);
1986
      break;
1987
    case (SHADOWSIZE):
×
1988
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
×
1989
        return (-1);
1990
      if (symbol == MS_NUMBER) {
×
1991
        label->shadowsizex = (int)msyynumber; // x offset, any int ok
×
1992
      } else {
1993
        if (label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].item != NULL)
×
1994
          msFree(label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].item);
×
1995
        label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].item =
×
1996
            msStrdup(msyystring_buffer);
×
1997
        label->numbindings++;
×
1998
      }
1999

2000
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
×
2001
        return (-1);
2002
      if (symbol == MS_NUMBER) {
×
2003
        label->shadowsizey = (int)msyynumber; // y offset, any int ok
×
2004
      } else {
2005
        if (label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].item != NULL)
×
2006
          msFree(label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].item);
×
2007
        label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].item =
×
2008
            msStrdup(msyystring_buffer);
×
2009
        label->numbindings++;
×
2010
      }
2011
      break;
2012
    case (SIZE):
2,655✔
2013
      if (label->bindings[MS_LABEL_BINDING_SIZE].item) {
2,655✔
2014
        msFree(label->bindings[MS_LABEL_BINDING_SIZE].item);
×
2015
        label->bindings[MS_LABEL_BINDING_SIZE].item = NULL;
×
2016
        label->numbindings--;
×
2017
      }
2018
      if (label->exprBindings[MS_LABEL_BINDING_SIZE].string) {
2,655✔
2019
        msFreeExpression(&label->exprBindings[MS_LABEL_BINDING_SIZE]);
×
2020
        label->nexprbindings--;
×
2021
      }
2022

2023
      if ((symbol = getSymbol(8, MS_EXPRESSION, MS_NUMBER, MS_BINDING, MS_TINY,
2,655✔
2024
                              MS_SMALL, MS_MEDIUM, MS_LARGE, MS_GIANT)) == -1)
2025
        return (-1);
2026

2027
      if (symbol == MS_NUMBER) {
2,655✔
2028
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_GT, 0, -1) == MS_FAILURE) {
2,154✔
2029
          msSetError(MS_MISCERR,
×
2030
                     "Invalid SIZE, must be greater than 0 (line %d)",
2031
                     "loadLabel()", msyylineno);
2032
          return (-1);
×
2033
        }
2034
        label->size = (double)msyynumber;
2,154✔
2035
      } else if (symbol == MS_BINDING) {
501✔
2036
        label->bindings[MS_LABEL_BINDING_SIZE].item =
2✔
2037
            msStrdup(msyystring_buffer);
2✔
2038
        label->numbindings++;
2✔
2039
      } else if (symbol == MS_EXPRESSION) {
499✔
2040
        msFree(label->exprBindings[MS_LABEL_BINDING_SIZE].string);
2✔
2041
        label->exprBindings[MS_LABEL_BINDING_SIZE].string =
2✔
2042
            msStrdup(msyystring_buffer);
2✔
2043
        label->exprBindings[MS_LABEL_BINDING_SIZE].type = MS_EXPRESSION;
2✔
2044
        label->nexprbindings++;
2✔
2045
      } else
2046
        label->size = symbol;
497✔
2047
      break;
2048
    case (STYLE):
1,165✔
2049
      if (msGrowLabelStyles(label) == NULL)
1,165✔
2050
        return (-1);
2051
      initStyle(label->styles[label->numstyles]);
1,165✔
2052
      if (loadStyle(label->styles[label->numstyles]) != MS_SUCCESS) {
1,165✔
2053
        freeStyle(label->styles[label->numstyles]);
×
2054
        free(label->styles[label->numstyles]);
×
2055
        label->styles[label->numstyles] = NULL;
×
2056
        return (-1);
×
2057
      }
2058
      if (label->styles[label->numstyles]->_geomtransform.type ==
1,165✔
2059
          MS_GEOMTRANSFORM_NONE)
2060
        label->styles[label->numstyles]->_geomtransform.type =
98✔
2061
            MS_GEOMTRANSFORM_LABELPOINT; /* set a default, a marker? */
2062
      label->numstyles++;
1,165✔
2063
      break;
1,165✔
2064
    case (TEXT):
320✔
2065
      if (loadExpression(&(label->text)) == -1)
320✔
2066
        return (-1); /* loadExpression() cleans up previously allocated
2067
                        expression */
2068
      if ((label->text.type != MS_STRING) &&
320✔
2069
          (label->text.type != MS_EXPRESSION)) {
2070
        msSetError(
×
2071
            MS_MISCERR,
2072
            "Text expressions support constant or tagged replacement strings.",
2073
            "loadLabel()");
2074
        return (-1);
×
2075
      }
2076
      break;
2077
    case (TYPE):
2,511✔
2078
      if (getSymbol(2, MS_TRUETYPE, MS_BITMAP) == -1)
2,511✔
2079
        return (-1); /* ignore TYPE */
2080
      break;
2081
    case (WRAP):
257✔
2082
      if (getCharacter(&(label->wrap)) == -1)
257✔
2083
        return (-1);
2084
      break;
2085
    default:
×
2086
      if (strlen(msyystring_buffer) > 0) {
×
2087
        msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
2088
                   "loadLabel()", msyystring_buffer, msyylineno);
2089
        return (-1);
×
2090
      } else {
2091
        return (0); /* end of a string, not an error */
2092
      }
2093
    }
2094
  } /* next token */
2095
}
2096

2097
int msUpdateLabelFromString(labelObj *label, char *string) {
×
2098
  if (!label || !string)
×
2099
    return MS_FAILURE;
2100

2101
  msAcquireLock(TLOCK_PARSER);
×
2102

2103
  msyystate = MS_TOKENIZE_STRING;
×
2104
  msyystring = string;
×
2105
  msyylex(); /* sets things up, but doesn't process any tokens */
×
2106

2107
  msyylineno = 1; /* start at line 1 */
×
2108

2109
  if (loadLabel(label) == -1) {
×
2110
    msReleaseLock(TLOCK_PARSER);
×
2111
    return MS_FAILURE; /* parse error */
×
2112
    ;
2113
  }
2114

2115
  msyylex_destroy();
×
2116
  msReleaseLock(TLOCK_PARSER);
×
2117
  return MS_SUCCESS;
×
2118
}
2119

2120
static void writeLeader(FILE *stream, int indent, labelLeaderObj *leader) {
×
2121
  int i;
2122
  if (leader->maxdistance == 0 && leader->numstyles == 0) {
×
2123
    return;
2124
  }
2125
  indent++;
×
2126
  writeBlockBegin(stream, indent, "LEADER");
×
2127
  writeNumber(stream, indent, "MAXDISTANCE", 0, leader->maxdistance);
×
2128
  writeNumber(stream, indent, "GRIDSTEP", 5, leader->gridstep);
×
2129
  for (i = 0; i < leader->numstyles; i++)
×
2130
    writeStyle(stream, indent, leader->styles[i]);
×
2131

2132
  writeBlockEnd(stream, indent, "LEADER");
×
2133
}
2134

2135
static void writeLabel(FILE *stream, int indent, labelObj *label) {
6✔
2136
  int i;
2137
  colorObj c;
2138

2139
  if (label->size == -1)
6✔
2140
    return; /* there is no default label anymore */
×
2141

2142
  indent++;
6✔
2143
  writeBlockBegin(stream, indent, "LABEL");
6✔
2144

2145
  if (label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_ANGLE].item)
6✔
2146
    writeAttributeBinding(stream, indent, "ANGLE",
×
2147
                          &(label->bindings[MS_LABEL_BINDING_ANGLE]));
2148
  else
2149
    writeNumberOrKeyword(stream, indent, "ANGLE", 0, label->angle,
6✔
2150
                         label->anglemode, 3, MS_FOLLOW, "FOLLOW", MS_AUTO,
6✔
2151
                         "AUTO", MS_AUTO2, "AUTO2");
2152

2153
  writeExpression(stream, indent, "EXPRESSION", &(label->expression));
6✔
2154

2155
  if (label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_FONT].item)
6✔
2156
    writeAttributeBinding(stream, indent, "FONT",
×
2157
                          &(label->bindings[MS_LABEL_BINDING_FONT]));
2158
  else
2159
    writeString(stream, indent, "FONT", NULL, label->font);
6✔
2160

2161
  writeNumber(stream, indent, "MAXSIZE", MS_MAXFONTSIZE, label->maxsize);
6✔
2162
  writeNumber(stream, indent, "MINSIZE", MS_MINFONTSIZE, label->minsize);
6✔
2163

2164
  if (label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_SIZE].item)
6✔
2165
    writeAttributeBinding(stream, indent, "SIZE",
×
2166
                          &(label->bindings[MS_LABEL_BINDING_SIZE]));
2167
  else
2168
    writeNumber(stream, indent, "SIZE", -1, label->size);
6✔
2169

2170
  writeKeyword(stream, indent, "ALIGN", label->align, 3, MS_ALIGN_LEFT, "LEFT",
6✔
2171
               MS_ALIGN_CENTER, "CENTER", MS_ALIGN_RIGHT, "RIGHT");
2172
  writeNumber(stream, indent, "BUFFER", 0, label->buffer);
6✔
2173

2174
  if (label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_COLOR].item)
6✔
2175
    writeAttributeBinding(stream, indent, "COLOR",
×
2176
                          &(label->bindings[MS_LABEL_BINDING_COLOR]));
2177
  else {
2178
    MS_INIT_COLOR(c, 0, 0, 0, 255);
6✔
2179
    writeColor(stream, indent, "COLOR", &c, &(label->color));
6✔
2180
  }
2181

2182
  writeString(stream, indent, "ENCODING", NULL, label->encoding);
6✔
2183
  if (label->leader)
6✔
2184
    writeLeader(stream, indent, label->leader);
×
2185
  writeKeyword(stream, indent, "FORCE", label->force, 2, MS_TRUE, "TRUE",
6✔
2186
               MS_LABEL_FORCE_GROUP, "GROUP");
2187
  writeNumber(stream, indent, "MAXLENGTH", 0, label->maxlength);
6✔
2188
  writeNumber(stream, indent, "MAXSCALEDENOM", -1, label->maxscaledenom);
6✔
2189
  writeNumber(stream, indent, "MINDISTANCE", -1, label->mindistance);
6✔
2190
  writeNumberOrKeyword(stream, indent, "MINFEATURESIZE", -1,
6✔
2191
                       label->minfeaturesize, 1, label->autominfeaturesize,
6✔
2192
                       MS_TRUE, "AUTO");
2193
  writeNumber(stream, indent, "MINSCALEDENOM", -1, label->minscaledenom);
6✔
2194
  writeDimension(stream, indent, "OFFSET", label->offsetx, label->offsety, NULL,
6✔
2195
                 NULL);
2196

2197
  if (label->numbindings > 0 &&
6✔
2198
      label->bindings[MS_LABEL_BINDING_OUTLINECOLOR].item)
×
2199
    writeAttributeBinding(stream, indent, "OUTLINECOLOR",
×
2200
                          &(label->bindings[MS_LABEL_BINDING_OUTLINECOLOR]));
2201
  else
2202
    writeColor(stream, indent, "OUTLINECOLOR", NULL, &(label->outlinecolor));
6✔
2203

2204
  writeNumber(stream, indent, "OUTLINEWIDTH", 1, label->outlinewidth);
6✔
2205
  writeKeyword(stream, indent, "PARTIALS", label->partials, 1, MS_TRUE, "TRUE");
6✔
2206

2207
  if (label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_POSITION].item)
6✔
2208
    writeAttributeBinding(stream, indent, "POSITION",
×
2209
                          &(label->bindings[MS_LABEL_BINDING_POSITION]));
2210
  else
2211
    writeKeyword(stream, indent, "POSITION", label->position, 10, MS_UL, "UL",
6✔
2212
                 MS_UC, "UC", MS_UR, "UR", MS_CL, "CL", MS_CC, "CC", MS_CR,
2213
                 "CR", MS_LL, "LL", MS_LC, "LC", MS_LR, "LR", MS_AUTO, "AUTO");
2214

2215
  if (label->numbindings > 0 && label->bindings[MS_LABEL_BINDING_PRIORITY].item)
6✔
2216
    writeAttributeBinding(stream, indent, "PRIORITY",
×
2217
                          &(label->bindings[MS_LABEL_BINDING_PRIORITY]));
2218
  else if (label->nexprbindings > 0 &&
6✔
2219
           label->exprBindings[MS_LABEL_BINDING_PRIORITY].string)
1✔
2220
    writeExpression(stream, indent, "PRIORITY",
1✔
2221
                    &(label->exprBindings[MS_LABEL_BINDING_PRIORITY]));
2222
  else
2223
    writeNumber(stream, indent, "PRIORITY", MS_DEFAULT_LABEL_PRIORITY,
5✔
2224
                label->priority);
5✔
2225

2226
  writeNumber(stream, indent, "REPEATDISTANCE", 0, label->repeatdistance);
6✔
2227
  writeColor(stream, indent, "SHADOWCOLOR", NULL, &(label->shadowcolor));
6✔
2228
  writeDimension(stream, indent, "SHADOWSIZE", label->shadowsizex,
6✔
2229
                 label->shadowsizey,
6✔
2230
                 label->bindings[MS_LABEL_BINDING_SHADOWSIZEX].item,
2231
                 label->bindings[MS_LABEL_BINDING_SHADOWSIZEY].item);
2232

2233
  writeNumber(stream, indent, "MAXOVERLAPANGLE", 22.5, label->maxoverlapangle);
6✔
2234
  for (i = 0; i < label->numstyles; i++)
7✔
2235
    writeStyle(stream, indent, label->styles[i]);
1✔
2236

2237
  writeExpression(stream, indent, "TEXT", &(label->text));
6✔
2238

2239
  writeCharacter(stream, indent, "WRAP", '\0', label->wrap);
6✔
2240
  writeBlockEnd(stream, indent, "LABEL");
6✔
2241
}
2242

2243
char *msWriteLabelToString(labelObj *label) {
1✔
2244
  msIOContext context;
2245
  msIOBuffer buffer;
2246

2247
  context.label = NULL;
1✔
2248
  context.write_channel = MS_TRUE;
1✔
2249
  context.readWriteFunc = msIO_bufferWrite;
1✔
2250
  context.cbData = &buffer;
1✔
2251
  buffer.data = NULL;
1✔
2252
  buffer.data_len = 0;
1✔
2253
  buffer.data_offset = 0;
1✔
2254

2255
  msIO_installHandlers(NULL, &context, NULL);
1✔
2256

2257
  writeLabel(stdout, -1, label);
1✔
2258
  msIO_bufferWrite(&buffer, "", 1);
1✔
2259

2260
  msIO_installHandlers(NULL, NULL, NULL);
1✔
2261

2262
  return (char *)buffer.data;
1✔
2263
}
2264

2265
void msInitExpression(expressionObj *exp) {
1,389,720✔
2266
  memset(exp, 0, sizeof(*exp));
2267
  exp->type = MS_STRING;
1,389,720✔
2268
}
1,389,720✔
2269

2270
void msFreeExpressionTokens(expressionObj *exp) {
816,025✔
2271
  tokenListNodeObjPtr node = NULL;
2272
  tokenListNodeObjPtr nextNode = NULL;
2273

2274
  if (!exp)
816,025✔
2275
    return;
2276

2277
  if (exp->tokens) {
816,025✔
2278
    node = exp->tokens;
2279
    while (node != NULL) {
9,364✔
2280
      nextNode = node->next;
8,121✔
2281

2282
      msFree(node->tokensrc); /* not set very often */
8,121✔
2283

2284
      switch (node->token) {
8,121✔
2285
      case MS_TOKEN_BINDING_DOUBLE:
1,644✔
2286
      case MS_TOKEN_BINDING_INTEGER:
2287
      case MS_TOKEN_BINDING_STRING:
2288
      case MS_TOKEN_BINDING_TIME:
2289
        msFree(node->tokenval.bindval.item);
1,644✔
2290
        break;
1,644✔
2291
      case MS_TOKEN_LITERAL_TIME:
2292
        /* anything to do? */
2293
        break;
2294
      case MS_TOKEN_LITERAL_STRING:
276✔
2295
        msFree(node->tokenval.strval);
276✔
2296
        break;
276✔
2297
      case MS_TOKEN_LITERAL_SHAPE:
107✔
2298
        msFreeShape(node->tokenval.shpval);
107✔
2299
        free(node->tokenval.shpval);
107✔
2300
        break;
107✔
2301
      }
2302

2303
      msFree(node);
8,121✔
2304
      node = nextNode;
2305
    }
2306
    exp->tokens = exp->curtoken = NULL;
1,243✔
2307
  }
2308
}
2309

2310
void msFreeExpression(expressionObj *exp) {
696,721✔
2311
  if (!exp)
696,721✔
2312
    return;
2313
  msFree(exp->string);
696,721✔
2314
  msFree(exp->native_string);
696,721✔
2315
  if ((exp->type == MS_REGEX) && exp->compiled)
696,721✔
2316
    ms_regfree(&(exp->regex));
27✔
2317
  msFreeExpressionTokens(exp);
696,721✔
2318
  msInitExpression(exp); /* re-initialize */
696,721✔
2319
}
2320

2321
int loadExpression(expressionObj *exp) {
4,623✔
2322
  /* TODO: should we call msFreeExpression if exp->string != NULL? We do some
2323
   * checking to avoid a leak but is it enough... */
2324

2325
  msyystring_icase = MS_TRUE;
4,623✔
2326
  if ((exp->type = getSymbol(6, MS_STRING, MS_EXPRESSION, MS_REGEX, MS_ISTRING,
4,623✔
2327
                             MS_IREGEX, MS_LIST)) == -1)
2328
    return (-1);
2329
  if (exp->string != NULL) {
4,623✔
2330
    msFree(exp->string);
×
2331
    msFree(exp->native_string);
×
2332
  }
2333
  exp->string = msStrdup(msyystring_buffer);
4,623✔
2334
  exp->native_string = NULL;
4,623✔
2335

2336
  if (exp->type == MS_ISTRING) {
4,623✔
2337
    exp->flags = exp->flags | MS_EXP_INSENSITIVE;
19✔
2338
    exp->type = MS_STRING;
19✔
2339
  } else if (exp->type == MS_IREGEX) {
4,604✔
2340
    exp->flags = exp->flags | MS_EXP_INSENSITIVE;
19✔
2341
    exp->type = MS_REGEX;
19✔
2342
  }
2343

2344
  return (0);
2345
}
2346

2347
/* ---------------------------------------------------------------------------
2348
   msLoadExpressionString and loadExpressionString
2349

2350
   msLoadExpressionString wraps call to loadExpressionString with mutex
2351
   acquisition and release.  This function should be used everywhere outside
2352
   the mapfile loading phase of an application.  loadExpressionString does
2353
   not check for a mutex!  It should be used only within code that has
2354
   properly acquired a mutex.
2355

2356
   See bug 339 for more details -- SG.
2357
   ------------------------------------------------------------------------ */
2358

2359
int msLoadExpressionString(expressionObj *exp, const char *value) {
2,784✔
2360
  int retval = MS_FAILURE;
2361

2362
  msAcquireLock(TLOCK_PARSER);
2,784✔
2363
  retval = loadExpressionString(exp, value);
2,784✔
2364
  msReleaseLock(TLOCK_PARSER);
2,784✔
2365

2366
  return retval;
2,784✔
2367
}
2368

2369
int loadExpressionString(expressionObj *exp, const char *value) {
2,784✔
2370
  msyystate = MS_TOKENIZE_STRING;
2,784✔
2371
  msyystring = value;
2,784✔
2372
  msyylex(); /* sets things up but processes no tokens */
2,784✔
2373

2374
  msFreeExpression(exp); /* we're totally replacing the old expression so free
2,784✔
2375
                            (which re-inits) to start over */
2376

2377
  msyystring_icase = MS_TRUE;
2,784✔
2378
  if ((exp->type = getSymbol2(5, MS_EXPRESSION, MS_REGEX, MS_IREGEX, MS_ISTRING,
2,784✔
2379
                              MS_LIST)) != -1) {
2380
    exp->string = msStrdup(msyystring_buffer);
2,765✔
2381

2382
    if (exp->type == MS_ISTRING) {
2,765✔
2383
      exp->type = MS_STRING;
×
2384
      exp->flags = exp->flags | MS_EXP_INSENSITIVE;
×
2385
    } else if (exp->type == MS_IREGEX) {
2,765✔
2386
      exp->type = MS_REGEX;
×
2387
      exp->flags = exp->flags | MS_EXP_INSENSITIVE;
×
2388
    }
2389
  } else {
2390
    /* failure above is not an error since we'll consider anything not matching
2391
     * (like an unquoted number) as a STRING) */
2392
    exp->type = MS_STRING;
19✔
2393
    if ((strlen(value) - strlen(msyystring_buffer)) == 2)
19✔
2394
      exp->string = msStrdup(msyystring_buffer); /* value was quoted */
3✔
2395
    else
2396
      exp->string = msStrdup(value); /* use the whole value */
16✔
2397
  }
2398

2399
  return (0);
2,784✔
2400
}
2401

2402
/* msGetExpressionString()
2403
 *
2404
 * Returns the string representation of this expression, including delimiters
2405
 * and any flags (e.g. i = case-insensitive).
2406
 *
2407
 * Returns a newly allocated buffer that should be freed by the caller or NULL.
2408
 */
2409
char *msGetExpressionString(expressionObj *exp) {
14✔
2410
  if (exp->string) {
14✔
2411
    char *exprstring;
2412
    size_t buffer_size;
2413
    const char *case_insensitive = "";
2414

2415
    if (exp->flags & MS_EXP_INSENSITIVE)
12✔
2416
      case_insensitive = "i";
2417

2418
    /* Alloc buffer big enough for string + 2 delimiters + 'i' + \0 */
2419
    buffer_size = strlen(exp->string) + 4;
12✔
2420
    exprstring = (char *)msSmallMalloc(buffer_size);
12✔
2421

2422
    switch (exp->type) {
12✔
2423
    case (MS_REGEX):
1✔
2424
      snprintf(exprstring, buffer_size, "/%s/%s", exp->string,
1✔
2425
               case_insensitive);
2426
      return exprstring;
1✔
2427
    case (MS_STRING):
5✔
2428
      snprintf(exprstring, buffer_size, "\"%s\"%s", exp->string,
5✔
2429
               case_insensitive);
2430
      return exprstring;
5✔
2431
    case (MS_EXPRESSION):
6✔
2432
      snprintf(exprstring, buffer_size, "(%s)", exp->string);
6✔
2433
      return exprstring;
6✔
2434
    case (MS_LIST):
×
2435
      snprintf(exprstring, buffer_size, "{%s}", exp->string);
×
2436
      return exprstring;
×
2437
    default:
×
2438
      /* We should never get to here really! */
2439
      free(exprstring);
×
2440
      return NULL;
×
2441
    }
2442
  }
2443
  return NULL;
2444
}
2445

2446
static void writeExpression(FILE *stream, int indent, const char *name,
47✔
2447
                            expressionObj *exp) {
2448
  if (!exp || !exp->string)
47✔
2449
    return;
2450

2451
  writeIndent(stream, ++indent);
2452
  switch (exp->type) {
5✔
2453
  case (MS_LIST):
×
2454
    fprintf(stream, "%s {%s}", name, exp->string);
×
2455
    break;
2456
  case (MS_REGEX):
×
2457
    msIO_fprintf(stream, "%s /%s/", name, exp->string);
×
2458
    break;
×
2459
  case (MS_STRING):
4✔
2460
    msIO_fprintf(stream, "%s ", name);
4✔
2461
    writeStringElement(stream, exp->string);
4✔
2462
    break;
4✔
2463
  case (MS_EXPRESSION):
1✔
2464
    msIO_fprintf(stream, "%s (%s)", name, exp->string);
1✔
2465
    break;
1✔
2466
  }
2467
  if ((exp->type == MS_STRING || exp->type == MS_REGEX) &&
5✔
2468
      (exp->flags & MS_EXP_INSENSITIVE))
4✔
2469
    msIO_fprintf(stream, "i");
×
2470
  writeLineFeed(stream);
2471
}
2472

2473
int loadHashTable(hashTableObj *ptable) {
15,108✔
2474
  assert(ptable);
2475

2476
  for (;;) {
2477
    switch (msyylex()) {
106,653✔
2478
    case (EOF):
×
2479
      msSetError(MS_EOFERR, NULL, "loadHashTable()");
×
2480
      return (MS_FAILURE);
×
2481
    case (END):
2482
      return (MS_SUCCESS);
2483
    case (MS_STRING): {
91,545✔
2484
      char *data = NULL;
91,545✔
2485
      char *key =
2486
          msStrdup(msyystring_buffer); /* the key is *always* a string */
91,545✔
2487
      if (getString(&data) == MS_FAILURE) {
91,545✔
2488
        free(key);
×
2489
        return (MS_FAILURE);
×
2490
      }
2491
      msInsertHashTable(ptable, key, data);
91,545✔
2492

2493
      free(key);
91,545✔
2494
      free(data);
91,545✔
2495
      break;
91,545✔
2496
    }
2497
    default:
×
2498
      msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
2499
                 "loadHashTable()", msyystring_buffer, msyylineno);
2500
      return (MS_FAILURE);
×
2501
    }
2502
  }
2503

2504
  return (MS_SUCCESS);
2505
}
2506

2507
static void writeHashTable(FILE *stream, int indent, const char *title,
48✔
2508
                           hashTableObj *table) {
2509
  struct hashObj *tp;
2510
  int i;
2511

2512
  if (!table)
48✔
2513
    return;
2514
  if (msHashIsEmpty(table))
48✔
2515
    return;
2516

2517
  indent++;
4✔
2518
  writeBlockBegin(stream, indent, title);
4✔
2519
  for (i = 0; i < MS_HASHSIZE; i++) {
168✔
2520
    if (table->items[i] != NULL) {
164✔
2521
      for (tp = table->items[i]; tp != NULL; tp = tp->next)
28✔
2522
        writeNameValuePair(stream, indent, tp->key, tp->data);
14✔
2523
    }
2524
  }
2525
  writeBlockEnd(stream, indent, title);
4✔
2526
}
2527

2528
static void writeHashTableInline(FILE *stream, int indent, char *name,
1✔
2529
                                 hashTableObj *table) {
2530
  struct hashObj *tp = NULL;
2531
  int i;
2532

2533
  if (!table)
1✔
2534
    return;
2535
  if (msHashIsEmpty(table))
1✔
2536
    return;
2537

2538
  ++indent;
2539
  for (i = 0; i < MS_HASHSIZE; ++i) {
×
2540
    if (table->items[i] != NULL) {
×
2541
      for (tp = table->items[i]; tp != NULL; tp = tp->next) {
×
2542
        writeIndent(stream, indent);
2543
        msIO_fprintf(stream, "%s ", name);
×
2544
        writeStringElement(stream, tp->key);
×
2545
        msIO_fprintf(stream, " ");
×
2546
        writeStringElement(stream, tp->data);
×
2547
        writeLineFeed(stream);
2548
      }
2549
    }
2550
  }
2551
}
2552

2553
/*
2554
** Initialize, load and free a cluster object
2555
*/
2556
void initCluster(clusterObj *cluster) {
13,656✔
2557
  cluster->maxdistance = 10;
13,656✔
2558
  cluster->buffer = 0;
13,656✔
2559
  cluster->region = NULL;
13,656✔
2560
  msInitExpression(&(cluster->group));
13,656✔
2561
  msInitExpression(&(cluster->filter));
13,656✔
2562
}
13,656✔
2563

2564
void freeCluster(clusterObj *cluster) {
13,621✔
2565
  msFree(cluster->region);
13,621✔
2566
  msFreeExpression(&(cluster->group));
13,621✔
2567
  msFreeExpression(&(cluster->filter));
13,621✔
2568
}
13,621✔
2569

2570
int loadCluster(clusterObj *cluster) {
5✔
2571
  for (;;) {
2572
    switch (msyylex()) {
16✔
2573
    case (CLUSTER):
2574
      break; /* for string loads */
2575
    case (MAXDISTANCE):
5✔
2576
      if (getDouble(&(cluster->maxdistance), MS_NUM_CHECK_GT, 0, -1) == -1)
5✔
2577
        return (-1);
2578
      break;
2579
    case (BUFFER):
×
2580
      if (getDouble(&(cluster->buffer), MS_NUM_CHECK_GT, 0, -1) == -1)
×
2581
        return (-1);
2582
      break;
2583
    case (REGION):
5✔
2584
      if (getString(&cluster->region) == MS_FAILURE)
5✔
2585
        return (-1);
2586
      break;
2587
    case (END):
2588
      return (0);
2589
      break;
2590
    case (GROUP):
×
2591
      if (loadExpression(&(cluster->group)) == -1)
×
2592
        return (-1);
2593
      break;
2594
    case (FILTER):
×
2595
      if (loadExpression(&(cluster->filter)) == -1)
×
2596
        return (-1);
2597
      break;
2598
    default:
×
2599
      if (strlen(msyystring_buffer) > 0) {
×
2600
        msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
2601
                   "loadCluster()", msyystring_buffer, msyylineno);
2602
        return (-1);
×
2603
      } else {
2604
        return (0); /* end of a string, not an error */
2605
      }
2606
    }
2607
  }
2608
  return (MS_SUCCESS);
2609
}
2610

2611
int msUpdateClusterFromString(clusterObj *cluster, char *string) {
1✔
2612
  if (!cluster || !string)
1✔
2613
    return MS_FAILURE;
2614

2615
  msAcquireLock(TLOCK_PARSER);
1✔
2616

2617
  msyystate = MS_TOKENIZE_STRING;
1✔
2618
  msyystring = string;
1✔
2619
  msyylex(); /* sets things up, but doesn't process any tokens */
1✔
2620

2621
  msyylineno = 1; /* start at line 1 */
1✔
2622

2623
  if (loadCluster(cluster) == -1) {
1✔
2624
    msReleaseLock(TLOCK_PARSER);
×
2625
    return MS_FAILURE; /* parse error */
×
2626
    ;
2627
  }
2628

2629
  msyylex_destroy();
1✔
2630
  msReleaseLock(TLOCK_PARSER);
1✔
2631
  return MS_SUCCESS;
1✔
2632
}
2633

2634
static void writeCluster(FILE *stream, int indent, clusterObj *cluster) {
8✔
2635

2636
  if (cluster->maxdistance == 10 && cluster->buffer == 0.0 &&
8✔
2637
      cluster->region == NULL && cluster->group.string == NULL &&
7✔
2638
      cluster->filter.string == NULL)
7✔
2639
    return; /* Nothing to write */
2640

2641
  indent++;
1✔
2642
  writeBlockBegin(stream, indent, "CLUSTER");
1✔
2643
  writeNumber(stream, indent, "MAXDISTANCE", 10, cluster->maxdistance);
1✔
2644
  writeNumber(stream, indent, "BUFFER", 0, cluster->buffer);
1✔
2645
  writeString(stream, indent, "REGION", NULL, cluster->region);
1✔
2646
  writeExpression(stream, indent, "GROUP", &(cluster->group));
1✔
2647
  writeExpression(stream, indent, "FILTER", &(cluster->filter));
1✔
2648
  writeBlockEnd(stream, indent, "CLUSTER");
1✔
2649
}
2650

2651
char *msWriteClusterToString(clusterObj *cluster) {
1✔
2652
  msIOContext context;
2653
  msIOBuffer buffer;
2654

2655
  context.label = NULL;
1✔
2656
  context.write_channel = MS_TRUE;
1✔
2657
  context.readWriteFunc = msIO_bufferWrite;
1✔
2658
  context.cbData = &buffer;
1✔
2659
  buffer.data = NULL;
1✔
2660
  buffer.data_len = 0;
1✔
2661
  buffer.data_offset = 0;
1✔
2662

2663
  msIO_installHandlers(NULL, &context, NULL);
1✔
2664

2665
  writeCluster(stdout, -1, cluster);
1✔
2666
  msIO_bufferWrite(&buffer, "", 1);
1✔
2667

2668
  msIO_installHandlers(NULL, NULL, NULL);
1✔
2669

2670
  return (char *)buffer.data;
1✔
2671
}
2672

2673
/*
2674
** Initialize, load and free a single style
2675
*/
2676
int initStyle(styleObj *style) {
24,678✔
2677
  int i;
2678
  MS_REFCNT_INIT(style);
24,678✔
2679
  MS_INIT_COLOR(style->color, -1, -1, -1, 255); /* must explicitly set colors */
24,678✔
2680
  MS_INIT_COLOR(style->outlinecolor, -1, -1, -1, 255);
24,678✔
2681
  /* New Color Range fields*/
2682
  MS_INIT_COLOR(style->mincolor, -1, -1, -1, 255);
24,678✔
2683
  MS_INIT_COLOR(style->maxcolor, -1, -1, -1, 255);
24,678✔
2684
  style->minvalue = 0.0;
24,678✔
2685
  style->maxvalue = 1.0;
24,678✔
2686
  style->rangeitem = NULL;
24,678✔
2687
  /* End Color Range fields*/
2688
  style->symbol = 0; /* there is always a default symbol*/
24,678✔
2689
  style->symbolname = NULL;
24,678✔
2690
  style->size = -1; /* in SIZEUNITS (layerObj) */
24,678✔
2691
  style->minsize = MS_MINSYMBOLSIZE;
24,678✔
2692
  style->maxsize = MS_MAXSYMBOLSIZE;
24,678✔
2693
  style->width = 1;        /* in pixels */
24,678✔
2694
  style->outlinewidth = 0; /* in pixels */
24,678✔
2695
  style->minwidth = MS_MINSYMBOLWIDTH;
24,678✔
2696
  style->maxwidth = MS_MAXSYMBOLWIDTH;
24,678✔
2697
  style->minscaledenom = style->maxscaledenom = -1.0;
24,678✔
2698
  style->offsetx = style->offsety = 0;                   /* no offset */
24,678✔
2699
  style->polaroffsetpixel = style->polaroffsetangle = 0; /* no polar offset */
24,678✔
2700
  style->angle = 0;
24,678✔
2701
  style->autoangle = MS_FALSE;
24,678✔
2702
  style->antialiased = MS_TRUE;
24,678✔
2703
  style->opacity = 100; /* fully opaque */
24,678✔
2704

2705
  msInitExpression(&(style->_geomtransform));
24,678✔
2706
  style->_geomtransform.type = MS_GEOMTRANSFORM_NONE;
24,678✔
2707

2708
  style->patternlength = 0; /* solid line */
24,678✔
2709
  style->gap = 0;
24,678✔
2710
  style->initialgap = -1;
24,678✔
2711
  style->linecap = MS_CJC_DEFAULT_CAPS;
24,678✔
2712
  style->linejoin = MS_CJC_DEFAULT_JOINS;
24,678✔
2713
  style->linejoinmaxsize = MS_CJC_DEFAULT_JOIN_MAXSIZE;
24,678✔
2714

2715
  style->numbindings = 0;
24,678✔
2716
  style->nexprbindings = 0;
24,678✔
2717
  for (i = 0; i < MS_STYLE_BINDING_LENGTH; i++) {
320,814✔
2718
    style->bindings[i].item = NULL;
296,136✔
2719
    style->bindings[i].index = -1;
296,136✔
2720
    msInitExpression(&(style->exprBindings[i]));
296,136✔
2721
  }
2722

2723
  style->sizeunits = MS_INHERIT;
24,678✔
2724
  style->scalefactor = 1.0;
24,678✔
2725

2726
  return MS_SUCCESS;
24,678✔
2727
}
2728

2729
int loadStyle(styleObj *style) {
13,772✔
2730
  int symbol;
2731

2732
  for (;;) {
2733
    switch (msyylex()) {
48,490✔
2734
      /* New Color Range fields*/
2735
    case (COLORRANGE):
32✔
2736
      /*These are both in one line now*/
2737
      if (loadColor(&(style->mincolor), NULL) != MS_SUCCESS)
32✔
2738
        return (MS_FAILURE);
2739
      if (loadColor(&(style->maxcolor), NULL) != MS_SUCCESS)
32✔
2740
        return (MS_FAILURE);
2741
      break;
2742
    case (DATARANGE):
32✔
2743
      /*These are both in one line now*/
2744
      if (getDouble(&(style->minvalue), MS_NUM_CHECK_NONE, -1, -1) == -1)
32✔
2745
        return (MS_FAILURE);
2746
      if (getDouble(&(style->maxvalue), MS_NUM_CHECK_NONE, -1, -1) == -1)
32✔
2747
        return (MS_FAILURE);
2748
      break;
2749
    case (RANGEITEM):
×
2750
      if (getString(&style->rangeitem) == MS_FAILURE)
×
2751
        return (MS_FAILURE);
2752
      break;
2753
      /* End Range fields*/
2754
    case (ANGLE):
296✔
2755
      if ((symbol = getSymbol(3, MS_NUMBER, MS_BINDING, MS_AUTO)) == -1)
296✔
2756
        return (MS_FAILURE);
2757

2758
      if (symbol == MS_NUMBER) {
296✔
2759
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, -360.0, 360.0) ==
150✔
2760
            MS_FAILURE) {
2761
          msSetError(MS_MISCERR,
×
2762
                     "Invalid ANGLE, must be between -360 and 360 (line %d)",
2763
                     "loadStyle()", msyylineno);
2764
          return (MS_FAILURE);
×
2765
        }
2766
        style->angle = (double)msyynumber;
150✔
2767
      } else if (symbol == MS_BINDING) {
146✔
2768
        if (style->bindings[MS_STYLE_BINDING_ANGLE].item != NULL)
94✔
2769
          msFree(style->bindings[MS_STYLE_BINDING_ANGLE].item);
×
2770
        style->bindings[MS_STYLE_BINDING_ANGLE].item =
94✔
2771
            msStrdup(msyystring_buffer);
94✔
2772
        style->numbindings++;
94✔
2773
      } else {
2774
        style->autoangle = MS_TRUE;
52✔
2775
      }
2776
      break;
2777
    case (ANTIALIAS):
2✔
2778
      if ((symbol = getSymbol(2, MS_TRUE, MS_FALSE)) == -1)
2✔
2779
        return (MS_FAILURE);
2780
      if (symbol == MS_FALSE) {
2✔
2781
        style->antialiased = MS_FALSE;
1✔
2782
      }
2783
      break;
2784
    case (COLOR):
12,377✔
2785
      if (loadColor(&(style->color),
12,377✔
2786
                    &(style->bindings[MS_STYLE_BINDING_COLOR])) != MS_SUCCESS)
2787
        return (MS_FAILURE);
2788
      if (style->bindings[MS_STYLE_BINDING_COLOR].item)
12,377✔
2789
        style->numbindings++;
16✔
2790
      break;
2791
    case (EOF):
×
2792
      msSetError(MS_EOFERR, NULL, "loadStyle()");
×
2793
      return (MS_FAILURE); /* missing END (probably) */
×
2794
    case (END): {
13,772✔
2795
      int alpha;
2796

2797
      /* apply opacity as the alpha channel color(s) */
2798
      if (style->opacity < 100) {
13,772✔
2799
        alpha = MS_NINT(style->opacity * 2.55);
214✔
2800

2801
        style->color.alpha = alpha;
214✔
2802
        style->outlinecolor.alpha = alpha;
214✔
2803

2804
        style->mincolor.alpha = alpha;
214✔
2805
        style->maxcolor.alpha = alpha;
214✔
2806
      }
2807

2808
      return (MS_SUCCESS);
2809
    } break;
2810
    case (GAP):
87✔
2811
      if (getDouble(&(style->gap), MS_NUM_CHECK_NONE, -1, -1) == -1)
87✔
2812
        return (MS_FAILURE);
2813
      break;
2814
    case (INITIALGAP):
45✔
2815
      if (getDouble(&(style->initialgap), MS_NUM_CHECK_GTE, 0, -1) ==
45✔
2816
          -1) { // zero is ok
2817
        msSetError(MS_MISCERR,
×
2818
                   "INITIALGAP requires a positive values (line %d)",
2819
                   "loadStyle()", msyylineno);
2820
        return (MS_FAILURE);
×
2821
      }
2822
      break;
2823
    case (MAXSCALEDENOM):
×
2824
      if (getDouble(&(style->maxscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1)
×
2825
        return (MS_FAILURE);
2826
      break;
2827
    case (MINSCALEDENOM):
×
2828
      if (getDouble(&(style->minscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1)
×
2829
        return (MS_FAILURE);
2830
      break;
2831
    case (GEOMTRANSFORM): {
1,200✔
2832
      int s;
2833
      if ((s = getSymbol(2, MS_STRING, MS_EXPRESSION)) == -1)
1,200✔
2834
        return (MS_FAILURE);
2835
      if (s == MS_STRING)
1,200✔
2836
        msStyleSetGeomTransform(style, msyystring_buffer);
1,164✔
2837
      else {
2838
        /* handle expression case here for the moment */
2839
        msFree(style->_geomtransform.string);
36✔
2840
        style->_geomtransform.string = msStrdup(msyystring_buffer);
36✔
2841
        style->_geomtransform.type = MS_GEOMTRANSFORM_EXPRESSION;
36✔
2842
      }
2843
    } break;
2844
    case (LINECAP):
36✔
2845
      if ((style->linecap = getSymbol(4, MS_CJC_BUTT, MS_CJC_ROUND,
36✔
2846
                                      MS_CJC_SQUARE, MS_CJC_TRIANGLE)) == -1)
2847
        return (MS_FAILURE);
2848
      break;
2849
    case (LINEJOIN):
×
2850
      if ((style->linejoin = getSymbol(4, MS_CJC_NONE, MS_CJC_ROUND,
×
2851
                                       MS_CJC_MITER, MS_CJC_BEVEL)) == -1)
2852
        return (MS_FAILURE);
2853
      break;
2854
    case (LINEJOINMAXSIZE):
×
2855
      if (getDouble(&(style->linejoinmaxsize), MS_NUM_CHECK_GT, 0, -1) == -1)
×
2856
        return (MS_FAILURE);
2857
      break;
2858
    case (MAXSIZE):
75✔
2859
      if (getDouble(&(style->maxsize), MS_NUM_CHECK_GT, 0, -1) == -1)
75✔
2860
        return (MS_FAILURE);
2861
      break;
2862
    case (MINSIZE):
×
2863
      if (getDouble(&(style->minsize), MS_NUM_CHECK_GTE, 0, -1) == -1)
×
2864
        return (MS_FAILURE);
2865
      break;
2866
    case (MAXWIDTH):
×
2867
      if (getDouble(&(style->maxwidth), MS_NUM_CHECK_GT, 0, -1) == -1)
×
2868
        return (MS_FAILURE);
2869
      break;
2870
    case (MINWIDTH):
×
2871
      if (getDouble(&(style->minwidth), MS_NUM_CHECK_GTE, 0, -1) == -1)
×
2872
        return (MS_FAILURE);
2873
      break;
2874
    case (OFFSET):
173✔
2875
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
173✔
2876
        return (MS_FAILURE);
2877
      if (symbol == MS_NUMBER)
173✔
2878
        style->offsetx = (double)msyynumber; // any double ok
173✔
2879
      else {
2880
        if (style->bindings[MS_STYLE_BINDING_OFFSET_X].item != NULL)
×
2881
          msFree(style->bindings[MS_STYLE_BINDING_OFFSET_X].item);
×
2882
        style->bindings[MS_STYLE_BINDING_OFFSET_X].item =
×
2883
            msStrdup(msyystring_buffer);
×
2884
        style->numbindings++;
×
2885
      }
2886

2887
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
173✔
2888
        return (MS_FAILURE);
2889
      if (symbol == MS_NUMBER)
173✔
2890
        style->offsety = (double)msyynumber; // any double ok
173✔
2891
      else {
2892
        if (style->bindings[MS_STYLE_BINDING_OFFSET_Y].item != NULL)
×
2893
          msFree(style->bindings[MS_STYLE_BINDING_OFFSET_Y].item);
×
2894
        style->bindings[MS_STYLE_BINDING_OFFSET_Y].item =
×
2895
            msStrdup(msyystring_buffer);
×
2896
        style->numbindings++;
×
2897
      }
2898
      break;
2899
    case (OPACITY):
218✔
2900
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
218✔
2901
        return (MS_FAILURE);
2902
      if (symbol == MS_NUMBER)
218✔
2903
        style->opacity = MS_MAX(MS_MIN((int)msyynumber, 100),
218✔
2904
                                0); /* force opacity to between 0 and 100 */
2905
      else {
2906
        if (style->bindings[MS_STYLE_BINDING_OPACITY].item != NULL)
×
2907
          msFree(style->bindings[MS_STYLE_BINDING_OPACITY].item);
×
2908
        style->bindings[MS_STYLE_BINDING_OPACITY].item =
×
2909
            msStrdup(msyystring_buffer);
×
2910
        style->numbindings++;
×
2911
      }
2912
      break;
2913
    case (OUTLINECOLOR):
3,884✔
2914
      if (loadColor(&(style->outlinecolor),
3,884✔
2915
                    &(style->bindings[MS_STYLE_BINDING_OUTLINECOLOR])) !=
2916
          MS_SUCCESS)
2917
        return (MS_FAILURE);
2918
      if (style->bindings[MS_STYLE_BINDING_OUTLINECOLOR].item)
3,884✔
2919
        style->numbindings++;
×
2920
      break;
2921
    case (PATTERN): {
2922
      int done = MS_FALSE;
2923
      for (;;) { /* read till the next END */
2924
        switch (msyylex()) {
236✔
2925
        case (END):
72✔
2926
          if (style->patternlength < 2) {
72✔
2927
            msSetError(MS_SYMERR,
×
2928
                       "Not enough pattern elements. A minimum of 2 are "
2929
                       "required (line %d)",
2930
                       "loadStyle()", msyylineno);
2931
            return (MS_FAILURE);
×
2932
          }
2933
          done = MS_TRUE;
2934
          break;
2935
        case (MS_NUMBER): /* read the pattern values */
164✔
2936
          if (style->patternlength == MS_MAXPATTERNLENGTH) {
164✔
2937
            msSetError(MS_SYMERR, "Pattern too long.", "loadStyle()");
×
2938
            return (MS_FAILURE);
×
2939
          }
2940
          style->pattern[style->patternlength] =
164✔
2941
              atof(msyystring_buffer); // good enough?
164✔
2942
          style->patternlength++;
164✔
2943
          break;
2944
        default:
×
2945
          msSetError(MS_TYPEERR, "Parsing error near (%s):(line %d)",
×
2946
                     "loadStyle()", msyystring_buffer, msyylineno);
2947
          return (MS_FAILURE);
×
2948
        }
2949
        if (done == MS_TRUE)
2950
          break;
2951
      }
2952
      break;
2953
    }
2954
    case (OUTLINEWIDTH):
43✔
2955
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
43✔
2956
        return (MS_FAILURE);
2957
      if (symbol == MS_NUMBER) {
43✔
2958
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_GTE, 0, -1) == MS_FAILURE) {
25✔
2959
          msSetError(MS_MISCERR,
×
2960
                     "Invalid OUTLINEWIDTH, must be greater then or equal to 0 "
2961
                     "(line %d)",
2962
                     "loadStyle()", msyylineno);
2963
          return (MS_FAILURE);
×
2964
        }
2965
        style->outlinewidth = (double)msyynumber;
25✔
2966
      } else {
2967
        if (style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].item != NULL)
18✔
2968
          msFree(style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].item);
×
2969
        style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].item =
18✔
2970
            msStrdup(msyystring_buffer);
18✔
2971
        style->numbindings++;
18✔
2972
      }
2973
      break;
2974
    case (SIZE):
5,767✔
2975
      if (style->exprBindings[MS_STYLE_BINDING_SIZE].string) {
5,767✔
2976
        msFreeExpression(&style->exprBindings[MS_STYLE_BINDING_SIZE]);
3✔
2977
        style->nexprbindings--;
3✔
2978
      }
2979

2980
      if ((symbol = getSymbol(3, MS_EXPRESSION, MS_NUMBER, MS_BINDING)) == -1)
5,767✔
2981
        return (MS_FAILURE);
2982
      if (symbol == MS_NUMBER) {
5,767✔
2983
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_GT, 0, -1) == MS_FAILURE) {
5,671✔
2984
          msSetError(MS_MISCERR,
×
2985
                     "Invalid SIZE, must be greater than 0 (line %d)",
2986
                     "loadStyle()", msyylineno);
2987
          return (MS_FAILURE);
×
2988
        }
2989
        style->size = (double)msyynumber;
5,671✔
2990
      } else if (symbol == MS_EXPRESSION) {
96✔
2991
        msFree(style->exprBindings[MS_STYLE_BINDING_SIZE].string);
6✔
2992
        style->exprBindings[MS_STYLE_BINDING_SIZE].string =
6✔
2993
            msStrdup(msyystring_buffer);
6✔
2994
        style->exprBindings[MS_STYLE_BINDING_SIZE].type = MS_EXPRESSION;
6✔
2995
        style->nexprbindings++;
6✔
2996
      } else {
2997
        if (style->bindings[MS_STYLE_BINDING_SIZE].item != NULL)
90✔
2998
          msFree(style->bindings[MS_STYLE_BINDING_SIZE].item);
3✔
2999
        style->bindings[MS_STYLE_BINDING_SIZE].item =
90✔
3000
            msStrdup(msyystring_buffer);
90✔
3001
        style->numbindings++;
90✔
3002
      }
3003
      break;
3004
    case (STYLE):
3005
      break; /* for string loads */
3006
    case (SYMBOL):
6,953✔
3007
      if ((symbol = getSymbol(3, MS_NUMBER, MS_STRING, MS_BINDING)) == -1)
6,953✔
3008
        return (MS_FAILURE);
3009
      if (symbol == MS_NUMBER) {
6,953✔
3010
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_GTE, 0, -1) == MS_FAILURE) {
4,530✔
3011
          msSetError(
×
3012
              MS_MISCERR,
3013
              "Invalid SYMBOL id, must be greater than or equal to 0 (line %d)",
3014
              "loadStyle()", msyylineno);
3015
          return (MS_FAILURE);
×
3016
        }
3017
        if (style->symbolname != NULL) {
4,530✔
3018
          msFree(style->symbolname);
×
3019
          style->symbolname = NULL;
×
3020
        }
3021
        style->symbol = (int)msyynumber;
4,530✔
3022
      } else if (symbol == MS_STRING) {
2,423✔
3023
        if (style->symbolname != NULL)
2,411✔
3024
          msFree(style->symbolname);
×
3025
        style->symbolname = msStrdup(msyystring_buffer);
2,411✔
3026
      } else {
3027
        if (style->bindings[MS_STYLE_BINDING_SYMBOL].item != NULL)
12✔
3028
          msFree(style->bindings[MS_STYLE_BINDING_SYMBOL].item);
×
3029
        style->bindings[MS_STYLE_BINDING_SYMBOL].item =
12✔
3030
            msStrdup(msyystring_buffer);
12✔
3031
        style->numbindings++;
12✔
3032
      }
3033
      break;
3034
    case (WIDTH):
3,410✔
3035
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
3,410✔
3036
        return (MS_FAILURE);
3037
      if (symbol == MS_NUMBER) {
3,410✔
3038
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_GTE, 0, -1) == MS_FAILURE) {
3,392✔
3039
          msSetError(
×
3040
              MS_MISCERR,
3041
              "Invalid WIDTH, must be greater than or equal to 0 (line %d)",
3042
              "loadStyle()", msyylineno);
3043
          return (MS_FAILURE);
×
3044
        }
3045
        style->width = (double)msyynumber;
3,392✔
3046
      } else {
3047
        if (style->bindings[MS_STYLE_BINDING_WIDTH].item != NULL)
18✔
3048
          msFree(style->bindings[MS_STYLE_BINDING_WIDTH].item);
×
3049
        style->bindings[MS_STYLE_BINDING_WIDTH].item =
18✔
3050
            msStrdup(msyystring_buffer);
18✔
3051
        style->numbindings++;
18✔
3052
      }
3053
      break;
3054
    case (POLAROFFSET):
13✔
3055
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
13✔
3056
        return (MS_FAILURE);
3057
      if (symbol == MS_NUMBER) {
13✔
3058
        style->polaroffsetpixel = (double)msyynumber; // ok?
×
3059
      } else {
3060
        if (style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item != NULL)
13✔
3061
          msFree(style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item);
×
3062
        style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item =
13✔
3063
            msStrdup(msyystring_buffer);
13✔
3064
        style->numbindings++;
13✔
3065
      }
3066

3067
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
13✔
3068
        return (MS_FAILURE);
3069
      if (symbol == MS_NUMBER) {
13✔
3070
        style->polaroffsetangle = (double)msyynumber; // ok?
×
3071
      } else {
3072
        if (style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item != NULL)
13✔
3073
          msFree(style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item);
×
3074
        style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item =
13✔
3075
            msStrdup(msyystring_buffer);
13✔
3076
        style->numbindings++;
13✔
3077
      }
3078
      break;
3079
    default:
×
3080
      if (strlen(msyystring_buffer) > 0) {
×
3081
        msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
3082
                   "loadStyle()", msyystring_buffer, msyylineno);
3083
        return (MS_FAILURE);
×
3084
      } else {
3085
        return (MS_SUCCESS); /* end of a string, not an error */
3086
      }
3087
    }
3088
  }
3089
}
3090

3091
int msUpdateStyleFromString(styleObj *style, char *string) {
3✔
3092
  if (!style || !string)
3✔
3093
    return MS_FAILURE;
3094

3095
  msAcquireLock(TLOCK_PARSER);
3✔
3096

3097
  msyystate = MS_TOKENIZE_STRING;
3✔
3098
  msyystring = string;
3✔
3099
  msyylex(); /* sets things up, but doesn't process any tokens */
3✔
3100

3101
  msyylineno = 1; /* start at line 1 */
3✔
3102

3103
  if (loadStyle(style) == -1) {
3✔
3104
    msReleaseLock(TLOCK_PARSER);
×
3105
    return MS_FAILURE; /* parse error */
×
3106
    ;
3107
  }
3108

3109
  msyylex_destroy();
3✔
3110
  msReleaseLock(TLOCK_PARSER);
3✔
3111
  return MS_SUCCESS;
3✔
3112
}
3113

3114
int freeStyle(styleObj *style) {
24,691✔
3115
  int i;
3116

3117
  if (MS_REFCNT_DECR_IS_NOT_ZERO(style)) {
24,691✔
3118
    return MS_FAILURE;
3119
  }
3120

3121
  msFree(style->symbolname);
24,637✔
3122
  msFreeExpression(&style->_geomtransform);
24,637✔
3123
  msFree(style->rangeitem);
24,637✔
3124

3125
  for (i = 0; i < MS_STYLE_BINDING_LENGTH; i++) {
320,281✔
3126
    msFree(style->bindings[i].item);
295,644✔
3127
    msFreeExpression(&(style->exprBindings[i]));
295,644✔
3128
  }
3129

3130
  return MS_SUCCESS;
3131
}
3132

3133
void writeStyle(FILE *stream, int indent, styleObj *style) {
11✔
3134

3135
  indent++;
11✔
3136
  writeBlockBegin(stream, indent, "STYLE");
11✔
3137

3138
  if (style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_ANGLE].item)
11✔
3139
    writeAttributeBinding(stream, indent, "ANGLE",
×
3140
                          &(style->bindings[MS_STYLE_BINDING_ANGLE]));
3141
  else
3142
    writeNumberOrKeyword(stream, indent, "ANGLE", 0, style->angle,
11✔
3143
                         style->autoangle, 1, MS_TRUE, "AUTO");
3144

3145
  if (style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_COLOR].item)
11✔
3146
    writeAttributeBinding(stream, indent, "COLOR",
×
3147
                          &(style->bindings[MS_STYLE_BINDING_COLOR]));
3148
  else
3149
    writeColor(stream, indent, "COLOR", NULL, &(style->color));
11✔
3150

3151
  writeNumber(stream, indent, "GAP", 0, style->gap);
11✔
3152
  writeNumber(stream, indent, "INITIALGAP", -1, style->initialgap);
11✔
3153

3154
  if (style->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) {
11✔
3155
    writeIndent(stream, indent + 1);
×
3156
    msIO_fprintf(stream, "GEOMTRANSFORM (%s)\n", style->_geomtransform.string);
×
3157
  } else if (style->_geomtransform.type != MS_GEOMTRANSFORM_NONE) {
11✔
3158
    writeKeyword(stream, indent, "GEOMTRANSFORM", style->_geomtransform.type, 8,
1✔
3159
                 MS_GEOMTRANSFORM_BBOX, "\"bbox\"", MS_GEOMTRANSFORM_END,
3160
                 "\"end\"", MS_GEOMTRANSFORM_LABELPOINT, "\"labelpnt\"",
3161
                 MS_GEOMTRANSFORM_LABELPOLY, "\"labelpoly\"",
3162
                 MS_GEOMTRANSFORM_LABELCENTER, "\"labelcenter\"",
3163
                 MS_GEOMTRANSFORM_START, "\"start\"", MS_GEOMTRANSFORM_VERTICES,
3164
                 "\"vertices\"", MS_GEOMTRANSFORM_CENTROID, "\"centroid\"");
3165
  }
3166

3167
  if (style->linecap != MS_CJC_DEFAULT_CAPS) {
11✔
3168
    writeKeyword(stream, indent, "LINECAP", (int)style->linecap, 5, MS_CJC_NONE,
×
3169
                 "NONE", MS_CJC_ROUND, "ROUND", MS_CJC_SQUARE, "SQUARE",
3170
                 MS_CJC_BUTT, "BUTT", MS_CJC_TRIANGLE, "TRIANGLE");
3171
  }
3172
  if (style->linejoin != MS_CJC_DEFAULT_JOINS) {
11✔
3173
    writeKeyword(stream, indent, "LINEJOIN", (int)style->linejoin, 5,
×
3174
                 MS_CJC_NONE, "NONE", MS_CJC_ROUND, "ROUND", MS_CJC_BEVEL,
3175
                 "BEVEL", MS_CJC_MITER, "MITER");
3176
  }
3177
  writeNumber(stream, indent, "LINEJOINMAXSIZE", MS_CJC_DEFAULT_JOIN_MAXSIZE,
11✔
3178
              style->linejoinmaxsize);
3179

3180
  writeNumber(stream, indent, "MAXSCALEDENOM", -1, style->maxscaledenom);
11✔
3181
  writeNumber(stream, indent, "MAXSIZE", MS_MAXSYMBOLSIZE, style->maxsize);
11✔
3182
  writeNumber(stream, indent, "MAXWIDTH", MS_MAXSYMBOLWIDTH, style->maxwidth);
11✔
3183
  writeNumber(stream, indent, "MINSCALEDENOM", -1, style->minscaledenom);
11✔
3184
  writeNumber(stream, indent, "MINSIZE", MS_MINSYMBOLSIZE, style->minsize);
11✔
3185
  writeNumber(stream, indent, "MINWIDTH", MS_MINSYMBOLWIDTH, style->minwidth);
11✔
3186
  if ((style->numbindings > 0 &&
11✔
3187
       (style->bindings[MS_STYLE_BINDING_OFFSET_X].item ||
×
3188
        style->bindings[MS_STYLE_BINDING_OFFSET_Y].item)) ||
×
3189
      style->offsetx != 0 || style->offsety != 0)
11✔
3190
    writeDimension(stream, indent, "OFFSET", style->offsetx, style->offsety,
1✔
3191
                   style->bindings[MS_STYLE_BINDING_OFFSET_X].item,
3192
                   style->bindings[MS_STYLE_BINDING_OFFSET_Y].item);
3193
  if ((style->numbindings > 0 &&
11✔
3194
       (style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item ||
×
3195
        style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item)) ||
×
3196
      style->polaroffsetangle != 0 || style->polaroffsetpixel != 0)
11✔
3197
    writeDimension(stream, indent, "POLAROFFSET", style->polaroffsetpixel,
×
3198
                   style->polaroffsetangle,
3199
                   style->bindings[MS_STYLE_BINDING_POLAROFFSET_PIXEL].item,
3200
                   style->bindings[MS_STYLE_BINDING_POLAROFFSET_ANGLE].item);
3201

3202
  if (style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_OPACITY].item)
11✔
3203
    writeAttributeBinding(stream, indent, "OPACITY",
×
3204
                          &(style->bindings[MS_STYLE_BINDING_OPACITY]));
3205
  else
3206
    writeNumber(stream, indent, "OPACITY", 100, style->opacity);
11✔
3207

3208
  if (style->numbindings > 0 &&
11✔
3209
      style->bindings[MS_STYLE_BINDING_OUTLINECOLOR].item)
×
3210
    writeAttributeBinding(stream, indent, "OUTLINECOLOR",
×
3211
                          &(style->bindings[MS_STYLE_BINDING_OUTLINECOLOR]));
3212
  else
3213
    writeColor(stream, indent, "OUTLINECOLOR", NULL, &(style->outlinecolor));
11✔
3214

3215
  if (style->numbindings > 0 &&
11✔
3216
      style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH].item)
×
3217
    writeAttributeBinding(stream, indent, "OUTLINEWIDTH",
×
3218
                          &(style->bindings[MS_STYLE_BINDING_OUTLINEWIDTH]));
3219
  else
3220
    writeNumber(stream, indent, "OUTLINEWIDTH", 0, style->outlinewidth);
11✔
3221

3222
  /* PATTERN */
3223
  if (style->patternlength != 0) {
11✔
3224
    int i;
3225
    indent++;
×
3226
    writeBlockBegin(stream, indent, "PATTERN");
×
3227
    writeIndent(stream, indent);
3228
    for (i = 0; i < style->patternlength; i++)
×
3229
      msIO_fprintf(stream, " %.2f", style->pattern[i]);
×
3230
    msIO_fprintf(stream, "\n");
×
3231
    writeBlockEnd(stream, indent, "PATTERN");
×
3232
    indent--;
3233
  }
3234

3235
  if (style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_SIZE].item)
11✔
3236
    writeAttributeBinding(stream, indent, "SIZE",
×
3237
                          &(style->bindings[MS_STYLE_BINDING_SIZE]));
3238
  else
3239
    writeNumber(stream, indent, "SIZE", -1, style->size);
11✔
3240

3241
  if (style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_SYMBOL].item)
11✔
3242
    writeAttributeBinding(stream, indent, "SYMBOL",
×
3243
                          &(style->bindings[MS_STYLE_BINDING_SYMBOL]));
3244
  else
3245
    writeNumberOrString(stream, indent, "SYMBOL", 0, style->symbol,
11✔
3246
                        style->symbolname);
3247

3248
  if (style->numbindings > 0 && style->bindings[MS_STYLE_BINDING_WIDTH].item)
11✔
3249
    writeAttributeBinding(stream, indent, "WIDTH",
×
3250
                          &(style->bindings[MS_STYLE_BINDING_WIDTH]));
3251
  else
3252
    writeNumber(stream, indent, "WIDTH", 1, style->width);
11✔
3253

3254
  writeString(stream, indent, "RANGEITEM", NULL, style->rangeitem);
11✔
3255
  /* If COLORRANGE is valid, assume DATARANGE also needs to be written */
3256
  if (MS_VALID_COLOR(style->mincolor) && MS_VALID_COLOR(style->maxcolor)) {
11✔
3257
    writeColorRange(stream, indent, "COLORRANGE", &(style->mincolor),
×
3258
                    &(style->maxcolor));
3259
    writeDoubleRange(stream, indent, "DATARANGE", style->minvalue,
×
3260
                     style->maxvalue);
3261
  }
3262

3263
  writeBlockEnd(stream, indent, "STYLE");
11✔
3264
}
11✔
3265

3266
char *msWriteStyleToString(styleObj *style) {
1✔
3267
  msIOContext context;
3268
  msIOBuffer buffer;
3269

3270
  context.label = NULL;
1✔
3271
  context.write_channel = MS_TRUE;
1✔
3272
  context.readWriteFunc = msIO_bufferWrite;
1✔
3273
  context.cbData = &buffer;
1✔
3274
  buffer.data = NULL;
1✔
3275
  buffer.data_len = 0;
1✔
3276
  buffer.data_offset = 0;
1✔
3277

3278
  msIO_installHandlers(NULL, &context, NULL);
1✔
3279

3280
  writeStyle(stdout, -1, style);
1✔
3281
  msIO_bufferWrite(&buffer, "", 1);
1✔
3282

3283
  msIO_installHandlers(NULL, NULL, NULL);
1✔
3284

3285
  return (char *)buffer.data;
1✔
3286
}
3287

3288
/*
3289
** Initialize, load and free a single class
3290
*/
3291
int initClass(classObj *class) {
18,894✔
3292
  class->status = MS_ON;
18,894✔
3293
  class->debug = MS_OFF;
18,894✔
3294
  MS_REFCNT_INIT(class);
18,894✔
3295
  class->isfallback = FALSE;
18,894✔
3296

3297
  msInitExpression(&(class->expression));
18,894✔
3298
  class->name = NULL;
18,894✔
3299
  class->title = NULL;
18,894✔
3300
  msInitExpression(&(class->text));
18,894✔
3301

3302
  class->template = NULL;
18,894✔
3303

3304
  initHashTable(&(class->metadata));
18,894✔
3305
  initHashTable(&(class->validation));
18,894✔
3306

3307
  class->maxscaledenom = class->minscaledenom = -1.0;
18,894✔
3308
  class->minfeaturesize = -1; /* no limit */
18,894✔
3309

3310
  /* Set maxstyles = 0, styles[] will be allocated as needed on first call
3311
   * to msGrowClassStyles()
3312
   */
3313
  class->numstyles = class->maxstyles = 0;
18,894✔
3314
  class->styles = NULL;
18,894✔
3315

3316
  class->numlabels = class->maxlabels = 0;
18,894✔
3317
  class->labels = NULL;
18,894✔
3318

3319
  class->keyimage = NULL;
18,894✔
3320

3321
  class->group = NULL;
18,894✔
3322

3323
  class->leader = NULL;
18,894✔
3324

3325
  class->sizeunits = MS_INHERIT;
18,894✔
3326
  class->scalefactor = 1.0;
18,894✔
3327

3328
  return (0);
18,894✔
3329
}
3330

3331
int freeClass(classObj *class) {
18,968✔
3332
  int i;
3333

3334
  if (MS_REFCNT_DECR_IS_NOT_ZERO(class)) {
18,968✔
3335
    return MS_FAILURE;
3336
  }
3337

3338
  msFreeExpression(&(class->expression));
18,853✔
3339
  msFreeExpression(&(class->text));
18,853✔
3340
  msFree(class->name);
18,853✔
3341
  msFree(class->title);
18,853✔
3342
  msFree(class->template);
18,853✔
3343
  msFree(class->group);
18,853✔
3344

3345
  msFreeHashItems(&(class->metadata));
18,853✔
3346
  msFreeHashItems(&(class->validation));
18,853✔
3347

3348
  for (i = 0; i < class->numstyles; i++) { /* each style */
37,561✔
3349
    if (class->styles[i] != NULL) {
18,708✔
3350
      if (freeStyle(class->styles[i]) == MS_SUCCESS) {
18,708✔
3351
        msFree(class->styles[i]);
18,705✔
3352
      }
3353
    }
3354
  }
3355
  msFree(class->styles);
18,853✔
3356

3357
  for (i = 0; i < class->numlabels; i++) { /* each label */
22,102✔
3358
    if (class->labels[i] != NULL) {
3,249✔
3359
      if (freeLabel(class->labels[i]) == MS_SUCCESS) {
3,249✔
3360
        msFree(class->labels[i]);
3,246✔
3361
      }
3362
    }
3363
  }
3364
  msFree(class->labels);
18,853✔
3365

3366
  msFree(class->keyimage);
18,853✔
3367

3368
  if (class->leader) {
18,853✔
3369
    freeLabelLeader(class->leader);
16✔
3370
    msFree(class->leader);
16✔
3371
    class->leader = NULL;
16✔
3372
  }
3373

3374
  return MS_SUCCESS;
3375
}
3376

3377
/*
3378
** Ensure there is at least one free entry in the sttyles array of this
3379
** classObj. Grow the allocated styles array if necessary and allocate
3380
** a new style for styles[numstyles] if there is not already one,
3381
** setting its contents to all zero bytes (i.e. does not call initStyle()
3382
** on it).
3383
**
3384
** This function is safe to use for the initial allocation of the styles[]
3385
** array as well (i.e. when maxstyles==0 and styles==NULL)
3386
**
3387
** Returns a reference to the new styleObj on success, NULL on error.
3388
*/
3389
styleObj *msGrowClassStyles(classObj *class) {
18,830✔
3390
  /* Do we need to increase the size of styles[] by  MS_STYLE_ALLOCSIZE?
3391
   */
3392
  if (class->numstyles == class->maxstyles) {
18,830✔
3393
    styleObj **newStylePtr;
3394
    int i, newsize;
3395

3396
    newsize = class->maxstyles + MS_STYLE_ALLOCSIZE;
17,849✔
3397

3398
    /* Alloc/realloc styles */
3399
    newStylePtr =
3400
        (styleObj **)realloc(class->styles, newsize * sizeof(styleObj *));
17,849✔
3401
    MS_CHECK_ALLOC(newStylePtr, newsize * sizeof(styleObj *), NULL);
17,849✔
3402

3403
    class->styles = newStylePtr;
17,849✔
3404
    class->maxstyles = newsize;
17,849✔
3405
    for (i = class->numstyles; i < class->maxstyles; i++) {
89,245✔
3406
      class->styles[i] = NULL;
71,396✔
3407
    }
3408
  }
3409

3410
  if (class->styles[class->numstyles] == NULL) {
18,830✔
3411
    class->styles[class->numstyles] = (styleObj *)calloc(1, sizeof(styleObj));
18,830✔
3412
    MS_CHECK_ALLOC(class->styles[class->numstyles], sizeof(styleObj), NULL);
18,830✔
3413
  }
3414

3415
  return class->styles[class->numstyles];
18,830✔
3416
}
3417

3418
/* exactly the same as for a classObj */
3419
styleObj *msGrowLabelStyles(labelObj *label) {
5,817✔
3420
  /* Do we need to increase the size of styles[] by  MS_STYLE_ALLOCSIZE?
3421
   */
3422
  if (label->numstyles == label->maxstyles) {
5,817✔
3423
    styleObj **newStylePtr;
3424
    int i, newsize;
3425

3426
    newsize = label->maxstyles + MS_STYLE_ALLOCSIZE;
5,787✔
3427

3428
    /* Alloc/realloc styles */
3429
    newStylePtr =
3430
        (styleObj **)realloc(label->styles, newsize * sizeof(styleObj *));
5,787✔
3431
    MS_CHECK_ALLOC(newStylePtr, newsize * sizeof(styleObj *), NULL);
5,787✔
3432

3433
    label->styles = newStylePtr;
5,787✔
3434
    label->maxstyles = newsize;
5,787✔
3435
    for (i = label->numstyles; i < label->maxstyles; i++) {
28,935✔
3436
      label->styles[i] = NULL;
23,148✔
3437
    }
3438
  }
3439

3440
  if (label->styles[label->numstyles] == NULL) {
5,817✔
3441
    label->styles[label->numstyles] = (styleObj *)calloc(1, sizeof(styleObj));
5,817✔
3442
    MS_CHECK_ALLOC(label->styles[label->numstyles], sizeof(styleObj), NULL);
5,817✔
3443
  }
3444

3445
  return label->styles[label->numstyles];
5,817✔
3446
}
3447

3448
/* exactly the same as for a labelLeaderObj, needs refactoring */
3449
styleObj *msGrowLeaderStyles(labelLeaderObj *leader) {
16✔
3450
  /* Do we need to increase the size of styles[] by  MS_STYLE_ALLOCSIZE?
3451
   */
3452
  if (leader->numstyles == leader->maxstyles) {
16✔
3453
    styleObj **newStylePtr;
3454
    int i, newsize;
3455

3456
    newsize = leader->maxstyles + MS_STYLE_ALLOCSIZE;
16✔
3457

3458
    /* Alloc/realloc styles */
3459
    newStylePtr =
3460
        (styleObj **)realloc(leader->styles, newsize * sizeof(styleObj *));
16✔
3461
    MS_CHECK_ALLOC(newStylePtr, newsize * sizeof(styleObj *), NULL);
16✔
3462

3463
    leader->styles = newStylePtr;
16✔
3464
    leader->maxstyles = newsize;
16✔
3465
    for (i = leader->numstyles; i < leader->maxstyles; i++) {
80✔
3466
      leader->styles[i] = NULL;
64✔
3467
    }
3468
  }
3469

3470
  if (leader->styles[leader->numstyles] == NULL) {
16✔
3471
    leader->styles[leader->numstyles] = (styleObj *)calloc(1, sizeof(styleObj));
16✔
3472
    MS_CHECK_ALLOC(leader->styles[leader->numstyles], sizeof(styleObj), NULL);
16✔
3473
  }
3474

3475
  return leader->styles[leader->numstyles];
16✔
3476
}
3477

3478
/* msMaybeAllocateClassStyle()
3479
**
3480
** Ensure that requested style index exists and has been initialized.
3481
**
3482
** Returns MS_SUCCESS/MS_FAILURE.
3483
*/
3484
int msMaybeAllocateClassStyle(classObj *c, int idx) {
3,189✔
3485
  if (c == NULL)
3,189✔
3486
    return MS_FAILURE;
3487

3488
  if (idx < 0) {
3,189✔
3489
    msSetError(MS_MISCERR, "Invalid style index: %d",
×
3490
               "msMaybeAllocateClassStyle()", idx);
3491
    return MS_FAILURE;
×
3492
  }
3493

3494
  /* Alloc empty styles as needed up to idx.
3495
   * Nothing to do if requested style already exists
3496
   */
3497
  while (c->numstyles <= idx) {
6,376✔
3498
    if (msGrowClassStyles(c) == NULL)
3,187✔
3499
      return MS_FAILURE;
3500

3501
    if (initStyle(c->styles[c->numstyles]) == MS_FAILURE) {
3,187✔
3502
      msSetError(MS_MISCERR, "Failed to init new styleObj",
×
3503
                 "msMaybeAllocateClassStyle()");
3504
      freeStyle(c->styles[c->numstyles]);
×
3505
      free(c->styles[c->numstyles]);
×
3506
      c->styles[c->numstyles] = NULL;
×
3507
      return (MS_FAILURE);
×
3508
    }
3509
    c->numstyles++;
3,187✔
3510
  }
3511
  return MS_SUCCESS;
3512
}
3513

3514
/*
3515
 * Reset style info in the class to defaults
3516
 * the only members we don't touch are name, expression, and join/query stuff
3517
 * This is used with STYLEITEM before overwriting the contents of a class.
3518
 */
3519
void resetClassStyle(classObj *class) {
50✔
3520
  int i;
3521

3522
  /* reset labels */
3523
  for (i = 0; i < class->numlabels; i++) {
53✔
3524
    if (class->labels[i] != NULL) {
3✔
3525
      if (freeLabel(class->labels[i]) == MS_SUCCESS) {
3✔
3526
        msFree(class->labels[i]);
3✔
3527
      }
3528
      class->labels[i] = NULL;
3✔
3529
    }
3530
  }
3531
  class->numlabels = 0;
50✔
3532

3533
  msFreeExpression(&(class->text));
50✔
3534
  msInitExpression(&(class->text));
50✔
3535

3536
  /* reset styles */
3537
  for (i = 0; i < class->numstyles; i++) {
130✔
3538
    if (class->styles[i] != NULL) {
80✔
3539
      if (freeStyle(class->styles[i]) == MS_SUCCESS) {
80✔
3540
        msFree(class->styles[i]);
80✔
3541
      }
3542
      class->styles[i] = NULL;
80✔
3543
    }
3544
  }
3545
  class->numstyles = 0;
50✔
3546

3547
  class->layer = NULL;
50✔
3548
}
50✔
3549

3550
labelObj *msGrowClassLabels(classObj *class) {
3,269✔
3551

3552
  /* Do we need to increase the size of labels[] by MS_LABEL_ALLOCSIZE?
3553
   */
3554
  if (class->numlabels == class->maxlabels) {
3,269✔
3555
    labelObj **newLabelPtr;
3556
    int i, newsize;
3557

3558
    newsize = class->maxlabels + MS_LABEL_ALLOCSIZE;
3,198✔
3559

3560
    /* Alloc/realloc labels */
3561
    newLabelPtr =
3562
        (labelObj **)realloc(class->labels, newsize * sizeof(labelObj *));
3,198✔
3563
    MS_CHECK_ALLOC(newLabelPtr, newsize * sizeof(labelObj *), NULL);
3,198✔
3564

3565
    class->labels = newLabelPtr;
3,198✔
3566
    class->maxlabels = newsize;
3,198✔
3567
    for (i = class->numlabels; i < class->maxlabels; i++) {
9,594✔
3568
      class->labels[i] = NULL;
6,396✔
3569
    }
3570
  }
3571

3572
  if (class->labels[class->numlabels] == NULL) {
3,269✔
3573
    class->labels[class->numlabels] = (labelObj *)calloc(1, sizeof(labelObj));
3,269✔
3574
    MS_CHECK_ALLOC(class->labels[class->numlabels], sizeof(labelObj), NULL);
3,269✔
3575
  }
3576

3577
  return class->labels[class->numlabels];
3,269✔
3578
}
3579

3580
int loadClass(classObj *class, layerObj *layer) {
12,817✔
3581
  if (!class || !layer)
12,817✔
3582
    return (-1);
3583

3584
  class->layer = (layerObj *)layer;
12,817✔
3585

3586
  for (;;) {
3587
    switch (msyylex()) {
42,748✔
3588
    case (CLASS):
3589
      break; /* for string loads */
3590
    case (DEBUG):
×
3591
      if ((class->debug = getSymbol(3, MS_ON, MS_OFF, MS_NUMBER)) == -1)
×
3592
        return (-1);
3593
      if (class->debug == MS_NUMBER) {
×
3594
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, 0, 5) == MS_FAILURE) {
×
3595
          msSetError(MS_MISCERR,
×
3596
                     "Invalid DEBUG level, must be between 0 and 5 (line %d)",
3597
                     "loadClass()", msyylineno);
3598
          return (-1);
×
3599
        }
3600
        class->debug = (int)msyynumber;
×
3601
      }
3602
      break;
3603
    case (EOF):
×
3604
      msSetError(MS_EOFERR, NULL, "loadClass()");
×
3605
      return (-1);
×
3606
    case (END):
3607
      return (0);
3608
      break;
3609
    case (EXPRESSION):
3,241✔
3610
      if (loadExpression(&(class->expression)) == -1)
3,241✔
3611
        return (-1); /* loadExpression() cleans up previously allocated
3612
                        expression */
3613
      break;
3614
    case (GROUP):
1,656✔
3615
      if (getString(&class->group) == MS_FAILURE)
1,656✔
3616
        return (-1); /* getString() cleans up previously allocated string */
3617
      break;
3618
    case (KEYIMAGE):
28✔
3619
      if (getString(&class->keyimage) == MS_FAILURE)
28✔
3620
        return (-1); /* getString() cleans up previously allocated string */
3621
      break;
3622
    case (LABEL):
3,093✔
3623
      if (msGrowClassLabels(class) == NULL)
3,093✔
3624
        return (-1);
3625
      initLabel(class->labels[class->numlabels]);
3,093✔
3626
      class->labels[class->numlabels]->size =
3,093✔
3627
          MS_MEDIUM; /* only set a default if the LABEL section is present */
3628
      if (loadLabel(class->labels[class->numlabels]) == -1) {
3,093✔
3629
        freeLabel(class->labels[class->numlabels]);
×
3630
        free(class->labels[class->numlabels]);
×
3631
        class->labels[class->numlabels] = NULL;
×
3632
        return (-1);
×
3633
      }
3634
      class->numlabels++;
3,093✔
3635
      break;
3,093✔
3636
    case (LEADER):
15✔
3637
      if (!class->leader) {
15✔
3638
        class->leader = msSmallMalloc(sizeof(labelLeaderObj));
15✔
3639
        initLeader(class->leader);
15✔
3640
      }
3641
      if (loadLeader(class->leader) == -1)
15✔
3642
        return (-1);
3643
      break;
3644
    case (MAXSCALE):
44✔
3645
    case (MAXSCALEDENOM):
3646
      if (getDouble(&(class->maxscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1)
44✔
3647
        return (-1);
3648
      break;
3649
    case (METADATA):
402✔
3650
      if (loadHashTable(&(class->metadata)) != MS_SUCCESS)
402✔
3651
        return (-1);
3652
      break;
3653
    case (MINSCALE):
16✔
3654
    case (MINSCALEDENOM):
3655
      if (getDouble(&(class->minscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1)
16✔
3656
        return (-1);
3657
      break;
3658
    case (MINFEATURESIZE):
×
3659
      if (getInteger(&(class->minfeaturesize), MS_NUM_CHECK_GT, 0, -1) == -1)
×
3660
        return (-1);
3661
      break;
3662
    case (NAME):
7,940✔
3663
      if (getString(&class->name) == MS_FAILURE)
7,940✔
3664
        return (-1);
3665
      break;
3666
    case (STATUS):
×
3667
      if ((class->status = getSymbol(2, MS_ON, MS_OFF)) == -1)
×
3668
        return (-1);
3669
      break;
3670
    case (STYLE):
12,589✔
3671
      if (msGrowClassStyles(class) == NULL)
12,589✔
3672
        return (-1);
3673
      initStyle(class->styles[class->numstyles]);
12,589✔
3674
      if (loadStyle(class->styles[class->numstyles]) != MS_SUCCESS) {
12,589✔
3675
        freeStyle(class->styles[class->numstyles]);
×
3676
        free(class->styles[class->numstyles]);
×
3677
        class->styles[class->numstyles] = NULL;
×
3678
        return (-1);
×
3679
      }
3680
      class->numstyles++;
12,589✔
3681
      break;
12,589✔
3682
    case (TEMPLATE):
402✔
3683
      if (getString(&class->template) == MS_FAILURE)
402✔
3684
        return (-1); /* getString() cleans up previously allocated string */
3685
      break;
3686
    case (TEXT):
477✔
3687
      if (loadExpression(&(class->text)) == -1)
477✔
3688
        return (-1); /* loadExpression() cleans up previously allocated
3689
                        expression */
3690
      if ((class->text.type != MS_STRING) &&
477✔
3691
          (class->text.type != MS_EXPRESSION)) {
3692
        msSetError(
×
3693
            MS_MISCERR,
3694
            "Text expressions support constant or tagged replacement strings.",
3695
            "loadClass()");
3696
        return (-1);
×
3697
      }
3698
      break;
3699
    case (TITLE):
15✔
3700
      if (getString(&class->title) == MS_FAILURE)
15✔
3701
        return (-1); /* getString() cleans up previously allocated string */
3702
      break;
3703
    case (VALIDATION):
13✔
3704
      if (loadHashTable(&(class->validation)) != MS_SUCCESS)
13✔
3705
        return (-1);
3706
      break;
3707
    default:
×
3708
      if (strlen(msyystring_buffer) > 0) {
×
3709
        msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
3710
                   "loadClass()", msyystring_buffer, msyylineno);
3711
        return (-1);
×
3712
      } else {
3713
        return (0); /* end of a string, not an error */
3714
      }
3715
    }
3716
  }
3717
}
3718

3719
static int classResolveSymbolNames(classObj *class) {
12,817✔
3720
  int i, j;
3721
  int try_addimage_if_notfound = MS_TRUE;
3722

3723
  /* step through styles and labels to resolve symbol names */
3724
  /* class styles */
3725
  for (i = 0; i < class->numstyles; i++) {
25,406✔
3726
    if (class->styles[i]->symbolname) {
12,589✔
3727
      if ((class->styles[i]->symbol = msGetSymbolIndex(
1,717✔
3728
               &(class->layer->map->symbolset), class->styles[i]->symbolname,
1,717✔
3729
               try_addimage_if_notfound)) == -1) {
3730
        msSetError(MS_MISCERR,
×
3731
                   "Undefined symbol \"%s\" in class, style %d of layer %s.",
3732
                   "classResolveSymbolNames()", class->styles[i]->symbolname, i,
×
3733
                   class->layer->name);
×
3734
        return MS_FAILURE;
×
3735
      }
3736
    }
3737
  }
3738

3739
  /* label styles */
3740
  for (i = 0; i < class->numlabels; i++) {
15,910✔
3741
    for (j = 0; j < class->labels[i]->numstyles; j++) {
4,258✔
3742
      if (class->labels[i]->styles[j]->symbolname) {
1,165✔
3743
        if ((class->labels[i]->styles[j]->symbol =
694✔
3744
                 msGetSymbolIndex(&(class->layer->map->symbolset),
694✔
3745
                                  class->labels[i]->styles[j]->symbolname,
3746
                                  try_addimage_if_notfound)) == -1) {
3747
          msSetError(
×
3748
              MS_MISCERR,
3749
              "Undefined symbol \"%s\" in class, label style %d of layer %s.",
3750
              "classResolveSymbolNames()",
3751
              class->labels[i]->styles[j]->symbolname, j, class->layer->name);
×
3752
          return MS_FAILURE;
×
3753
        }
3754
      }
3755
    }
3756
  }
3757

3758
  return MS_SUCCESS;
3759
}
3760

3761
int msUpdateClassFromString(classObj *class, char *string) {
×
3762
  if (!class || !string)
×
3763
    return MS_FAILURE;
3764

3765
  msAcquireLock(TLOCK_PARSER);
×
3766

3767
  msyystate = MS_TOKENIZE_STRING;
×
3768
  msyystring = string;
×
3769
  msyylex(); /* sets things up, but doesn't process any tokens */
×
3770

3771
  msyylineno = 1; /* start at line 1 */
×
3772

3773
  if (loadClass(class, class->layer) == -1) {
×
3774
    msReleaseLock(TLOCK_PARSER);
×
3775
    return MS_FAILURE; /* parse error */
×
3776
    ;
3777
  }
3778

3779
  msyylex_destroy();
×
3780
  msReleaseLock(TLOCK_PARSER);
×
3781

3782
  if (classResolveSymbolNames(class) != MS_SUCCESS)
×
3783
    return MS_FAILURE;
×
3784

3785
  return MS_SUCCESS;
3786
}
3787

3788
static void writeClass(FILE *stream, int indent, classObj *class) {
9✔
3789
  int i;
3790

3791
  if (class->status == MS_DELETE)
9✔
3792
    return;
3793

3794
  indent++;
9✔
3795
  writeBlockBegin(stream, indent, "CLASS");
9✔
3796
  writeString(stream, indent, "NAME", NULL, class->name);
9✔
3797
  writeString(stream, indent, "GROUP", NULL, class->group);
9✔
3798
  writeNumber(stream, indent, "DEBUG", 0, class->debug);
9✔
3799
  writeExpression(stream, indent, "EXPRESSION", &(class->expression));
9✔
3800
  writeString(stream, indent, "KEYIMAGE", NULL, class->keyimage);
9✔
3801
  for (i = 0; i < class->numlabels; i++)
12✔
3802
    writeLabel(stream, indent, class->labels[i]);
3✔
3803
  if (class->leader)
9✔
3804
    writeLeader(stream, indent, class->leader);
×
3805
  writeNumber(stream, indent, "MAXSCALEDENOM", -1, class->maxscaledenom);
9✔
3806
  writeHashTable(stream, indent, "METADATA", &(class->metadata));
9✔
3807
  writeNumber(stream, indent, "MINSCALEDENOM", -1, class->minscaledenom);
9✔
3808
  writeNumber(stream, indent, "MINFEATURESIZE", -1, class->minfeaturesize);
9✔
3809
  writeKeyword(stream, indent, "STATUS", class->status, 1, MS_OFF, "OFF");
9✔
3810
  for (i = 0; i < class->numstyles; i++)
18✔
3811
    writeStyle(stream, indent, class->styles[i]);
9✔
3812
  writeString(stream, indent, "TEMPLATE", NULL, class->template);
9✔
3813
  writeExpression(stream, indent, "TEXT", &(class->text));
9✔
3814
  writeString(stream, indent, "TITLE", NULL, class->title);
9✔
3815
  writeHashTable(stream, indent, "VALIDATION", &(class->validation));
9✔
3816
  writeBlockEnd(stream, indent, "CLASS");
9✔
3817
}
3818

3819
char *msWriteClassToString(classObj *class) {
×
3820
  msIOContext context;
3821
  msIOBuffer buffer;
3822

3823
  context.label = NULL;
×
3824
  context.write_channel = MS_TRUE;
×
3825
  context.readWriteFunc = msIO_bufferWrite;
×
3826
  context.cbData = &buffer;
×
3827
  buffer.data = NULL;
×
3828
  buffer.data_len = 0;
×
3829
  buffer.data_offset = 0;
×
3830

3831
  msIO_installHandlers(NULL, &context, NULL);
×
3832

3833
  writeClass(stdout, -1, class);
×
3834
  msIO_bufferWrite(&buffer, "", 1);
×
3835

3836
  msIO_installHandlers(NULL, NULL, NULL);
×
3837

3838
  return (char *)buffer.data;
×
3839
}
3840

3841
int initCompositingFilter(CompositingFilter *filter) {
×
3842
  filter->filter = NULL;
×
3843
  filter->next = NULL;
×
3844
  return MS_SUCCESS;
×
3845
}
3846

3847
void freeCompositingFilter(CompositingFilter *filter) {
82✔
3848
  if (!filter)
82✔
3849
    return;
3850
  if (filter->next)
×
3851
    freeCompositingFilter(filter->next);
×
3852
  free(filter->filter);
×
3853
  free(filter);
×
3854
}
3855

3856
int initLayerCompositer(LayerCompositer *compositer) {
82✔
3857
  compositer->comp_op = MS_COMPOP_SRC_OVER;
82✔
3858
  compositer->opacity = 100;
82✔
3859
  compositer->next = NULL;
82✔
3860
  compositer->filter = NULL;
82✔
3861
  return MS_SUCCESS;
82✔
3862
}
3863

3864
void freeLayerCompositer(LayerCompositer *compositer) {
82✔
3865
  if (!compositer)
82✔
3866
    return;
3867
  if (compositer->next)
82✔
3868
    freeLayerCompositer(compositer->next);
×
3869
  freeCompositingFilter(compositer->filter);
82✔
3870
  free(compositer);
82✔
3871
}
3872

3873
/*
3874
** Initialize, load and free a single layer structure
3875
*/
3876
int initLayer(layerObj *layer, mapObj *map) {
13,656✔
3877
  if (layer == NULL) {
13,656✔
3878
    msSetError(MS_MEMERR, "Layer is null", "initLayer()");
×
3879
    return (-1);
×
3880
  }
3881
  layer->debug = (int)msGetGlobalDebugLevel();
13,656✔
3882
  MS_REFCNT_INIT(layer);
13,656✔
3883

3884
  /* Set maxclasses = 0, class[] will be allocated as needed on first call
3885
   * to msGrowLayerClasses()
3886
   */
3887
  layer->numclasses = 0;
13,656✔
3888
  layer->maxclasses = 0;
13,656✔
3889
  layer->class = NULL;
13,656✔
3890

3891
  layer->name = NULL;
13,656✔
3892
  layer->group = NULL;
13,656✔
3893
  layer->status = MS_OFF;
13,656✔
3894
  layer->data = NULL;
13,656✔
3895
  layer->rendermode = MS_FIRST_MATCHING_CLASS;
13,656✔
3896

3897
  layer->map = map; /* point back to the encompassing structure */
13,656✔
3898

3899
  layer->type = -1;
13,656✔
3900

3901
  layer->toleranceunits = MS_PIXELS;
13,656✔
3902
  layer->tolerance =
13,656✔
3903
      -1; /* perhaps this should have a different value based on type */
3904

3905
  layer->symbolscaledenom = -1.0; /* -1 means nothing is set */
13,656✔
3906
  layer->scalefactor = 1.0;
13,656✔
3907
  layer->maxscaledenom = -1.0;
13,656✔
3908
  layer->minscaledenom = -1.0;
13,656✔
3909
  layer->minfeaturesize = -1; /* no limit */
13,656✔
3910
  layer->maxgeowidth = -1.0;
13,656✔
3911
  layer->mingeowidth = -1.0;
13,656✔
3912

3913
  layer->sizeunits = MS_PIXELS;
13,656✔
3914

3915
  layer->maxfeatures = -1; /* no quota */
13,656✔
3916
  layer->startindex = -1;  /*used for pagination*/
13,656✔
3917

3918
  layer->scaletokens = NULL;
13,656✔
3919
  layer->numscaletokens = 0;
13,656✔
3920

3921
  layer->template = layer->header = layer->footer = NULL;
13,656✔
3922

3923
  layer->transform = MS_TRUE;
13,656✔
3924

3925
  layer->classitem = NULL;
13,656✔
3926
  layer->classitemindex = -1;
13,656✔
3927

3928
  layer->units = MS_METERS;
13,656✔
3929
  if (msInitProjection(&(layer->projection)) == -1)
13,656✔
3930
    return (-1);
3931

3932
  if (map) {
13,656✔
3933
    msProjectionInheritContextFrom(&(layer->projection), &(map->projection));
13,625✔
3934
  }
3935

3936
  layer->project = MS_TRUE;
13,656✔
3937
  layer->reprojectorLayerToMap = NULL;
13,656✔
3938
  layer->reprojectorMapToLayer = NULL;
13,656✔
3939

3940
  initCluster(&layer->cluster);
13,656✔
3941

3942
  MS_INIT_COLOR(layer->offsite, -1, -1, -1, 255);
13,656✔
3943

3944
  layer->labelcache = MS_ON;
13,656✔
3945
  layer->postlabelcache = MS_FALSE;
13,656✔
3946

3947
  layer->labelitem = NULL;
13,656✔
3948
  layer->labelitemindex = -1;
13,656✔
3949

3950
  layer->labelmaxscaledenom = -1;
13,656✔
3951
  layer->labelminscaledenom = -1;
13,656✔
3952

3953
  layer->tileitem = msStrdup("location");
13,656✔
3954
  layer->tileitemindex = -1;
13,656✔
3955
  layer->tileindex = NULL;
13,656✔
3956
  layer->tilesrs = NULL;
13,656✔
3957

3958
  layer->bandsitem = NULL;
13,656✔
3959
  layer->bandsitemindex = -1;
13,656✔
3960

3961
  layer->currentfeature = layer->features = NULL;
13,656✔
3962

3963
  layer->connection = NULL;
13,656✔
3964
  layer->plugin_library = NULL;
13,656✔
3965
  layer->plugin_library_original = NULL;
13,656✔
3966
  layer->connectiontype = MS_SHAPEFILE;
13,656✔
3967
  layer->vtable = NULL;
13,656✔
3968
  layer->classgroup = NULL;
13,656✔
3969

3970
  layer->layerinfo = NULL;
13,656✔
3971
  layer->wfslayerinfo = NULL;
13,656✔
3972

3973
  layer->items = NULL;
13,656✔
3974
  layer->iteminfo = NULL;
13,656✔
3975
  layer->numitems = 0;
13,656✔
3976

3977
  layer->resultcache = NULL;
13,656✔
3978

3979
  msInitExpression(&(layer->filter));
13,656✔
3980
  layer->filteritem = NULL;
13,656✔
3981
  layer->filteritemindex = -1;
13,656✔
3982

3983
  layer->
3984
    requires
3985
  = layer->labelrequires = NULL;
13,656✔
3986

3987
  initHashTable(&(layer->metadata));
13,656✔
3988
  initHashTable(&(layer->bindvals));
13,656✔
3989
  initHashTable(&(layer->validation));
13,656✔
3990

3991
  layer->styleitem = NULL;
13,656✔
3992
  layer->styleitemindex = -1;
13,656✔
3993

3994
  layer->processing = NULL;
13,656✔
3995
  layer->numjoins = 0;
13,656✔
3996
  layer->joins = (joinObj *)malloc(MS_MAXJOINS * sizeof(joinObj));
13,656✔
3997
  MS_CHECK_ALLOC(layer->joins, MS_MAXJOINS * sizeof(joinObj), -1);
13,656✔
3998

3999
  layer->extent.minx = -1.0;
13,656✔
4000
  layer->extent.miny = -1.0;
13,656✔
4001
  layer->extent.maxx = -1.0;
13,656✔
4002
  layer->extent.maxy = -1.0;
13,656✔
4003

4004
  layer->mask = NULL;
13,656✔
4005
  layer->maskimage = NULL;
13,656✔
4006
  layer->grid = NULL;
13,656✔
4007

4008
  msInitExpression(&(layer->_geomtransform));
13,656✔
4009
  layer->_geomtransform.type = MS_GEOMTRANSFORM_NONE;
13,656✔
4010

4011
  msInitExpression(&(layer->utfdata));
13,656✔
4012
  layer->utfitem = NULL;
13,656✔
4013
  layer->utfitemindex = -1;
13,656✔
4014

4015
  layer->encoding = NULL;
13,656✔
4016

4017
  layer->sortBy.nProperties = 0;
13,656✔
4018
  layer->sortBy.properties = NULL;
13,656✔
4019
  layer->orig_st = NULL;
13,656✔
4020

4021
  layer->compositer = NULL;
13,656✔
4022

4023
  initHashTable(&(layer->connectionoptions));
13,656✔
4024

4025
  return (0);
13,656✔
4026
}
4027

4028
int initScaleToken(scaleTokenObj *token) {
56✔
4029
  token->n_entries = 0;
56✔
4030
  token->name = NULL;
56✔
4031
  token->tokens = NULL;
56✔
4032
  return MS_SUCCESS;
56✔
4033
}
4034

4035
int freeScaleTokenEntry(scaleTokenEntryObj *token) {
128✔
4036
  msFree(token->value);
128✔
4037
  return MS_SUCCESS;
128✔
4038
}
4039

4040
int freeScaleToken(scaleTokenObj *scaletoken) {
56✔
4041
  int i;
4042
  msFree(scaletoken->name);
56✔
4043
  for (i = 0; i < scaletoken->n_entries; i++) {
184✔
4044
    freeScaleTokenEntry(&scaletoken->tokens[i]);
128✔
4045
  }
4046
  msFree(scaletoken->tokens);
56✔
4047
  return MS_SUCCESS;
56✔
4048
}
4049

4050
int freeLayer(layerObj *layer) {
13,956✔
4051
  int i;
4052
  if (!layer)
13,956✔
4053
    return MS_FAILURE;
4054
  if (MS_REFCNT_DECR_IS_NOT_ZERO(layer)) {
13,956✔
4055
    return MS_FAILURE;
4056
  }
4057

4058
  if (layer->debug >= MS_DEBUGLEVEL_VVV)
13,621✔
4059
    msDebug("freeLayer(): freeing layer at %p.\n", layer);
21✔
4060

4061
  if (msLayerIsOpen(layer))
13,621✔
4062
    msLayerClose(layer);
879✔
4063

4064
  msFree(layer->name);
13,621✔
4065
  msFree(layer->encoding);
13,621✔
4066
  msFree(layer->group);
13,621✔
4067
  msFree(layer->data);
13,621✔
4068
  msFree(layer->classitem);
13,621✔
4069
  msFree(layer->labelitem);
13,621✔
4070
  msFree(layer->header);
13,621✔
4071
  msFree(layer->footer);
13,621✔
4072
  msFree(layer->template);
13,621✔
4073
  msFree(layer->tileindex);
13,621✔
4074
  msFree(layer->tileitem);
13,621✔
4075
  msFree(layer->tilesrs);
13,621✔
4076
  msFree(layer->bandsitem);
13,621✔
4077
  msFree(layer->plugin_library);
13,621✔
4078
  msFree(layer->plugin_library_original);
13,621✔
4079
  msFree(layer->connection);
13,621✔
4080
  msFree(layer->vtable);
13,621✔
4081
  msFree(layer->classgroup);
13,621✔
4082

4083
  msProjectDestroyReprojector(layer->reprojectorLayerToMap);
13,621✔
4084
  msProjectDestroyReprojector(layer->reprojectorMapToLayer);
13,621✔
4085
  msFreeProjection(&(layer->projection));
13,621✔
4086
  msFreeExpression(&layer->_geomtransform);
13,621✔
4087

4088
  freeCluster(&layer->cluster);
13,621✔
4089

4090
  for (i = 0; i < layer->maxclasses; i++) {
104,445✔
4091
    if (layer->class[i] != NULL) {
90,824✔
4092
      layer->class[i]->layer = NULL;
18,647✔
4093
      if (freeClass(layer->class[i]) == MS_SUCCESS) {
18,647✔
4094
        msFree(layer->class[i]);
18,638✔
4095
      }
4096
    }
4097
  }
4098
  msFree(layer->class);
13,621✔
4099

4100
  if (layer->numscaletokens > 0) {
13,621✔
4101
    for (i = 0; i < layer->numscaletokens; i++) {
86✔
4102
      freeScaleToken(&layer->scaletokens[i]);
56✔
4103
    }
4104
    msFree(layer->scaletokens);
30✔
4105
  }
4106

4107
  if (layer->features)
13,621✔
4108
    freeFeatureList(layer->features);
2,362✔
4109

4110
  if (layer->resultcache) {
13,621✔
4111
    cleanupResultCache(layer->resultcache);
889✔
4112
    msFree(layer->resultcache);
889✔
4113
  }
4114

4115
  msFree(layer->styleitem);
13,621✔
4116

4117
  msFree(layer->filteritem);
13,621✔
4118
  msFreeExpression(&(layer->filter));
13,621✔
4119

4120
  msFree(layer->requires);
13,621✔
4121
  msFree(layer->labelrequires);
13,621✔
4122

4123
  msFreeHashItems(&(layer->metadata));
13,621✔
4124
  msFreeHashItems(&(layer->validation));
13,621✔
4125
  msFreeHashItems(&layer->bindvals);
13,621✔
4126

4127
  CSLDestroy(layer->processing);
13,621✔
4128

4129
  for (i = 0; i < layer->numjoins; i++) /* each join */
13,621✔
4130
    freeJoin(&(layer->joins[i]));
×
4131
  msFree(layer->joins);
13,621✔
4132
  layer->numjoins = 0;
13,621✔
4133

4134
  layer->classgroup = NULL;
13,621✔
4135

4136
  msFree(layer->mask);
13,621✔
4137
  if (layer->maskimage) {
13,621✔
4138
    msFreeImage(layer->maskimage);
47✔
4139
  }
4140

4141
  if (layer->compositer) {
13,621✔
4142
    freeLayerCompositer(layer->compositer);
82✔
4143
  }
4144

4145
  if (layer->grid) {
13,621✔
4146
    freeGrid(layer->grid);
8✔
4147
    msFree(layer->grid);
8✔
4148
  }
4149

4150
  msFreeExpression(&(layer->utfdata));
13,621✔
4151
  msFree(layer->utfitem);
13,621✔
4152

4153
  for (i = 0; i < layer->sortBy.nProperties; i++)
13,634✔
4154
    msFree(layer->sortBy.properties[i].item);
13✔
4155
  msFree(layer->sortBy.properties);
13,621✔
4156

4157
  msFreeHashItems(&layer->connectionoptions);
13,621✔
4158

4159
  return MS_SUCCESS;
13,621✔
4160
}
4161

4162
/*
4163
** Ensure there is at least one free entry in the class array of this
4164
** layerObj. Grow the allocated class array if necessary and allocate
4165
** a new class for class[numclasses] if there is not already one,
4166
** setting its contents to all zero bytes (i.e. does not call initClass()
4167
** on it).
4168
**
4169
** This function is safe to use for the initial allocation of the class[]
4170
** array as well (i.e. when maxclasses==0 and class==NULL)
4171
**
4172
** Returns a reference to the new classObj on success, NULL on error.
4173
*/
4174
classObj *msGrowLayerClasses(layerObj *layer) {
18,888✔
4175
  /* Do we need to increase the size of class[] by  MS_CLASS_ALLOCSIZE?
4176
   */
4177
  if (layer->numclasses == layer->maxclasses) {
18,888✔
4178
    classObj **newClassPtr;
4179
    int i, newsize;
4180

4181
    newsize = layer->maxclasses + MS_CLASS_ALLOCSIZE;
11,382✔
4182

4183
    /* Alloc/realloc classes */
4184
    newClassPtr =
4185
        (classObj **)realloc(layer->class, newsize * sizeof(classObj *));
11,382✔
4186
    MS_CHECK_ALLOC(newClassPtr, newsize * sizeof(classObj *), NULL);
11,382✔
4187

4188
    layer->class = newClassPtr;
11,382✔
4189
    layer->maxclasses = newsize;
11,382✔
4190
    for (i = layer->numclasses; i < layer->maxclasses; i++) {
102,438✔
4191
      layer->class[i] = NULL;
91,056✔
4192
    }
4193
  }
4194

4195
  if (layer->class[layer->numclasses] == NULL) {
18,888✔
4196
    layer->class[layer->numclasses] = (classObj *)calloc(1, sizeof(classObj));
18,888✔
4197
    MS_CHECK_ALLOC(layer->class[layer->numclasses], sizeof(classObj), NULL);
18,888✔
4198
  }
4199

4200
  return layer->class[layer->numclasses];
18,888✔
4201
}
4202

4203
scaleTokenObj *msGrowLayerScaletokens(layerObj *layer) {
56✔
4204
  layer->scaletokens = msSmallRealloc(
112✔
4205
      layer->scaletokens, (layer->numscaletokens + 1) * sizeof(scaleTokenObj));
56✔
4206
  memset(&layer->scaletokens[layer->numscaletokens], 0, sizeof(scaleTokenObj));
56✔
4207
  return &layer->scaletokens[layer->numscaletokens];
56✔
4208
}
4209

4210
int loadScaletoken(scaleTokenObj *token, layerObj *layer) {
56✔
4211
  (void)layer;
4212
  for (;;) {
4213
    int stop = 0;
4214
    switch (msyylex()) {
168✔
4215
    case (EOF):
×
4216
      msSetError(MS_EOFERR, NULL, "loadScaletoken()");
×
4217
      return (MS_FAILURE);
×
4218
    case (NAME):
56✔
4219
      if (getString(&token->name) == MS_FAILURE)
56✔
4220
        return (MS_FAILURE);
4221
      break;
4222
    case (VALUES):
184✔
4223
      for (;;) {
4224
        if (stop)
4225
          break;
4226
        switch (msyylex()) {
184✔
4227
        case (EOF):
×
4228
          msSetError(MS_EOFERR, NULL, "loadScaletoken()");
×
4229
          return (MS_FAILURE);
×
4230
        case (END):
56✔
4231
          stop = 1;
4232
          if (token->n_entries == 0) {
56✔
4233
            msSetError(MS_PARSEERR,
×
4234
                       "Scaletoken (line:%d) has no VALUES defined",
4235
                       "loadScaleToken()", msyylineno);
4236
            return (MS_FAILURE);
×
4237
          }
4238
          token->tokens[token->n_entries - 1].maxscale = DBL_MAX;
56✔
4239
          break;
4240
        case (MS_STRING):
128✔
4241
          /* we have a key */
4242
          token->tokens =
128✔
4243
              msSmallRealloc(token->tokens, (token->n_entries + 1) *
128✔
4244
                                                sizeof(scaleTokenEntryObj));
4245

4246
          if (1 != sscanf(msyystring_buffer, "%lf",
128✔
4247
                          &token->tokens[token->n_entries].minscale)) {
128✔
4248
            msSetError(MS_PARSEERR,
×
4249
                       "failed to parse SCALETOKEN VALUE (%s):(line %d), "
4250
                       "expecting \"minscale\"",
4251
                       "loadScaletoken()", msyystring_buffer, msyylineno);
4252
            return (MS_FAILURE);
×
4253
          }
4254
          if (token->n_entries == 0) {
128✔
4255
            /* check supplied value was 0*/
4256
            if (token->tokens[0].minscale != 0) {
56✔
4257
              msSetError(MS_PARSEERR,
×
4258
                         "First SCALETOKEN VALUE (%s):(line %d) must be zero, "
4259
                         "expecting \"0\"",
4260
                         "loadScaletoken()", msyystring_buffer, msyylineno);
4261
              return (MS_FAILURE);
×
4262
            }
4263
          } else {
4264
            /* set max scale of previous token */
4265
            token->tokens[token->n_entries - 1].maxscale =
72✔
4266
                token->tokens[token->n_entries].minscale;
72✔
4267
          }
4268
          token->tokens[token->n_entries].value = NULL;
128✔
4269
          if (getString(&(token->tokens[token->n_entries].value)) == MS_FAILURE)
128✔
4270
            return (MS_FAILURE);
4271
          token->n_entries++;
128✔
4272
          break;
128✔
4273
        default:
×
4274
          msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
4275
                     "loadScaletoken()", msyystring_buffer, msyylineno);
4276
          return (MS_FAILURE);
×
4277
        }
4278
      }
4279
      break;
4280
    case (END):
56✔
4281
      if (!token->name || !*(token->name)) {
56✔
4282
        msSetError(MS_PARSEERR,
×
4283
                   "ScaleToken missing mandatory NAME entry (line %d)",
4284
                   "loadScaleToken()", msyylineno);
4285
        return MS_FAILURE;
×
4286
      }
4287
      if (token->n_entries == 0) {
56✔
4288
        msSetError(MS_PARSEERR,
×
4289
                   "ScaleToken missing at least one VALUES entry (line %d)",
4290
                   "loadScaleToken()", msyylineno);
4291
        return MS_FAILURE;
×
4292
      }
4293
      return MS_SUCCESS;
4294
    default:
×
4295
      msSetError(MS_IDENTERR, "Parsing error 2 near (%s):(line %d)",
×
4296
                 "loadScaletoken()", msyystring_buffer, msyylineno);
4297
      return (MS_FAILURE);
×
4298
    }
4299
  } /* next token*/
4300
}
4301

4302
static const struct {
4303
  CompositingOperation eOp;
4304
  const char *pszName;
4305
} CompOps[] = {
4306
    {MS_COMPOP_CLEAR, "clear"},
4307
    {MS_COMPOP_COLOR_BURN, "color-burn"},
4308
    {MS_COMPOP_COLOR_DODGE, "color-dodge"},
4309
    {MS_COMPOP_CONTRAST, "contrast"},
4310
    {MS_COMPOP_DARKEN, "darken"},
4311
    {MS_COMPOP_DIFFERENCE, "difference"},
4312
    {MS_COMPOP_DST, "dst"},
4313
    {MS_COMPOP_DST_ATOP, "dst-atop"},
4314
    {MS_COMPOP_DST_IN, "dst-in"},
4315
    {MS_COMPOP_DST_OUT, "dst-out"},
4316
    {MS_COMPOP_DST_OVER, "dst-over"},
4317
    {MS_COMPOP_EXCLUSION, "exclusion"},
4318
    {MS_COMPOP_HARD_LIGHT, "hard-light"},
4319
    {MS_COMPOP_HSL_COLOR, "hsl-color"},
4320
    {MS_COMPOP_HSL_HUE, "hsl-hue"},
4321
    {MS_COMPOP_HSL_LUMINOSITY, "hsl-luminosity"},
4322
    {MS_COMPOP_HSL_SATURATION, "hsl-saturation"},
4323
    {MS_COMPOP_INVERT, "invert"},
4324
    {MS_COMPOP_INVERT_RGB, "invert-rgb"},
4325
    {MS_COMPOP_LIGHTEN, "lighten"},
4326
    {MS_COMPOP_MINUS, "minus"},
4327
    {MS_COMPOP_MULTIPLY, "multiply"},
4328
    {MS_COMPOP_OVERLAY, "overlay"},
4329
    {MS_COMPOP_PLUS, "plus"},
4330
    {MS_COMPOP_SCREEN, "screen"},
4331
    {MS_COMPOP_SOFT_LIGHT, "soft-light"},
4332
    {MS_COMPOP_SRC, "src"},
4333
    {MS_COMPOP_SRC_ATOP, "src-atop"},
4334
    {MS_COMPOP_SRC_IN, "src-in"},
4335
    {MS_COMPOP_SRC_OUT, "src-out"},
4336
    {MS_COMPOP_SRC_OVER, "src-over"},
4337
    {MS_COMPOP_XOR, "xor"},
4338
};
4339

4340
#define SIZEOF_COMP_OPS ((int)(sizeof(CompOps) / sizeof(CompOps[0])))
4341

4342
int loadLayerCompositer(LayerCompositer *compositer) {
81✔
4343
  for (;;) {
4344
    switch (msyylex()) {
176✔
4345
    case COMPFILTER: {
×
4346
      CompositingFilter **filter = &compositer->filter;
×
4347
      while (*filter) {
×
4348
        filter = &((*filter)->next);
×
4349
      }
4350
      *filter = msSmallMalloc(sizeof(CompositingFilter));
×
4351
      initCompositingFilter(*filter);
×
4352
      if (getString(&((*filter)->filter)) == MS_FAILURE)
×
4353
        return (MS_FAILURE);
4354
    } break;
4355
    case COMPOP: {
14✔
4356
      char *compop = NULL;
14✔
4357
      if (getString(&compop) == MS_FAILURE)
14✔
4358
        return (MS_FAILURE);
×
4359

4360
      bool bFound = false;
4361
      for (int i = 0; i < SIZEOF_COMP_OPS; ++i) {
240✔
4362
        if (strcmp(compop, CompOps[i].pszName) == 0) {
240✔
4363
          bFound = true;
4364
          compositer->comp_op = CompOps[i].eOp;
14✔
4365
          break;
4366
        }
4367
      }
4368
      if (!bFound) {
4369
        msSetError(MS_PARSEERR, "Unknown COMPOP \"%s\"",
×
4370
                   "loadLayerCompositer()", compop);
4371
        free(compop);
×
4372
        return MS_FAILURE;
×
4373
      }
4374
      free(compop);
14✔
4375
    } break;
14✔
4376
    case END:
4377
      return MS_SUCCESS;
4378
    case OPACITY:
81✔
4379
      if (getInteger(&(compositer->opacity), MS_NUM_CHECK_RANGE, 0, 100) ==
81✔
4380
          -1) {
4381
        msSetError(MS_PARSEERR, "OPACITY must be between 0 and 100 (line %d)",
×
4382
                   "loadLayerCompositer()", msyylineno);
4383
        return MS_FAILURE;
×
4384
      }
4385
      break;
4386
    default:
×
4387
      msSetError(MS_IDENTERR, "Parsing error 2 near (%s):(line %d)",
×
4388
                 "loadLayerCompositer()", msyystring_buffer, msyylineno);
4389
      return (MS_FAILURE);
×
4390
    }
4391
  }
4392
}
4393
int loadLayer(layerObj *layer, mapObj *map) {
12,770✔
4394
  int type;
4395

4396
  layer->map = (mapObj *)map;
12,770✔
4397

4398
  for (;;) {
4399
    switch (msyylex()) {
107,159✔
4400
    case (BINDVALS):
3✔
4401
      if (loadHashTable(&(layer->bindvals)) != MS_SUCCESS)
3✔
4402
        return (-1);
4403
      break;
4404
    case (CLASS):
12,817✔
4405
      if (msGrowLayerClasses(layer) == NULL)
12,817✔
4406
        return (-1);
4407
      initClass(layer->class[layer->numclasses]);
12,817✔
4408
      if (loadClass(layer->class[layer->numclasses], layer) == -1) {
12,817✔
4409
        freeClass(layer->class[layer->numclasses]);
×
4410
        free(layer->class[layer->numclasses]);
×
4411
        layer->class[layer->numclasses] = NULL;
×
4412
        return (-1);
×
4413
      }
4414
      layer->numclasses++;
12,817✔
4415
      break;
12,817✔
4416
    case (CLUSTER):
4✔
4417
      if (loadCluster(&layer->cluster) == -1)
4✔
4418
        return (-1);
4419
      break;
4420
    case (CLASSGROUP):
781✔
4421
      if (getString(&layer->classgroup) == MS_FAILURE)
781✔
4422
        return (-1); /* getString() cleans up previously allocated string */
4423
      break;
4424
    case (CLASSITEM):
3,093✔
4425
      if (getString(&layer->classitem) == MS_FAILURE)
3,093✔
4426
        return (-1); /* getString() cleans up previously allocated string */
4427
      break;
4428
    case (COMPOSITE): {
81✔
4429
      LayerCompositer *compositer = msSmallMalloc(sizeof(LayerCompositer));
81✔
4430
      initLayerCompositer(compositer);
81✔
4431
      if (MS_FAILURE == loadLayerCompositer(compositer)) {
81✔
4432
        freeLayerCompositer(compositer);
×
4433
        return -1;
×
4434
      }
4435
      if (!layer->compositer) {
81✔
4436
        layer->compositer = compositer;
81✔
4437
      } else {
4438
        LayerCompositer *lctmp = layer->compositer;
4439
        while (lctmp->next)
×
4440
          lctmp = lctmp->next;
4441
        lctmp->next = compositer;
×
4442
      }
4443
      break;
4444
    }
4445
    case (CONNECTION):
2,298✔
4446
      if (getString(&layer->connection) == MS_FAILURE)
2,298✔
4447
        return (-1); /* getString() cleans up previously allocated string */
4448
      break;
4449
    case (CONNECTIONTYPE):
2,346✔
4450
      if ((type = getSymbol(14, MS_OGR, MS_POSTGIS, MS_WMS, MS_ORACLESPATIAL,
2,346✔
4451
                            MS_WFS, MS_GRATICULE, MS_PLUGIN, MS_UNION,
4452
                            MS_UVRASTER, MS_CONTOUR, MS_KERNELDENSITY, MS_IDW,
4453
                            MS_FLATGEOBUF, MS_RASTER_LABEL)) == -1)
4454
        return (-1);
4455
      layer->connectiontype = type;
2,346✔
4456
      break;
2,346✔
4457
    case (DATA):
8,714✔
4458
      if (getString(&layer->data) == MS_FAILURE)
8,714✔
4459
        return (-1); /* getString() cleans up previously allocated string */
4460
      break;
4461
    case (DEBUG):
885✔
4462
      if ((layer->debug = getSymbol(3, MS_ON, MS_OFF, MS_NUMBER)) == -1)
885✔
4463
        return (-1);
4464
      if (layer->debug == MS_NUMBER) {
885✔
4465
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, 0, 5) == MS_FAILURE) {
45✔
4466
          msSetError(MS_MISCERR,
×
4467
                     "Invalid DEBUG level, must be between 0 and 5 (line %d)",
4468
                     "loadLayer()", msyylineno);
4469
          return (-1);
×
4470
        }
4471
        layer->debug = (int)msyynumber;
45✔
4472
      }
4473
      break;
4474
    case (EOF):
×
4475
      msSetError(MS_EOFERR, NULL, "loadLayer()");
×
4476
      return (-1);
×
4477
      break;
4478
    case (ENCODING):
6✔
4479
      if (getString(&layer->encoding) == MS_FAILURE)
6✔
4480
        return (-1);
4481
      break;
4482
    case (END):
12,770✔
4483
      if ((int)layer->type == -1) {
12,770✔
4484
        msSetError(MS_MISCERR, "Layer type not set.", "loadLayer()");
×
4485
        return (-1);
×
4486
      }
4487

4488
      return (0);
4489
      break;
4490
    case (EXTENT): {
476✔
4491
      if (getDouble(&(layer->extent.minx), MS_NUM_CHECK_NONE, -1, -1) == -1)
476✔
4492
        return (-1);
4493
      if (getDouble(&(layer->extent.miny), MS_NUM_CHECK_NONE, -1, -1) == -1)
476✔
4494
        return (-1);
4495
      if (getDouble(&(layer->extent.maxx), MS_NUM_CHECK_NONE, -1, -1) == -1)
476✔
4496
        return (-1);
4497
      if (getDouble(&(layer->extent.maxy), MS_NUM_CHECK_NONE, -1, -1) == -1)
476✔
4498
        return (-1);
4499
      if (!MS_VALID_EXTENT(layer->extent)) {
476✔
4500
        msSetError(MS_MISCERR,
×
4501
                   "Given layer extent is invalid. Check that it is in the "
4502
                   "form: minx, miny, maxx, maxy",
4503
                   "loadLayer()");
4504
        return (-1);
×
4505
      }
4506
      break;
4507
    }
4508
    case (FEATURE):
2,798✔
4509
      if ((int)layer->type == -1) {
2,798✔
4510
        msSetError(MS_MISCERR,
×
4511
                   "Layer type must be set before defining inline features.",
4512
                   "loadLayer()");
4513
        return (-1);
×
4514
      }
4515

4516
      if (layer->type == MS_LAYER_POLYGON)
2,798✔
4517
        type = MS_SHAPE_POLYGON;
4518
      else if (layer->type == MS_LAYER_LINE)
2,686✔
4519
        type = MS_SHAPE_LINE;
4520
      else
4521
        type = MS_SHAPE_POINT;
4522

4523
      layer->connectiontype = MS_INLINE;
2,798✔
4524

4525
      if (loadFeature(layer, type) == MS_FAILURE)
2,798✔
4526
        return (-1);
4527
      break;
4528
    case (FILTER):
472✔
4529
      if (loadExpression(&(layer->filter)) == -1)
472✔
4530
        return (-1); /* loadExpression() cleans up previously allocated
4531
                        expression */
4532
      break;
4533
    case (FILTERITEM):
159✔
4534
      if (getString(&layer->filteritem) == MS_FAILURE)
159✔
4535
        return (-1); /* getString() cleans up previously allocated string */
4536
      break;
4537
    case (FOOTER):
572✔
4538
      if (getString(&layer->footer) == MS_FAILURE)
572✔
4539
        return (-1); /* getString() cleans up previously allocated string */
4540
      break;
4541
    case (GRID):
8✔
4542
      layer->connectiontype = MS_GRATICULE;
8✔
4543
      if (layer->grid) {
8✔
4544
        freeGrid(layer->grid);
×
4545
        msFree(layer->grid);
×
4546
      }
4547
      layer->grid = (void *)malloc(sizeof(graticuleObj));
8✔
4548
      MS_CHECK_ALLOC(layer->grid, sizeof(graticuleObj), -1);
8✔
4549

4550
      initGrid(layer->grid);
8✔
4551
      loadGrid(layer);
8✔
4552
      break;
8✔
4553
    case (GROUP):
177✔
4554
      if (getString(&layer->group) == MS_FAILURE)
177✔
4555
        return (-1); /* getString() cleans up previously allocated string */
4556
      break;
4557
    case (GEOMTRANSFORM): {
43✔
4558
      if (getSymbol(1, MS_EXPRESSION) == -1)
43✔
4559
        return (MS_FAILURE);
4560
      /* handle expression case here for the moment */
4561
      msFree(layer->_geomtransform.string);
43✔
4562
      layer->_geomtransform.string = msStrdup(msyystring_buffer);
43✔
4563
      layer->_geomtransform.type = MS_GEOMTRANSFORM_EXPRESSION;
43✔
4564
    } break;
43✔
4565
    case (HEADER):
604✔
4566
      if (getString(&layer->header) == MS_FAILURE)
604✔
4567
        return (-1); /* getString() cleans up previously allocated string */
4568
      break;
4569
    case (JOIN):
×
4570
      if (layer->numjoins == MS_MAXJOINS) { /* no room */
×
4571
        msSetError(MS_IDENTERR, "Maximum number of joins reached.",
×
4572
                   "loadLayer()");
4573
        return (-1);
×
4574
      }
4575

4576
      if (loadJoin(&(layer->joins[layer->numjoins])) == -1) {
×
4577
        freeJoin(&(layer->joins[layer->numjoins]));
×
4578
        return (-1);
×
4579
      }
4580
      layer->numjoins++;
×
4581
      break;
×
4582
    case (LABELCACHE):
30✔
4583
      if ((layer->labelcache = getSymbol(2, MS_ON, MS_OFF)) == -1)
30✔
4584
        return (-1);
4585
      break;
4586
    case (LABELITEM):
905✔
4587
      if (getString(&layer->labelitem) == MS_FAILURE)
905✔
4588
        return (-1); /* getString() cleans up previously allocated string */
4589
      break;
4590
    case (LABELMAXSCALE):
×
4591
    case (LABELMAXSCALEDENOM):
4592
      if (getDouble(&(layer->labelmaxscaledenom), MS_NUM_CHECK_GTE, 0, -1) ==
×
4593
          -1)
4594
        return (-1);
4595
      break;
4596
    case (LABELMINSCALE):
×
4597
    case (LABELMINSCALEDENOM):
4598
      if (getDouble(&(layer->labelminscaledenom), MS_NUM_CHECK_GTE, 0, -1) ==
×
4599
          -1)
4600
        return (-1);
4601
      break;
4602
    case (LABELREQUIRES):
×
4603
      if (getString(&layer->labelrequires) == MS_FAILURE)
×
4604
        return (-1); /* getString() cleans up previously allocated string */
4605
      break;
4606
    case (LAYER):
4607
      break; /* for string loads */
4608
    case (MASK):
51✔
4609
      if (getString(&layer->mask) == MS_FAILURE)
51✔
4610
        return (-1); /* getString() cleans up previously allocated string */
4611
      break;
4612
    case (MAXFEATURES):
2✔
4613
      if (getInteger(&(layer->maxfeatures), MS_NUM_CHECK_GT, 0, -1) == -1)
2✔
4614
        return (-1);
4615
      break;
4616
    case (MAXSCALE):
3✔
4617
    case (MAXSCALEDENOM):
4618
      if (getDouble(&(layer->maxscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1)
3✔
4619
        return (-1);
4620
      break;
4621
    case (MAXGEOWIDTH):
×
4622
      if (getDouble(&(layer->maxgeowidth), MS_NUM_CHECK_GT, 0, -1) == -1)
×
4623
        return (-1);
4624
      break;
4625
    case (METADATA):
7,022✔
4626
      if (loadHashTable(&(layer->metadata)) != MS_SUCCESS)
7,022✔
4627
        return (-1);
4628
      break;
4629
    case (MINSCALE):
68✔
4630
    case (MINSCALEDENOM):
4631
      if (getDouble(&(layer->minscaledenom), MS_NUM_CHECK_GTE, 0, -1) == -1)
68✔
4632
        return (-1);
4633
      break;
4634
    case (MINGEOWIDTH):
×
4635
      if (getDouble(&(layer->mingeowidth), MS_NUM_CHECK_GT, 0, -1) == -1)
×
4636
        return (-1);
4637
      break;
4638
    case (MINFEATURESIZE):
×
4639
      if (getInteger(&(layer->minfeaturesize), MS_NUM_CHECK_GT, 0, -1) == -1)
×
4640
        return (-1);
4641
      break;
4642
    case (NAME):
12,677✔
4643
      if (getString(&layer->name) == MS_FAILURE)
12,677✔
4644
        return (-1);
4645
      break;
4646
    case (OFFSITE):
34✔
4647
      if (loadColor(&(layer->offsite), NULL) != MS_SUCCESS)
34✔
4648
        return (-1);
4649
      break;
4650

4651
    case (CONNECTIONOPTIONS):
2✔
4652
      if (loadHashTable(&(layer->connectionoptions)) != MS_SUCCESS)
2✔
4653
        return (-1);
4654
      break;
4655
    case (MS_PLUGIN): {
×
4656
      int rv;
4657
      if (map->config) { // value *must* represent a config key
×
4658
        char *value = NULL;
×
4659
        const char *plugin_library = NULL;
4660

4661
        if (getString(&value) == MS_FAILURE)
×
4662
          return (-1);
×
4663
        plugin_library = msConfigGetPlugin(map->config, value);
×
4664
        msFree(value);
×
4665
        if (!plugin_library) {
×
4666
          msSetError(MS_MISCERR,
×
4667
                     "Plugin value not found in config file. See "
4668
                     "mapserver.org/mapfile/config.html for more information.",
4669
                     "loadLayer()");
4670
          return (-1);
×
4671
        }
4672
        msFree(layer->plugin_library_original);
×
4673
        layer->plugin_library_original = strdup(plugin_library);
×
4674
      } else {
4675
        if (getString(&layer->plugin_library_original) == MS_FAILURE)
×
4676
          return (-1);
4677
      }
4678
      rv = msBuildPluginLibraryPath(&layer->plugin_library,
×
4679
                                    layer->plugin_library_original, map);
×
4680
      if (rv == MS_FAILURE)
×
4681
        return (-1);
4682
    } break;
4683
    case (PROCESSING): {
1,282✔
4684
      /* NOTE: processing array maintained as size+1 with NULL terminator.
4685
               This ensure that CSL (GDAL string list) functions can be
4686
               used on the list for easy processing. */
4687
      char *value = NULL;
1,282✔
4688
      if (getString(&value) == MS_FAILURE)
1,282✔
4689
        return (-1);
×
4690
      msLayerAddProcessing(layer, value);
1,282✔
4691
      free(value);
1,282✔
4692
      value = NULL;
4693
    } break;
1,282✔
4694
    case (POSTLABELCACHE):
×
4695
      if ((layer->postlabelcache = getSymbol(2, MS_TRUE, MS_FALSE)) == -1)
×
4696
        return (-1);
4697
      if (layer->postlabelcache)
×
4698
        layer->labelcache = MS_OFF;
×
4699
      break;
4700
    case (PROJECTION):
8,905✔
4701
      if (loadProjection(&(layer->projection)) == -1)
8,905✔
4702
        return (-1);
4703
      layer->project = MS_TRUE;
8,905✔
4704
      break;
8,905✔
4705
    case (REQUIRES):
3✔
4706
      if (getString(&layer->requires) == MS_FAILURE)
3✔
4707
        return (-1); /* getString() cleans up previously allocated string */
4708
      break;
4709
    case (SCALETOKEN):
56✔
4710
      if (msGrowLayerScaletokens(layer) == NULL)
56✔
4711
        return (-1);
4712
      initScaleToken(&layer->scaletokens[layer->numscaletokens]);
56✔
4713
      if (loadScaletoken(&layer->scaletokens[layer->numscaletokens], layer) ==
56✔
4714
          -1) {
4715
        freeScaleToken(&layer->scaletokens[layer->numscaletokens]);
×
4716
        return (-1);
×
4717
      }
4718
      layer->numscaletokens++;
56✔
4719
      break;
56✔
4720
    case (SIZEUNITS):
247✔
4721
      if ((layer->sizeunits = getSymbol(
247✔
4722
               8, MS_INCHES, MS_FEET, MS_MILES, MS_METERS, MS_KILOMETERS,
4723
               MS_NAUTICALMILES, MS_DD, MS_PIXELS)) == -1)
4724
        return (-1);
4725
      break;
4726
    case (STATUS):
10,698✔
4727
      if ((layer->status = getSymbol(3, MS_ON, MS_OFF, MS_DEFAULT)) == -1)
10,698✔
4728
        return (-1);
4729
      break;
4730
    case (STYLEITEM):
129✔
4731
      if (getString(&layer->styleitem) == MS_FAILURE)
129✔
4732
        return (-1); /* getString() cleans up previously allocated string */
4733
      break;
4734
    case (SYMBOLSCALE):
1✔
4735
    case (SYMBOLSCALEDENOM):
4736
      if (getDouble(&(layer->symbolscaledenom), MS_NUM_CHECK_GTE, 1, -1) == -1)
1✔
4737
        return (-1);
4738
      break;
4739
    case (TEMPLATE):
2,076✔
4740
      if (getString(&layer->template) == MS_FAILURE)
2,076✔
4741
        return (-1); /* getString() cleans up previously allocated string */
4742
      break;
4743
    case (TILEINDEX):
297✔
4744
      if (getString(&layer->tileindex) == MS_FAILURE)
297✔
4745
        return (-1); /* getString() cleans up previously allocated string */
4746
      break;
4747
    case (TILEITEM):
297✔
4748
      if (getString(&layer->tileitem) == MS_FAILURE)
297✔
4749
        return (-1); /* getString() cleans up previously allocated string */
4750
      break;
4751
    case (TILESRS):
12✔
4752
      if (getString(&layer->tilesrs) == MS_FAILURE)
12✔
4753
        return (-1); /* getString() cleans up previously allocated string */
4754
      break;
4755
    case (TOLERANCE):
59✔
4756
      if (getDouble(&(layer->tolerance), MS_NUM_CHECK_GTE, 0, -1) == -1)
59✔
4757
        return (-1);
4758
      break;
4759
    case (TOLERANCEUNITS):
37✔
4760
      if ((layer->toleranceunits = getSymbol(
37✔
4761
               8, MS_INCHES, MS_FEET, MS_MILES, MS_METERS, MS_KILOMETERS,
4762
               MS_NAUTICALMILES, MS_DD, MS_PIXELS)) == -1)
4763
        return (-1);
4764
      break;
4765
    case (TRANSFORM):
74✔
4766
      if ((layer->transform =
74✔
4767
               getSymbol(11, MS_TRUE, MS_FALSE, MS_UL, MS_UC, MS_UR, MS_CL,
74✔
4768
                         MS_CC, MS_CR, MS_LL, MS_LC, MS_LR)) == -1)
4769
        return (-1);
4770
      break;
4771
    case (TYPE):
12,774✔
4772
      if ((type =
12,774✔
4773
               getSymbol(9, MS_LAYER_POINT, MS_LAYER_LINE, MS_LAYER_RASTER,
12,774✔
4774
                         MS_LAYER_POLYGON, MS_LAYER_ANNOTATION, MS_LAYER_QUERY,
4775
                         MS_LAYER_CIRCLE, MS_LAYER_CHART, TILEINDEX)) == -1)
4776
        return (-1);
4777
      if (type == TILEINDEX)
12,774✔
4778
        type = MS_LAYER_TILEINDEX; /* TILEINDEX is also a parameter */
4779
      if (type == MS_LAYER_ANNOTATION) {
12,770✔
4780
        msSetError(MS_IDENTERR,
×
4781
                   "Annotation Layers have been removed. To obtain same "
4782
                   "functionality, use a layer with label->styles and no "
4783
                   "class->styles",
4784
                   "loadLayer()");
4785
        return -1;
×
4786
      }
4787
      layer->type = type;
12,774✔
4788
      break;
12,774✔
4789
    case (UNITS):
3✔
4790
      if ((layer->units = getSymbol(9, MS_INCHES, MS_FEET, MS_MILES, MS_METERS,
3✔
4791
                                    MS_KILOMETERS, MS_NAUTICALMILES, MS_DD,
4792
                                    MS_PIXELS, MS_PERCENTAGES)) == -1)
4793
        return (-1);
4794
      break;
4795
    case (UTFDATA):
1✔
4796
      if (loadExpression(&(layer->utfdata)) == -1)
1✔
4797
        return (-1); /* loadExpression() cleans up previously allocated
4798
                        expression */
4799
      break;
4800
    case (UTFITEM):
1✔
4801
      if (getString(&layer->utfitem) == MS_FAILURE)
1✔
4802
        return (-1);
4803
      break;
4804
    case (VALIDATION):
279✔
4805
      if (loadHashTable(&(layer->validation)) != MS_SUCCESS)
279✔
4806
        return (-1);
4807
      break;
4808
    default:
×
4809
      if (strlen(msyystring_buffer) > 0) {
×
4810
        msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
4811
                   "loadLayer()", msyystring_buffer, msyylineno);
4812
        return (-1);
×
4813
      } else {
4814
        return (0); /* end of a string, not an error */
4815
      }
4816
    }
4817
  } /* next token */
4818
}
4819

4820
int msUpdateLayerFromString(layerObj *layer, char *string) {
27✔
4821
  int i;
4822

4823
  if (!layer || !string)
27✔
4824
    return MS_FAILURE;
4825

4826
  msAcquireLock(TLOCK_PARSER);
27✔
4827

4828
  msyystate = MS_TOKENIZE_STRING;
27✔
4829
  msyystring = string;
27✔
4830
  msyylex(); /* sets things up, but doesn't process any tokens */
27✔
4831

4832
  msyylineno = 1; /* start at line 1 */
27✔
4833

4834
  if (loadLayer(layer, layer->map) == -1) {
27✔
4835
    msReleaseLock(TLOCK_PARSER);
×
4836
    return MS_FAILURE; /* parse error */
×
4837
    ;
4838
  }
4839

4840
  msyylex_destroy();
27✔
4841
  msReleaseLock(TLOCK_PARSER);
27✔
4842

4843
  /* step through classes to resolve symbol names */
4844
  for (i = 0; i < layer->numclasses; i++) {
27✔
4845
    if (classResolveSymbolNames(layer->class[i]) != MS_SUCCESS)
×
4846
      return MS_FAILURE;
4847
  }
4848

4849
  return MS_SUCCESS;
4850
}
4851

4852
static void writeCompositingFilter(FILE *stream, int indent,
4853
                                   CompositingFilter *filter) {
4854
  while (filter) {
×
4855
    writeString(stream, indent, "COMPFILTER", "", filter->filter);
×
4856
    filter = filter->next;
×
4857
  }
4858
}
4859

4860
static void writeLayerCompositer(FILE *stream, int indent,
7✔
4861
                                 LayerCompositer *compositor) {
4862
  indent++;
7✔
4863
  while (compositor) {
7✔
4864
    writeBlockBegin(stream, indent, "COMPOSITE");
×
4865
    writeCompositingFilter(stream, indent, compositor->filter);
×
4866
    if (compositor->comp_op != MS_COMPOP_SRC_OVER) {
×
4867

4868
      bool bFound = false;
4869
      for (int i = 0; i < SIZEOF_COMP_OPS; ++i) {
×
4870
        if (compositor->comp_op == CompOps[i].eOp) {
×
4871
          bFound = true;
4872
          writeString(stream, indent, "COMPOP", NULL, CompOps[i].pszName);
×
4873
          break;
×
4874
        }
4875
      }
4876
      if (!bFound) {
4877
        assert(0);
4878
      }
4879
    }
4880
    writeNumber(stream, indent, "OPACITY", 100, compositor->opacity);
×
4881
    writeBlockEnd(stream, indent, "COMPOSITE");
×
4882
    compositor = compositor->next;
×
4883
  }
4884
}
7✔
4885
static void writeLayer(FILE *stream, int indent, layerObj *layer) {
7✔
4886
  int i;
4887
  featureListNodeObjPtr current = NULL;
4888

4889
  if (layer->status == MS_DELETE)
7✔
4890
    return;
4891

4892
  indent++;
7✔
4893
  writeBlockBegin(stream, indent, "LAYER");
7✔
4894
  writeHashTable(stream, indent, "BINDVALS", &(layer->bindvals));
7✔
4895
  /* class - see below */
4896
  writeString(stream, indent, "CLASSGROUP", NULL, layer->classgroup);
7✔
4897
  writeString(stream, indent, "CLASSITEM", NULL, layer->classitem);
7✔
4898
  writeCluster(stream, indent, &(layer->cluster));
7✔
4899
  writeLayerCompositer(stream, indent, layer->compositer);
7✔
4900
  writeString(stream, indent, "CONNECTION", NULL, layer->connection);
7✔
4901
  writeKeyword(stream, indent, "CONNECTIONTYPE", layer->connectiontype, 12,
7✔
4902
               MS_OGR, "OGR", MS_POSTGIS, "POSTGIS", MS_WMS, "WMS",
4903
               MS_ORACLESPATIAL, "ORACLESPATIAL", MS_WFS, "WFS", MS_PLUGIN,
4904
               "PLUGIN", MS_UNION, "UNION", MS_UVRASTER, "UVRASTER", MS_CONTOUR,
4905
               "CONTOUR", MS_KERNELDENSITY, "KERNELDENSITY", MS_IDW, "IDW",
4906
               MS_FLATGEOBUF, "FLATGEOBUF");
4907
  writeHashTable(stream, indent, "CONNECTIONOPTIONS",
7✔
4908
                 &(layer->connectionoptions));
4909
  writeString(stream, indent, "DATA", NULL, layer->data);
7✔
4910
  writeNumber(stream, indent, "DEBUG", 0,
7✔
4911
              layer->debug); /* is this right? see loadLayer() */
7✔
4912
  writeString(stream, indent, "ENCODING", NULL, layer->encoding);
7✔
4913
  writeExtent(stream, indent, "EXTENT", layer->extent);
7✔
4914
  writeExpression(stream, indent, "FILTER", &(layer->filter));
7✔
4915
  writeString(stream, indent, "FILTERITEM", NULL, layer->filteritem);
7✔
4916
  writeString(stream, indent, "FOOTER", NULL, layer->footer);
7✔
4917
  writeString(stream, indent, "GROUP", NULL, layer->group);
7✔
4918

4919
  if (layer->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) {
7✔
4920
    writeIndent(stream, indent + 1);
×
4921
    fprintf(stream, "GEOMTRANSFORM (%s)\n", layer->_geomtransform.string);
×
4922
  }
4923

4924
  writeString(stream, indent, "HEADER", NULL, layer->header);
7✔
4925
  /* join - see below */
4926
  writeKeyword(stream, indent, "LABELCACHE", layer->labelcache, 1, MS_OFF,
7✔
4927
               "OFF");
4928
  writeString(stream, indent, "LABELITEM", NULL, layer->labelitem);
7✔
4929
  writeNumber(stream, indent, "LABELMAXSCALEDENOM", -1,
7✔
4930
              layer->labelmaxscaledenom);
4931
  writeNumber(stream, indent, "LABELMINSCALEDENOM", -1,
7✔
4932
              layer->labelminscaledenom);
4933
  writeString(stream, indent, "LABELREQUIRES", NULL, layer->labelrequires);
7✔
4934
  writeNumber(stream, indent, "MAXFEATURES", -1, layer->maxfeatures);
7✔
4935
  writeNumber(stream, indent, "MAXGEOWIDTH", -1, layer->maxgeowidth);
7✔
4936
  writeNumber(stream, indent, "MAXSCALEDENOM", -1, layer->maxscaledenom);
7✔
4937
  writeString(stream, indent, "MASK", NULL, layer->mask);
7✔
4938
  writeHashTable(stream, indent, "METADATA", &(layer->metadata));
7✔
4939
  writeNumber(stream, indent, "MINGEOWIDTH", -1, layer->mingeowidth);
7✔
4940
  writeNumber(stream, indent, "MINSCALEDENOM", -1, layer->minscaledenom);
7✔
4941
  writeNumber(stream, indent, "MINFEATURESIZE", -1, layer->minfeaturesize);
7✔
4942
  writeString(stream, indent, "NAME", NULL, layer->name);
7✔
4943
  writeColor(stream, indent, "OFFSITE", NULL, &(layer->offsite));
7✔
4944
  writeString(stream, indent, "PLUGIN", NULL, layer->plugin_library_original);
7✔
4945
  writeKeyword(stream, indent, "POSTLABELCACHE", layer->postlabelcache, 1,
7✔
4946
               MS_TRUE, "TRUE");
4947
  for (i = 0; layer->processing && layer->processing[i]; i++)
8✔
4948
    writeString(stream, indent, "PROCESSING", NULL, layer->processing[i]);
1✔
4949
  writeProjection(stream, indent, &(layer->projection));
7✔
4950
  writeString(stream, indent, "REQUIRES", NULL, layer->requires);
7✔
4951
  writeKeyword(stream, indent, "SIZEUNITS", layer->sizeunits, 7, MS_INCHES,
7✔
4952
               "INCHES", MS_FEET, "FEET", MS_MILES, "MILES", MS_METERS,
4953
               "METERS", MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES,
4954
               "NAUTICALMILES", MS_DD, "DD");
4955
  writeKeyword(stream, indent, "STATUS", layer->status, 3, MS_ON, "ON", MS_OFF,
7✔
4956
               "OFF", MS_DEFAULT, "DEFAULT");
4957
  writeString(stream, indent, "STYLEITEM", NULL, layer->styleitem);
7✔
4958
  writeNumber(stream, indent, "SYMBOLSCALEDENOM", -1, layer->symbolscaledenom);
7✔
4959
  writeString(stream, indent, "TEMPLATE", NULL, layer->template);
7✔
4960
  writeString(stream, indent, "TILEINDEX", NULL, layer->tileindex);
7✔
4961
  writeString(stream, indent, "TILEITEM", NULL, layer->tileitem);
7✔
4962
  writeString(stream, indent, "TILESRS", NULL, layer->tilesrs);
7✔
4963
  writeNumber(stream, indent, "TOLERANCE", -1, layer->tolerance);
7✔
4964
  writeKeyword(stream, indent, "TOLERANCEUNITS", layer->toleranceunits, 7,
7✔
4965
               MS_INCHES, "INCHES", MS_FEET, "FEET", MS_MILES, "MILES",
4966
               MS_METERS, "METERS", MS_KILOMETERS, "KILOMETERS",
4967
               MS_NAUTICALMILES, "NAUTICALMILES", MS_DD, "DD");
4968
  writeKeyword(stream, indent, "TRANSFORM", layer->transform, 10, MS_FALSE,
7✔
4969
               "FALSE", MS_UL, "UL", MS_UC, "UC", MS_UR, "UR", MS_CL, "CL",
4970
               MS_CC, "CC", MS_CR, "CR", MS_LL, "LL", MS_LC, "LC", MS_LR, "LR");
4971
  writeKeyword(stream, indent, "TYPE", layer->type, 9, MS_LAYER_POINT, "POINT",
7✔
4972
               MS_LAYER_LINE, "LINE", MS_LAYER_POLYGON, "POLYGON",
4973
               MS_LAYER_RASTER, "RASTER", MS_LAYER_ANNOTATION, "ANNOTATION",
4974
               MS_LAYER_QUERY, "QUERY", MS_LAYER_CIRCLE, "CIRCLE",
4975
               MS_LAYER_TILEINDEX, "TILEINDEX", MS_LAYER_CHART, "CHART");
4976
  writeKeyword(stream, indent, "UNITS", layer->units, 9, MS_INCHES, "INCHES",
7✔
4977
               MS_FEET, "FEET", MS_MILES, "MILES", MS_METERS, "METERS",
4978
               MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES, "NAUTICALMILES",
4979
               MS_DD, "DD", MS_PIXELS, "PIXELS", MS_PERCENTAGES,
4980
               "PERCENTATGES");
4981
  writeExpression(stream, indent, "UTFDATA", &(layer->utfdata));
7✔
4982
  writeString(stream, indent, "UTFITEM", NULL, layer->utfitem);
7✔
4983
  writeHashTable(stream, indent, "VALIDATION", &(layer->validation));
7✔
4984

4985
  /* write potentially multiply occurring objects last */
4986
  for (i = 0; i < layer->numscaletokens; i++)
7✔
4987
    writeScaleToken(stream, indent, &(layer->scaletokens[i]));
×
4988
  for (i = 0; i < layer->numjoins; i++)
7✔
4989
    writeJoin(stream, indent, &(layer->joins[i]));
×
4990
  for (i = 0; i < layer->numclasses; i++)
16✔
4991
    writeClass(stream, indent, layer->class[i]);
9✔
4992

4993
  if (layer->grid && layer->connectiontype == MS_GRATICULE)
7✔
4994
    writeGrid(stream, indent, layer->grid);
×
4995
  else {
4996
    current = layer->features;
7✔
4997
    while (current != NULL) {
10✔
4998
      writeFeature(stream, indent, &(current->shape));
3✔
4999
      current = current->next;
3✔
5000
    }
5001
  }
5002

5003
  writeBlockEnd(stream, indent, "LAYER");
7✔
5004
  writeLineFeed(stream);
5005
}
5006

5007
char *msWriteLayerToString(layerObj *layer) {
×
5008
  msIOContext context;
5009
  msIOBuffer buffer;
5010

5011
  context.label = NULL;
×
5012
  context.write_channel = MS_TRUE;
×
5013
  context.readWriteFunc = msIO_bufferWrite;
×
5014
  context.cbData = &buffer;
×
5015
  buffer.data = NULL;
×
5016
  buffer.data_len = 0;
×
5017
  buffer.data_offset = 0;
×
5018

5019
  msIO_installHandlers(NULL, &context, NULL);
×
5020

5021
  writeLayer(stdout, -1, layer);
×
5022
  msIO_bufferWrite(&buffer, "", 1);
×
5023

5024
  msIO_installHandlers(NULL, NULL, NULL);
×
5025

5026
  return (char *)buffer.data;
×
5027
}
5028

5029
/*
5030
** Initialize, load and free a referenceMapObj structure
5031
*/
5032
void initReferenceMap(referenceMapObj *ref) {
3,147✔
5033
  ref->height = ref->width = 0;
3,147✔
5034
  ref->extent.minx = ref->extent.miny = ref->extent.maxx = ref->extent.maxy =
3,147✔
5035
      -1.0;
5036
  ref->image = NULL;
3,147✔
5037
  MS_INIT_COLOR(ref->color, 255, 0, 0, 255);
3,147✔
5038
  MS_INIT_COLOR(ref->outlinecolor, 0, 0, 0, 255);
3,147✔
5039
  ref->status = MS_OFF;
3,147✔
5040
  ref->marker = 0;
3,147✔
5041
  ref->markername = NULL;
3,147✔
5042
  ref->markersize = 0;
3,147✔
5043
  ref->minboxsize = 3;
3,147✔
5044
  ref->maxboxsize = 0;
3,147✔
5045
  ref->map = NULL;
3,147✔
5046
}
3,147✔
5047

5048
void freeReferenceMap(referenceMapObj *ref) {
3,099✔
5049
  msFree(ref->image);
3,099✔
5050
  msFree(ref->markername);
3,099✔
5051
}
3,099✔
5052

5053
int loadReferenceMap(referenceMapObj *ref, mapObj *map) {
×
5054
  int state;
5055

5056
  ref->map = (mapObj *)map;
×
5057

5058
  for (;;) {
5059
    switch (msyylex()) {
×
5060
    case (EOF):
×
5061
      msSetError(MS_EOFERR, NULL, "loadReferenceMap()");
×
5062
      return (-1);
×
5063
    case (END):
×
5064
      if (!ref->image) {
×
5065
        msSetError(MS_MISCERR, "No image defined for the reference map.",
×
5066
                   "loadReferenceMap()");
5067
        return (-1);
×
5068
      }
5069
      if (ref->width == 0 || ref->height == 0) {
×
5070
        msSetError(MS_MISCERR, "No image size defined for the reference map.",
×
5071
                   "loadReferenceMap()");
5072
        return (-1);
×
5073
      }
5074
      return (0);
5075
      break;
5076
    case (COLOR):
×
5077
      if (loadColor(&(ref->color), NULL) != MS_SUCCESS)
×
5078
        return (-1);
5079
      break;
5080
    case (EXTENT):
×
5081
      if (getDouble(&(ref->extent.minx), MS_NUM_CHECK_NONE, -1, -1) == -1)
×
5082
        return (-1);
5083
      if (getDouble(&(ref->extent.miny), MS_NUM_CHECK_NONE, -1, -1) == -1)
×
5084
        return (-1);
5085
      if (getDouble(&(ref->extent.maxx), MS_NUM_CHECK_NONE, -1, -1) == -1)
×
5086
        return (-1);
5087
      if (getDouble(&(ref->extent.maxy), MS_NUM_CHECK_NONE, -1, -1) == -1)
×
5088
        return (-1);
5089
      if (!MS_VALID_EXTENT(ref->extent)) {
×
5090
        msSetError(MS_MISCERR,
×
5091
                   "Given reference extent is invalid. Check that it "
5092
                   "is in the form: minx, miny, maxx, maxy",
5093
                   "loadReferenceMap()");
5094
        return (-1);
×
5095
      }
5096
      break;
5097
    case (IMAGE):
×
5098
      if (getString(&ref->image) == MS_FAILURE)
×
5099
        return (-1);
5100
      break;
5101
    case (OUTLINECOLOR):
×
5102
      if (loadColor(&(ref->outlinecolor), NULL) != MS_SUCCESS)
×
5103
        return (-1);
5104
      break;
5105
    case (SIZE):
×
5106
      if (getInteger(&(ref->width), MS_NUM_CHECK_RANGE, 5, ref->map->maxsize) ==
×
5107
          -1)
5108
        return (-1); // is 5 reasonable?
5109
      if (getInteger(&(ref->height), MS_NUM_CHECK_RANGE, 5,
×
5110
                     ref->map->maxsize) == -1)
×
5111
        return (-1);
5112
      break;
5113
    case (STATUS):
×
5114
      if ((ref->status = getSymbol(2, MS_ON, MS_OFF)) == -1)
×
5115
        return (-1);
5116
      break;
5117
    case (MARKER):
×
5118
      if ((state = getSymbol(2, MS_NUMBER, MS_STRING)) == -1)
×
5119
        return (-1);
5120

5121
      if (state == MS_NUMBER) {
×
5122
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_GTE, 0, -1) == MS_FAILURE) {
×
5123
          msSetError(MS_MISCERR,
×
5124
                     "Invalid MARKER, must be greater than 0 (line %d)",
5125
                     "loadReferenceMap()", msyylineno);
5126
          return (-1);
×
5127
        }
5128
        ref->marker = (int)msyynumber;
×
5129
      } else {
5130
        if (ref->markername != NULL)
×
5131
          msFree(ref->markername);
×
5132
        ref->markername = msStrdup(msyystring_buffer);
×
5133
      }
5134
      break;
5135
    case (MARKERSIZE):
×
5136
      if (getInteger(&(ref->markersize), MS_NUM_CHECK_GT, 0, -1) == -1)
×
5137
        return (-1);
5138
      break;
5139
    case (MINBOXSIZE):
×
5140
      if (getInteger(&(ref->minboxsize), MS_NUM_CHECK_GT, 0, -1) == -1)
×
5141
        return (-1);
5142
      break;
5143
    case (MAXBOXSIZE):
×
5144
      if (getInteger(&(ref->maxboxsize), MS_NUM_CHECK_GT, 0, -1) == -1)
×
5145
        return (-1);
5146
      break;
5147
    case (REFERENCE):
5148
      break; /* for string loads */
5149
    default:
×
5150
      if (strlen(msyystring_buffer) > 0) {
×
5151
        msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
5152
                   "loadReferenceMap()", msyystring_buffer, msyylineno);
5153
        return (-1);
×
5154
      } else {
5155
        return (0); /* end of a string, not an error */
5156
      }
5157
    }
5158
  } /* next token */
5159
}
5160

5161
int msUpdateReferenceMapFromString(referenceMapObj *ref, char *string) {
×
5162
  if (!ref || !string)
×
5163
    return MS_FAILURE;
5164

5165
  msAcquireLock(TLOCK_PARSER);
×
5166

5167
  msyystate = MS_TOKENIZE_STRING;
×
5168
  msyystring = string;
×
5169
  msyylex(); /* sets things up, but doesn't process any tokens */
×
5170

5171
  msyylineno = 1; /* start at line 1 */
×
5172

5173
  if (loadReferenceMap(ref, ref->map) == -1) {
×
5174
    msReleaseLock(TLOCK_PARSER);
×
5175
    return MS_FAILURE; /* parse error */
×
5176
    ;
5177
  }
5178

5179
  msyylex_destroy();
×
5180
  msReleaseLock(TLOCK_PARSER);
×
5181
  return MS_SUCCESS;
×
5182
}
5183

5184
static void writeReferenceMap(FILE *stream, int indent, referenceMapObj *ref) {
1✔
5185
  colorObj c;
5186

5187
  if (!ref->image)
1✔
5188
    return;
1✔
5189

5190
  indent++;
×
5191
  writeBlockBegin(stream, indent, "REFERENCE");
×
5192
  MS_INIT_COLOR(c, 255, 0, 0, 255);
×
5193
  writeColor(stream, indent, "COLOR", &c, &(ref->color));
×
5194
  writeExtent(stream, indent, "EXTENT", ref->extent);
×
5195
  writeString(stream, indent, "IMAGE", NULL, ref->image);
×
5196
  MS_INIT_COLOR(c, 0, 0, 0, 255);
×
5197
  writeColor(stream, indent, "OUTLINECOLOR", &c, &(ref->outlinecolor));
×
5198
  writeDimension(stream, indent, "SIZE", ref->width, ref->height, NULL, NULL);
×
5199
  writeKeyword(stream, indent, "STATUS", ref->status, 2, MS_ON, "ON", MS_OFF,
×
5200
               "OFF");
5201
  writeNumberOrString(stream, indent, "MARKER", 0, ref->marker,
×
5202
                      ref->markername);
5203
  writeNumber(stream, indent, "MARKERSIZE", -1, ref->markersize);
×
5204
  writeNumber(stream, indent, "MAXBOXSIZE", -1, ref->maxboxsize);
×
5205
  writeNumber(stream, indent, "MINBOXSIZE", -1, ref->minboxsize);
×
5206
  writeBlockEnd(stream, indent, "REFERENCE");
×
5207
  writeLineFeed(stream);
5208
}
5209

5210
char *msWriteReferenceMapToString(referenceMapObj *ref) {
×
5211
  msIOContext context;
5212
  msIOBuffer buffer;
5213

5214
  context.label = NULL;
×
5215
  context.write_channel = MS_TRUE;
×
5216
  context.readWriteFunc = msIO_bufferWrite;
×
5217
  context.cbData = &buffer;
×
5218
  buffer.data = NULL;
×
5219
  buffer.data_len = 0;
×
5220
  buffer.data_offset = 0;
×
5221

5222
  msIO_installHandlers(NULL, &context, NULL);
×
5223

5224
  writeReferenceMap(stdout, -1, ref);
×
5225
  msIO_bufferWrite(&buffer, "", 1);
×
5226

5227
  msIO_installHandlers(NULL, NULL, NULL);
×
5228

5229
  return (char *)buffer.data;
×
5230
}
5231

5232
#define MAX_FORMATOPTIONS 100
5233

5234
static int loadOutputFormat(mapObj *map) {
1,309✔
5235
  char *name = NULL;
5236
  char *mimetype = NULL;
1,309✔
5237
  char *driver = NULL;
5238
  char *extension = NULL;
1,309✔
5239
  int imagemode = MS_NOOVERRIDE;
5240
  int transparent = MS_NOOVERRIDE;
5241
  char *formatoptions[MAX_FORMATOPTIONS];
5242
  int numformatoptions = 0;
5243
  char *value = NULL;
1,309✔
5244

5245
  for (;;) {
5246
    switch (msyylex()) {
8,176✔
5247
    case (EOF):
×
5248
      msSetError(MS_EOFERR, NULL, "loadOutputFormat()");
×
5249
      goto load_output_error;
×
5250

5251
    case (END): {
1,309✔
5252
      outputFormatObj *format;
5253

5254
      if (driver == NULL) {
1,309✔
5255
        msSetError(MS_MISCERR,
×
5256
                   "OUTPUTFORMAT clause lacks DRIVER keyword near (%s):(%d)",
5257
                   "loadOutputFormat()", msyystring_buffer, msyylineno);
5258
        goto load_output_error;
×
5259
      }
5260

5261
      format = msCreateDefaultOutputFormat(map, driver, name, NULL);
1,309✔
5262
      if (format == NULL) {
1,309✔
5263
        msSetError(MS_MISCERR,
2✔
5264
                   "OUTPUTFORMAT (%s) clause references driver (%s), but this "
5265
                   "driver isn't configured.",
5266
                   "loadOutputFormat()", name, driver);
5267
        goto load_output_error;
2✔
5268
      }
5269
      msFree(name);
1,307✔
5270
      name = NULL;
5271
      msFree(driver);
1,307✔
5272
      driver = NULL;
5273

5274
      if (transparent != MS_NOOVERRIDE)
1,307✔
5275
        format->transparent = transparent;
122✔
5276
      if (extension != NULL) {
1,307✔
5277
        msFree(format->extension);
703✔
5278
        format->extension = extension;
703✔
5279
        extension = NULL;
703✔
5280
      }
5281
      if (mimetype != NULL) {
1,307✔
5282
        msFree(format->mimetype);
1,073✔
5283
        format->mimetype = mimetype;
1,073✔
5284
        mimetype = NULL;
1,073✔
5285
      }
5286
      if (imagemode != MS_NOOVERRIDE) {
1,307✔
5287
        if (format->renderer != MS_RENDER_WITH_AGG ||
752✔
5288
            imagemode != MS_IMAGEMODE_PC256) {
5289
          /* don't force to PC256 with agg, this can happen when using mapfile
5290
           * defined GD outputformats that are now falling back to agg/png8
5291
           */
5292
          format->imagemode = imagemode;
743✔
5293
        }
5294

5295
        if (transparent == MS_NOOVERRIDE) {
752✔
5296
          if (imagemode == MS_IMAGEMODE_RGB)
674✔
5297
            format->transparent = MS_FALSE;
56✔
5298
          else if (imagemode == MS_IMAGEMODE_RGBA)
618✔
5299
            format->transparent = MS_TRUE;
24✔
5300
        }
5301
        if (format->imagemode == MS_IMAGEMODE_INT16 ||
752✔
5302
            format->imagemode == MS_IMAGEMODE_FLOAT32 ||
752✔
5303
            format->imagemode == MS_IMAGEMODE_BYTE)
5304
          format->renderer = MS_RENDER_WITH_RAWDATA;
585✔
5305
      }
5306
      while (numformatoptions--) {
2,932✔
5307
        char *key = strchr(formatoptions[numformatoptions], '=');
1,625✔
5308
        if (!key || !*(key + 1)) {
1,625✔
5309
          msSetError(
×
5310
              MS_MISCERR,
5311
              "Failed to parse FORMATOPTION, expecting \"KEY=VALUE\" syntax.",
5312
              "loadOutputFormat()");
5313
          goto load_output_error;
×
5314
        }
5315
        *key = 0;
1,625✔
5316
        key++;
1,625✔
5317
        msSetOutputFormatOption(format, formatoptions[numformatoptions], key);
1,625✔
5318
        free(formatoptions[numformatoptions]);
1,625✔
5319
      }
5320

5321
      format->inmapfile = MS_TRUE;
1,307✔
5322

5323
      msOutputFormatValidate(format, MS_FALSE);
1,307✔
5324
      return (0);
1,307✔
5325
    }
5326
    case (NAME):
1,281✔
5327
      msFree(name);
1,281✔
5328
      if ((name = getToken()) == NULL)
1,281✔
5329
        goto load_output_error;
×
5330
      break;
5331
    case (MIMETYPE):
1,075✔
5332
      if (getString(&mimetype) == MS_FAILURE)
1,075✔
5333
        goto load_output_error;
×
5334
      break;
5335
    case (DRIVER): {
1,309✔
5336
      int s;
5337
      if ((s = getSymbol(2, MS_STRING, TEMPLATE)) ==
1,309✔
5338
          -1) /* allow the template to be quoted or not in the mapfile */
5339
        goto load_output_error;
×
5340
      free(driver);
1,309✔
5341
      if (s == MS_STRING)
1,309✔
5342
        driver = msStrdup(msyystring_buffer);
1,309✔
5343
      else
5344
        driver = msStrdup("TEMPLATE");
×
5345
    } break;
5346
    case (EXTENSION):
703✔
5347
      if (getString(&extension) == MS_FAILURE)
703✔
5348
        goto load_output_error;
×
5349
      if (extension[0] == '.') {
703✔
5350
        char *temp = msStrdup(extension + 1);
×
5351
        free(extension);
×
5352
        extension = temp;
×
5353
      }
5354
      break;
5355
    case (FORMATOPTION):
1,625✔
5356
      if (getString(&value) == MS_FAILURE)
1,625✔
5357
        goto load_output_error;
×
5358
      if (numformatoptions < MAX_FORMATOPTIONS)
1,625✔
5359
        formatoptions[numformatoptions++] = value;
1,625✔
5360
      value = NULL;
1,625✔
5361
      break;
1,625✔
5362
    case (IMAGEMODE):
5363
      value = getToken();
752✔
5364
      if (strcasecmp(value, "PC256") == 0)
752✔
5365
        imagemode = MS_IMAGEMODE_PC256;
5366
      else if (strcasecmp(value, "RGB") == 0)
743✔
5367
        imagemode = MS_IMAGEMODE_RGB;
5368
      else if (strcasecmp(value, "RGBA") == 0)
640✔
5369
        imagemode = MS_IMAGEMODE_RGBA;
5370
      else if (strcasecmp(value, "INT16") == 0)
585✔
5371
        imagemode = MS_IMAGEMODE_INT16;
5372
      else if (strcasecmp(value, "FLOAT32") == 0)
327✔
5373
        imagemode = MS_IMAGEMODE_FLOAT32;
5374
      else if (strcasecmp(value, "BYTE") == 0)
306✔
5375
        imagemode = MS_IMAGEMODE_BYTE;
5376
      else if (strcasecmp(value, "FEATURE") == 0)
×
5377
        imagemode = MS_IMAGEMODE_FEATURE;
5378
      else {
5379
        msSetError(MS_IDENTERR,
×
5380
                   "Parsing error near (%s):(line %d), expected PC256, RGB, "
5381
                   "RGBA, FEATURE, BYTE, INT16, or FLOAT32 for IMAGEMODE.",
5382
                   "loadOutputFormat()", msyystring_buffer, msyylineno);
5383
        goto load_output_error;
×
5384
      }
5385
      free(value);
752✔
5386
      value = NULL;
752✔
5387
      break;
752✔
5388
    case (TRANSPARENT):
122✔
5389
      if ((transparent = getSymbol(2, MS_ON, MS_OFF)) == -1)
122✔
5390
        goto load_output_error;
×
5391
      break;
5392
    default:
×
5393
      msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
5394
                 "loadOutputFormat()", msyystring_buffer, msyylineno);
5395
      goto load_output_error;
×
5396
    }
5397
  } /* next token */
5398
load_output_error:
2✔
5399
  msFree(driver);
2✔
5400
  msFree(extension);
2✔
5401
  msFree(mimetype);
2✔
5402
  msFree(name);
2✔
5403
  msFree(value);
2✔
5404
  return -1;
2✔
5405
}
5406

5407
/*
5408
** utility function to write an output format structure to file
5409
*/
5410
static void writeOutputformatobject(FILE *stream, int indent,
1✔
5411
                                    outputFormatObj *outputformat) {
5412
  int i = 0;
5413
  if (!outputformat)
1✔
5414
    return;
5415

5416
  indent++;
1✔
5417
  writeBlockBegin(stream, indent, "OUTPUTFORMAT");
1✔
5418
  writeString(stream, indent, "NAME", NULL, outputformat->name);
1✔
5419
  writeString(stream, indent, "MIMETYPE", NULL, outputformat->mimetype);
1✔
5420
  writeString(stream, indent, "DRIVER", NULL, outputformat->driver);
1✔
5421
  writeString(stream, indent, "EXTENSION", NULL, outputformat->extension);
1✔
5422
  writeKeyword(stream, indent, "IMAGEMODE", outputformat->imagemode, 7,
1✔
5423
               MS_IMAGEMODE_PC256, "PC256", MS_IMAGEMODE_RGB, "RGB",
5424
               MS_IMAGEMODE_RGBA, "RGBA", MS_IMAGEMODE_INT16, "INT16",
5425
               MS_IMAGEMODE_FLOAT32, "FLOAT32", MS_IMAGEMODE_BYTE, "BYTE",
5426
               MS_IMAGEMODE_FEATURE, "FEATURE");
5427
  writeKeyword(stream, indent, "TRANSPARENT", outputformat->transparent, 2,
1✔
5428
               MS_TRUE, "TRUE", MS_FALSE, "FALSE");
5429
  for (i = 0; i < outputformat->numformatoptions; i++)
1✔
5430
    writeString(stream, indent, "FORMATOPTION", NULL,
×
5431
                outputformat->formatoptions[i]);
×
5432
  writeBlockEnd(stream, indent, "OUTPUTFORMAT");
1✔
5433
  writeLineFeed(stream);
5434
}
5435

5436
/*
5437
** Write the output formats to file
5438
*/
5439
static void writeOutputformat(FILE *stream, int indent, mapObj *map) {
1✔
5440
  int i = 0;
5441
  if (!map->outputformat)
1✔
5442
    return;
5443

5444
  writeOutputformatobject(stream, indent, map->outputformat);
1✔
5445
  for (i = 0; i < map->numoutputformats; i++) {
3✔
5446
    if (map->outputformatlist[i]->inmapfile == MS_TRUE &&
2✔
5447
        strcmp(map->outputformatlist[i]->name, map->outputformat->name) != 0)
1✔
5448
      writeOutputformatobject(stream, indent, map->outputformatlist[i]);
×
5449
  }
5450
}
5451

5452
/*
5453
** Initialize, load and free a legendObj structure
5454
*/
5455
void initLegend(legendObj *legend) {
3,108✔
5456
  legend->height = legend->width = 0;
3,108✔
5457
  MS_INIT_COLOR(legend->imagecolor, 255, 255, 255, 255); /* white */
3,108✔
5458
  MS_INIT_COLOR(legend->outlinecolor, -1, -1, -1, 255);
3,108✔
5459
  initLabel(&legend->label);
3,108✔
5460
  legend->label.position = MS_XY; /* override */
3,108✔
5461
  legend->keysizex = 20;
3,108✔
5462
  legend->keysizey = 10;
3,108✔
5463
  legend->keyspacingx = 5;
3,108✔
5464
  legend->keyspacingy = 5;
3,108✔
5465
  legend->status = MS_OFF;
3,108✔
5466
  legend->transparent = MS_NOOVERRIDE;
3,108✔
5467
  legend->position = MS_LL;
3,108✔
5468
  legend->postlabelcache = MS_FALSE; /* draw with labels */
3,108✔
5469
  legend->template = NULL;
3,108✔
5470
  legend->map = NULL;
3,108✔
5471
}
3,108✔
5472

5473
void freeLegend(legendObj *legend) {
3,099✔
5474
  if (legend->template)
3,099✔
5475
    free(legend->template);
1✔
5476
  freeLabel(&(legend->label));
3,099✔
5477
}
3,099✔
5478

5479
int loadLegend(legendObj *legend, mapObj *map) {
479✔
5480
  legend->map = (mapObj *)map;
479✔
5481

5482
  for (;;) {
5483
    switch (msyylex()) {
1,035✔
5484
    case (EOF):
×
5485
      msSetError(MS_EOFERR, NULL, "loadLegend()");
×
5486
      return (-1);
×
5487
    case (END):
479✔
5488
      legend->label.position = MS_XY; /* overrides go here */
479✔
5489
      return (0);
479✔
5490
      break;
5491
    case (IMAGECOLOR):
423✔
5492
      if (loadColor(&(legend->imagecolor), NULL) != MS_SUCCESS)
423✔
5493
        return (-1);
5494
      break;
5495
    case (KEYSIZE):
4✔
5496
      if (getInteger(&(legend->keysizex), MS_NUM_CHECK_RANGE,
4✔
5497
                     MS_LEGEND_KEYSIZE_MIN, MS_LEGEND_KEYSIZE_MAX) == -1)
5498
        return (-1);
5499
      if (getInteger(&(legend->keysizey), MS_NUM_CHECK_RANGE,
4✔
5500
                     MS_LEGEND_KEYSIZE_MIN, MS_LEGEND_KEYSIZE_MAX) == -1)
5501
        return (-1);
5502
      break;
5503
    case (KEYSPACING):
4✔
5504
      if (getInteger(&(legend->keyspacingx), MS_NUM_CHECK_RANGE,
4✔
5505
                     MS_LEGEND_KEYSPACING_MIN, MS_LEGEND_KEYSPACING_MAX) == -1)
5506
        return (-1);
5507
      if (getInteger(&(legend->keyspacingy), MS_NUM_CHECK_RANGE,
4✔
5508
                     MS_LEGEND_KEYSPACING_MIN, MS_LEGEND_KEYSPACING_MAX) == -1)
5509
        return (-1);
5510
      break;
5511
    case (LABEL):
77✔
5512
      if (loadLabel(&(legend->label)) == -1)
77✔
5513
        return (-1);
5514
      legend->label.angle = 0; /* force */
77✔
5515
      break;
77✔
5516
    case (LEGEND):
5517
      break; /* for string loads */
5518
    case (OUTLINECOLOR):
×
5519
      if (loadColor(&(legend->outlinecolor), NULL) != MS_SUCCESS)
×
5520
        return (-1);
5521
      break;
5522
    case (POSITION):
16✔
5523
      if ((legend->position =
16✔
5524
               getSymbol(6, MS_UL, MS_UR, MS_LL, MS_LR, MS_UC, MS_LC)) == -1)
16✔
5525
        return (-1);
5526
      break;
5527
    case (POSTLABELCACHE):
8✔
5528
      if ((legend->postlabelcache = getSymbol(2, MS_TRUE, MS_FALSE)) == -1)
8✔
5529
        return (-1);
5530
      break;
5531
    case (STATUS):
16✔
5532
      if ((legend->status = getSymbol(3, MS_ON, MS_OFF, MS_EMBED)) == -1)
16✔
5533
        return (-1);
5534
      break;
5535
    case (TRANSPARENT):
8✔
5536
      if ((legend->transparent = getSymbol(2, MS_ON, MS_OFF)) == -1)
8✔
5537
        return (-1);
5538
      break;
5539
    case (TEMPLATE):
×
5540
      if (getString(&legend->template) == MS_FAILURE)
×
5541
        return (-1);
5542
      break;
5543
    default:
×
5544
      if (strlen(msyystring_buffer) > 0) {
×
5545
        msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
5546
                   "loadLegend()", msyystring_buffer, msyylineno);
5547
        return (-1);
×
5548
      } else {
5549
        return (0); /* end of a string, not an error */
5550
      }
5551
    }
5552
  } /* next token */
5553
}
5554

5555
int msUpdateLegendFromString(legendObj *legend, char *string) {
×
5556
  if (!legend || !string)
×
5557
    return MS_FAILURE;
5558

5559
  msAcquireLock(TLOCK_PARSER);
×
5560

5561
  msyystate = MS_TOKENIZE_STRING;
×
5562
  msyystring = string;
×
5563
  msyylex(); /* sets things up, but doesn't process any tokens */
×
5564

5565
  msyylineno = 1; /* start at line 1 */
×
5566

5567
  if (loadLegend(legend, legend->map) == -1) {
×
5568
    msReleaseLock(TLOCK_PARSER);
×
5569
    return MS_FAILURE; /* parse error */
×
5570
    ;
5571
  }
5572

5573
  msyylex_destroy();
×
5574
  msReleaseLock(TLOCK_PARSER);
×
5575
  return MS_SUCCESS;
×
5576
}
5577

5578
static void writeLegend(FILE *stream, int indent, legendObj *legend) {
1✔
5579
  colorObj c;
5580

5581
  indent++;
1✔
5582
  writeBlockBegin(stream, indent, "LEGEND");
1✔
5583
  MS_INIT_COLOR(c, 255, 255, 255, 255);
1✔
5584
  writeColor(stream, indent, "IMAGECOLOR", &c, &(legend->imagecolor));
1✔
5585
  writeDimension(stream, indent, "KEYSIZE", legend->keysizex, legend->keysizey,
1✔
5586
                 NULL, NULL);
5587
  writeDimension(stream, indent, "KEYSPACING", legend->keyspacingx,
1✔
5588
                 legend->keyspacingy, NULL, NULL);
1✔
5589
  writeLabel(stream, indent, &(legend->label));
1✔
5590
  writeColor(stream, indent, "OUTLINECOLOR", NULL, &(legend->outlinecolor));
1✔
5591
  if (legend->status == MS_EMBED)
1✔
5592
    writeKeyword(stream, indent, "POSITION", legend->position, 6, MS_LL, "LL",
×
5593
                 MS_UL, "UL", MS_UR, "UR", MS_LR, "LR", MS_UC, "UC", MS_LC,
5594
                 "LC");
5595
  writeKeyword(stream, indent, "POSTLABELCACHE", legend->postlabelcache, 1,
1✔
5596
               MS_TRUE, "TRUE");
5597
  writeKeyword(stream, indent, "STATUS", legend->status, 3, MS_ON, "ON", MS_OFF,
1✔
5598
               "OFF", MS_EMBED, "EMBED");
5599
  writeKeyword(stream, indent, "TRANSPARENT", legend->transparent, 2, MS_TRUE,
1✔
5600
               "TRUE", MS_FALSE, "FALSE");
5601
  writeString(stream, indent, "TEMPLATE", NULL, legend->template);
1✔
5602
  writeBlockEnd(stream, indent, "LEGEND");
1✔
5603
  writeLineFeed(stream);
5604
}
1✔
5605

5606
char *msWriteLegendToString(legendObj *legend) {
×
5607
  msIOContext context;
5608
  msIOBuffer buffer;
5609

5610
  context.label = NULL;
×
5611
  context.write_channel = MS_TRUE;
×
5612
  context.readWriteFunc = msIO_bufferWrite;
×
5613
  context.cbData = &buffer;
×
5614
  buffer.data = NULL;
×
5615
  buffer.data_len = 0;
×
5616
  buffer.data_offset = 0;
×
5617

5618
  msIO_installHandlers(NULL, &context, NULL);
×
5619

5620
  writeLegend(stdout, -1, legend);
×
5621
  msIO_bufferWrite(&buffer, "", 1);
×
5622

5623
  msIO_installHandlers(NULL, NULL, NULL);
×
5624

5625
  return (char *)buffer.data;
×
5626
}
5627

5628
/*
5629
** Initialize, load and free a scalebarObj structure
5630
*/
5631
void initScalebar(scalebarObj *scalebar) {
3,147✔
5632
  MS_INIT_COLOR(scalebar->imagecolor, -1, -1, -1, 255);
3,147✔
5633
  scalebar->width = 200;
3,147✔
5634
  scalebar->height = 3;
3,147✔
5635
  scalebar->style = 0; /* only 2 styles at this point */
3,147✔
5636
  scalebar->intervals = 4;
3,147✔
5637
  initLabel(&scalebar->label);
3,147✔
5638
  scalebar->label.position = MS_XY; /* override */
3,147✔
5639
  MS_INIT_COLOR(scalebar->backgroundcolor, -1, -1, -1,
3,147✔
5640
                255); /* if not set, scalebar creation needs to set this to
5641
                         match the background color */
5642
  MS_INIT_COLOR(scalebar->color, 0, 0, 0, 255); /* default to black */
3,147✔
5643
  MS_INIT_COLOR(scalebar->outlinecolor, -1, -1, -1, 255);
3,147✔
5644
  scalebar->units = MS_MILES;
3,147✔
5645
  scalebar->status = MS_OFF;
3,147✔
5646
  scalebar->position = MS_LL;
3,147✔
5647
  scalebar->transparent = MS_NOOVERRIDE; /* no transparency */
3,147✔
5648
  scalebar->postlabelcache = MS_FALSE;   /* draw with labels */
3,147✔
5649
  scalebar->align = MS_ALIGN_CENTER;
3,147✔
5650
  scalebar->offsetx = 0;
3,147✔
5651
  scalebar->offsety = 0;
3,147✔
5652
}
3,147✔
5653

5654
void freeScalebar(scalebarObj *scalebar) { freeLabel(&(scalebar->label)); }
3,099✔
5655

5656
int loadScalebar(scalebarObj *scalebar) {
414✔
5657
  for (;;) {
5658
    switch (msyylex()) {
4,934✔
5659
    case (ALIGN):
×
5660
      if ((scalebar->align = getSymbol(3, MS_ALIGN_LEFT, MS_ALIGN_CENTER,
×
5661
                                       MS_ALIGN_RIGHT)) == -1)
5662
        return (-1);
5663
      break;
5664
    case (BACKGROUNDCOLOR):
412✔
5665
      if (loadColor(&(scalebar->backgroundcolor), NULL) != MS_SUCCESS)
412✔
5666
        return (-1);
5667
      break;
5668
    case (COLOR):
412✔
5669
      if (loadColor(&(scalebar->color), NULL) != MS_SUCCESS)
412✔
5670
        return (-1);
5671
      break;
5672
    case (EOF):
×
5673
      msSetError(MS_EOFERR, NULL, "loadScalebar()");
×
5674
      return (-1);
×
5675
    case (END):
5676
      return (0);
5677
      break;
5678
    case (IMAGECOLOR):
402✔
5679
      if (loadColor(&(scalebar->imagecolor), NULL) != MS_SUCCESS)
402✔
5680
        return (-1);
5681
      break;
5682
    case (INTERVALS):
10✔
5683
      if (getInteger(&(scalebar->intervals), MS_NUM_CHECK_RANGE,
10✔
5684
                     MS_SCALEBAR_INTERVALS_MIN,
5685
                     MS_SCALEBAR_INTERVALS_MAX) == -1)
5686
        return (-1);
5687
      break;
5688
    case (LABEL):
412✔
5689
      if (loadLabel(&(scalebar->label)) == -1)
412✔
5690
        return (-1);
5691
      scalebar->label.angle = 0;
412✔
5692
      break;
412✔
5693
    case (OUTLINECOLOR):
10✔
5694
      if (loadColor(&(scalebar->outlinecolor), NULL) != MS_SUCCESS)
10✔
5695
        return (-1);
5696
      break;
5697
    case (POSITION):
402✔
5698
      if ((scalebar->position =
402✔
5699
               getSymbol(6, MS_UL, MS_UR, MS_LL, MS_LR, MS_UC, MS_LC)) == -1)
402✔
5700
        return (-1);
5701
      break;
5702
    case (POSTLABELCACHE):
402✔
5703
      if ((scalebar->postlabelcache = getSymbol(2, MS_TRUE, MS_FALSE)) == -1)
402✔
5704
        return (-1);
5705
      break;
5706
    case (SCALEBAR):
5707
      break; /* for string loads */
5708
    case (SIZE):
414✔
5709
      if (getInteger(&(scalebar->width), MS_NUM_CHECK_RANGE,
414✔
5710
                     MS_SCALEBAR_WIDTH_MIN, MS_SCALEBAR_WIDTH_MAX) == -1)
5711
        return (-1);
5712
      if (getInteger(&(scalebar->height), MS_NUM_CHECK_RANGE,
414✔
5713
                     MS_SCALEBAR_HEIGHT_MIN, MS_SCALEBAR_HEIGHT_MAX) == -1)
5714
        return (-1);
5715
      break;
5716
    case (STATUS):
414✔
5717
      if ((scalebar->status = getSymbol(3, MS_ON, MS_OFF, MS_EMBED)) == -1)
414✔
5718
        return (-1);
5719
      break;
5720
    case (STYLE):
402✔
5721
      if (getInteger(&(scalebar->style), MS_NUM_CHECK_RANGE, 0, 1) == -1)
402✔
5722
        return (-1); // only 2 styles: 0 and 1
5723
      break;
5724
    case (TRANSPARENT):
412✔
5725
      if ((scalebar->transparent = getSymbol(2, MS_ON, MS_OFF)) == -1)
412✔
5726
        return (-1);
5727
      break;
5728
    case (UNITS):
414✔
5729
      if ((scalebar->units =
414✔
5730
               getSymbol(6, MS_INCHES, MS_FEET, MS_MILES, MS_METERS,
414✔
5731
                         MS_KILOMETERS, MS_NAUTICALMILES)) == -1)
5732
        return (-1);
5733
      break;
5734
    case (OFFSET):
2✔
5735
      if (getInteger(&(scalebar->offsetx), MS_NUM_CHECK_RANGE,
2✔
5736
                     MS_SCALEBAR_OFFSET_MIN, MS_SCALEBAR_OFFSET_MAX) == -1)
5737
        return (-1);
5738
      if (getInteger(&(scalebar->offsety), MS_NUM_CHECK_RANGE,
2✔
5739
                     MS_SCALEBAR_OFFSET_MIN, MS_SCALEBAR_OFFSET_MAX) == -1)
5740
        return (-1);
5741
      break;
5742
    default:
×
5743
      if (strlen(msyystring_buffer) > 0) {
×
5744
        msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
5745
                   "loadScalebar()", msyystring_buffer, msyylineno);
5746
        return (-1);
×
5747
      } else {
5748
        return (0); /* end of a string, not an error */
5749
      }
5750
    }
5751
  } /* next token */
5752
}
5753

5754
int msUpdateScalebarFromString(scalebarObj *scalebar, char *string) {
×
5755
  if (!scalebar || !string)
×
5756
    return MS_FAILURE;
5757

5758
  msAcquireLock(TLOCK_PARSER);
×
5759

5760
  msyystate = MS_TOKENIZE_STRING;
×
5761
  msyystring = string;
×
5762
  msyylex(); /* sets things up, but doesn't process any tokens */
×
5763

5764
  msyylineno = 1; /* start at line 1 */
×
5765

5766
  if (loadScalebar(scalebar) == -1) {
×
5767
    msReleaseLock(TLOCK_PARSER);
×
5768
    return MS_FAILURE; /* parse error */
×
5769
    ;
5770
  }
5771

5772
  msyylex_destroy();
×
5773
  msReleaseLock(TLOCK_PARSER);
×
5774
  return MS_SUCCESS;
×
5775
}
5776

5777
static void writeScalebar(FILE *stream, int indent, scalebarObj *scalebar) {
1✔
5778
  colorObj c;
5779

5780
  indent++;
1✔
5781
  writeBlockBegin(stream, indent, "SCALEBAR");
1✔
5782
  writeKeyword(stream, indent, "ALIGN", scalebar->align, 2, MS_ALIGN_LEFT,
1✔
5783
               "LEFT", MS_ALIGN_RIGHT, "RIGHT");
5784
  writeColor(stream, indent, "BACKGROUNDCOLOR", NULL,
1✔
5785
             &(scalebar->backgroundcolor));
5786
  MS_INIT_COLOR(c, 0, 0, 0, 255);
1✔
5787
  writeColor(stream, indent, "COLOR", &c, &(scalebar->color));
1✔
5788
  writeColor(stream, indent, "IMAGECOLOR", NULL, &(scalebar->imagecolor));
1✔
5789
  writeNumber(stream, indent, "INTERVALS", -1, scalebar->intervals);
1✔
5790
  writeLabel(stream, indent, &(scalebar->label));
1✔
5791
  writeColor(stream, indent, "OUTLINECOLOR", NULL, &(scalebar->outlinecolor));
1✔
5792
  if (scalebar->status == MS_EMBED)
1✔
5793
    writeKeyword(stream, indent, "POSITION", scalebar->position, 6, MS_LL, "LL",
1✔
5794
                 MS_UL, "UL", MS_UR, "UR", MS_LR, "LR", MS_UC, "UC", MS_LC,
5795
                 "LC");
5796
  writeKeyword(stream, indent, "POSTLABELCACHE", scalebar->postlabelcache, 1,
1✔
5797
               MS_TRUE, "TRUE");
5798
  writeDimension(stream, indent, "SIZE", scalebar->width, scalebar->height,
1✔
5799
                 NULL, NULL);
5800
  writeKeyword(stream, indent, "STATUS", scalebar->status, 3, MS_ON, "ON",
1✔
5801
               MS_OFF, "OFF", MS_EMBED, "EMBED");
5802
  writeNumber(stream, indent, "STYLE", 0, scalebar->style);
1✔
5803
  writeKeyword(stream, indent, "TRANSPARENT", scalebar->transparent, 2, MS_TRUE,
1✔
5804
               "TRUE", MS_FALSE, "FALSE");
5805
  writeKeyword(stream, indent, "UNITS", scalebar->units, 6, MS_INCHES, "INCHES",
1✔
5806
               MS_FEET, "FEET", MS_MILES, "MILES", MS_METERS, "METERS",
5807
               MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES, "NAUTICALMILES");
5808
  writeBlockEnd(stream, indent, "SCALEBAR");
1✔
5809
  writeLineFeed(stream);
5810
}
1✔
5811

5812
char *msWriteScalebarToString(scalebarObj *scalebar) {
×
5813
  msIOContext context;
5814
  msIOBuffer buffer;
5815

5816
  context.label = NULL;
×
5817
  context.write_channel = MS_TRUE;
×
5818
  context.readWriteFunc = msIO_bufferWrite;
×
5819
  context.cbData = &buffer;
×
5820
  buffer.data = NULL;
×
5821
  buffer.data_len = 0;
×
5822
  buffer.data_offset = 0;
×
5823

5824
  msIO_installHandlers(NULL, &context, NULL);
×
5825

5826
  writeScalebar(stdout, -1, scalebar);
×
5827
  msIO_bufferWrite(&buffer, "", 1);
×
5828

5829
  msIO_installHandlers(NULL, NULL, NULL);
×
5830

5831
  return (char *)buffer.data;
×
5832
}
5833

5834
/*
5835
** Initialize a queryMapObj structure
5836
*/
5837
void initQueryMap(queryMapObj *querymap) {
3,108✔
5838
  querymap->width = querymap->height = -1;
3,108✔
5839
  querymap->style = MS_HILITE;
3,108✔
5840
  querymap->status = MS_OFF;
3,108✔
5841
  MS_INIT_COLOR(querymap->color, 255, 255, 0, 255); /* yellow */
3,108✔
5842
}
3,108✔
5843

5844
int loadQueryMap(queryMapObj *querymap, mapObj *map) {
165✔
5845
  querymap->map = (mapObj *)map;
165✔
5846

5847
  for (;;) {
5848
    switch (msyylex()) {
406✔
5849
    case (QUERYMAP):
5850
      break; /* for string loads */
5851
    case (COLOR):
154✔
5852
      if (loadColor(&(querymap->color), NULL) != MS_SUCCESS)
154✔
5853
        return MS_FAILURE;
5854
      break;
5855
    case (EOF):
×
5856
      msSetError(MS_EOFERR, NULL, "loadQueryMap()");
×
5857
      return (-1);
×
5858
    case (END):
5859
      return (0);
5860
      break;
5861
    case (SIZE):
29✔
5862
      /*
5863
       ** we do -1 (and avoid 0) here to maintain backwards compatibility as
5864
       *older versions write "SIZE -1 -1" when saving a mapfile
5865
       */
5866
      if (getInteger(&(querymap->width), MS_NUM_CHECK_RANGE, -1,
29✔
5867
                     querymap->map->maxsize) == -1 ||
29✔
5868
          querymap->width == 0) {
29✔
5869
        msSetError(MS_MISCERR, "Invalid SIZE value (line %d)", "loadQueryMap()",
×
5870
                   msyylineno);
5871
        return (-1);
×
5872
      }
5873
      if (getInteger(&(querymap->height), MS_NUM_CHECK_RANGE, -1,
29✔
5874
                     querymap->map->maxsize) == -1 ||
29✔
5875
          querymap->height == 0) {
29✔
5876
        msSetError(MS_MISCERR, "Invalid SIZE value (line %d)", "loadQueryMap()",
×
5877
                   msyylineno);
5878
        return (-1);
×
5879
      }
5880
      break;
5881
    case (STATUS):
29✔
5882
      if ((querymap->status = getSymbol(2, MS_ON, MS_OFF)) == -1)
29✔
5883
        return (-1);
5884
      break;
5885
    case (STYLE):
29✔
5886
    case (TYPE):
5887
      if ((querymap->style = getSymbol(3, MS_NORMAL, MS_HILITE, MS_SELECTED)) ==
29✔
5888
          -1)
5889
        return (-1);
5890
      break;
5891
    default:
×
5892
      if (strlen(msyystring_buffer) > 0) {
×
5893
        msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
5894
                   "loadQueryMap()", msyystring_buffer, msyylineno);
5895
        return (-1);
×
5896
      } else {
5897
        return (0); /* end of a string, not an error */
5898
      }
5899
    }
5900
  }
5901
}
5902

5903
int msUpdateQueryMapFromString(queryMapObj *querymap, char *string) {
×
5904
  if (!querymap || !string)
×
5905
    return MS_FAILURE;
5906

5907
  msAcquireLock(TLOCK_PARSER);
×
5908

5909
  msyystate = MS_TOKENIZE_STRING;
×
5910
  msyystring = string;
×
5911
  msyylex(); /* sets things up, but doesn't process any tokens */
×
5912

5913
  msyylineno = 1; /* start at line 1 */
×
5914

5915
  if (loadQueryMap(querymap, querymap->map) == -1) {
×
5916
    msReleaseLock(TLOCK_PARSER);
×
5917
    return MS_FAILURE; /* parse error */
×
5918
    ;
5919
  }
5920

5921
  msyylex_destroy();
×
5922
  msReleaseLock(TLOCK_PARSER);
×
5923
  return MS_SUCCESS;
×
5924
}
5925

5926
static void writeQueryMap(FILE *stream, int indent, queryMapObj *querymap) {
1✔
5927
  colorObj c;
5928

5929
  indent++;
1✔
5930
  writeBlockBegin(stream, indent, "QUERYMAP");
1✔
5931
  MS_INIT_COLOR(c, 255, 255, 0, 255);
1✔
5932
  writeColor(stream, indent, "COLOR", &c, &(querymap->color));
1✔
5933
  if (querymap->width != -1 &&
1✔
5934
      querymap->height != -1) // don't write SIZE if not explicitly set
×
5935
    writeDimension(stream, indent, "SIZE", querymap->width, querymap->height,
×
5936
                   NULL, NULL);
5937
  writeKeyword(stream, indent, "STATUS", querymap->status, 2, MS_ON, "ON",
1✔
5938
               MS_OFF, "OFF");
5939
  writeKeyword(stream, indent, "STYLE", querymap->style, 3, MS_NORMAL, "NORMAL",
1✔
5940
               MS_HILITE, "HILITE", MS_SELECTED, "SELECTED");
5941
  writeBlockEnd(stream, indent, "QUERYMAP");
1✔
5942
  writeLineFeed(stream);
5943
}
1✔
5944

5945
char *msWriteQueryMapToString(queryMapObj *querymap) {
×
5946
  msIOContext context;
5947
  msIOBuffer buffer;
5948

5949
  context.label = NULL;
×
5950
  context.write_channel = MS_TRUE;
×
5951
  context.readWriteFunc = msIO_bufferWrite;
×
5952
  context.cbData = &buffer;
×
5953
  buffer.data = NULL;
×
5954
  buffer.data_len = 0;
×
5955
  buffer.data_offset = 0;
×
5956

5957
  msIO_installHandlers(NULL, &context, NULL);
×
5958

5959
  writeQueryMap(stdout, -1, querymap);
×
5960
  msIO_bufferWrite(&buffer, "", 1);
×
5961

5962
  msIO_installHandlers(NULL, NULL, NULL);
×
5963

5964
  return (char *)buffer.data;
×
5965
}
5966

5967
/*
5968
** Initialize a webObj structure
5969
*/
5970
void initWeb(webObj *web) {
3,108✔
5971
  web->template = NULL;
3,108✔
5972
  web->header = web->footer = NULL;
3,108✔
5973
  web->error = web->empty = NULL;
3,108✔
5974
  web->mintemplate = web->maxtemplate = NULL;
3,108✔
5975
  web->minscaledenom = web->maxscaledenom = -1;
3,108✔
5976
  web->imagepath = msStrdup("");
3,108✔
5977
  web->temppath = NULL;
3,108✔
5978
  web->imageurl = msStrdup("");
3,108✔
5979

5980
  initHashTable(&(web->metadata));
3,108✔
5981
  initHashTable(&(web->validation));
3,108✔
5982

5983
  web->map = NULL;
3,108✔
5984
  web->queryformat = msStrdup("text/html");
3,108✔
5985
  web->legendformat = msStrdup("text/html");
3,108✔
5986
  web->browseformat = msStrdup("text/html");
3,108✔
5987
}
3,108✔
5988

5989
void freeWeb(webObj *web) {
3,099✔
5990
  msFree(web->template);
3,099✔
5991
  msFree(web->header);
3,099✔
5992
  msFree(web->footer);
3,099✔
5993
  msFree(web->error);
3,099✔
5994
  msFree(web->empty);
3,099✔
5995
  msFree(web->maxtemplate);
3,099✔
5996
  msFree(web->mintemplate);
3,099✔
5997
  msFree(web->imagepath);
3,099✔
5998
  msFree(web->temppath);
3,099✔
5999
  msFree(web->imageurl);
3,099✔
6000
  msFree(web->queryformat);
3,099✔
6001
  msFree(web->legendformat);
3,099✔
6002
  msFree(web->browseformat);
3,099✔
6003
  msFreeHashItems(&(web->metadata));
3,099✔
6004
  msFreeHashItems(&(web->validation));
3,099✔
6005
}
3,099✔
6006

6007
static void writeWeb(FILE *stream, int indent, webObj *web) {
1✔
6008
  indent++;
1✔
6009
  writeBlockBegin(stream, indent, "WEB");
1✔
6010
  writeString(stream, indent, "BROWSEFORMAT", "text/html", web->browseformat);
1✔
6011
  writeString(stream, indent, "EMPTY", NULL, web->empty);
1✔
6012
  writeString(stream, indent, "ERROR", NULL, web->error);
1✔
6013
  writeString(stream, indent, "FOOTER", NULL, web->footer);
1✔
6014
  writeString(stream, indent, "HEADER", NULL, web->header);
1✔
6015
  writeString(stream, indent, "IMAGEPATH", "", web->imagepath);
1✔
6016
  writeString(stream, indent, "TEMPPATH", NULL, web->temppath);
1✔
6017
  writeString(stream, indent, "IMAGEURL", "", web->imageurl);
1✔
6018
  writeString(stream, indent, "LEGENDFORMAT", "text/html", web->legendformat);
1✔
6019
  writeNumber(stream, indent, "MAXSCALEDENOM", -1, web->maxscaledenom);
1✔
6020
  writeString(stream, indent, "MAXTEMPLATE", NULL, web->maxtemplate);
1✔
6021
  writeHashTable(stream, indent, "METADATA", &(web->metadata));
1✔
6022
  writeNumber(stream, indent, "MINSCALEDENOM", -1, web->minscaledenom);
1✔
6023
  writeString(stream, indent, "MINTEMPLATE", NULL, web->mintemplate);
1✔
6024
  writeString(stream, indent, "QUERYFORMAT", "text/html", web->queryformat);
1✔
6025
  writeString(stream, indent, "TEMPLATE", NULL, web->template);
1✔
6026
  writeHashTable(stream, indent, "VALIDATION", &(web->validation));
1✔
6027
  writeBlockEnd(stream, indent, "WEB");
1✔
6028
  writeLineFeed(stream);
6029
}
1✔
6030

6031
char *msWriteWebToString(webObj *web) {
×
6032
  msIOContext context;
6033
  msIOBuffer buffer;
6034

6035
  context.label = NULL;
×
6036
  context.write_channel = MS_TRUE;
×
6037
  context.readWriteFunc = msIO_bufferWrite;
×
6038
  context.cbData = &buffer;
×
6039
  buffer.data = NULL;
×
6040
  buffer.data_len = 0;
×
6041
  buffer.data_offset = 0;
×
6042

6043
  msIO_installHandlers(NULL, &context, NULL);
×
6044

6045
  writeWeb(stdout, -1, web);
×
6046
  msIO_bufferWrite(&buffer, "", 1);
×
6047

6048
  msIO_installHandlers(NULL, NULL, NULL);
×
6049

6050
  return (char *)buffer.data;
×
6051
}
6052

6053
int loadWeb(webObj *web, mapObj *map) {
2,326✔
6054
  web->map = (mapObj *)map;
2,326✔
6055

6056
  for (;;) {
6057
    switch (msyylex()) {
7,799✔
6058
    case (BROWSEFORMAT): /* change to use validation in 6.0 */
×
6059
      free(web->browseformat);
×
6060
      web->browseformat = NULL; /* there is a default */
×
6061
      if (getString(&web->browseformat) == MS_FAILURE)
×
6062
        return (-1);
6063
      break;
6064
    case (EMPTY):
2✔
6065
      if (getString(&web->empty) == MS_FAILURE)
2✔
6066
        return (-1);
6067
      break;
6068
    case (WEB):
6069
      break; /* for string loads */
6070
    case (EOF):
×
6071
      msSetError(MS_EOFERR, NULL, "loadWeb()");
×
6072
      return (-1);
×
6073
    case (END):
6074
      return (0);
6075
      break;
6076
    case (ERROR):
×
6077
      if (getString(&web->error) == MS_FAILURE)
×
6078
        return (-1);
6079
      break;
6080
    case (FOOTER):
50✔
6081
      if (getString(&web->footer) == MS_FAILURE)
50✔
6082
        return (-1); /* getString() cleans up previously allocated string */
6083
      break;
6084
    case (HEADER):
50✔
6085
      if (getString(&web->header) == MS_FAILURE)
50✔
6086
        return (-1); /* getString() cleans up previously allocated string */
6087
      break;
6088
    case (IMAGEPATH):
1,364✔
6089
      if (getString(&web->imagepath) == MS_FAILURE)
1,364✔
6090
        return (-1);
6091
      break;
6092
    case (TEMPPATH):
×
6093
      if (getString(&web->temppath) == MS_FAILURE)
×
6094
        return (-1);
6095
      break;
6096
    case (IMAGEURL):
1,347✔
6097
      if (getString(&web->imageurl) == MS_FAILURE)
1,347✔
6098
        return (-1);
6099
      break;
6100
    case (LEGENDFORMAT): /* change to use validation in 6.0 */
×
6101
      free(web->legendformat);
×
6102
      web->legendformat = NULL; /* there is a default */
×
6103
      if (getString(&web->legendformat) == MS_FAILURE)
×
6104
        return (-1);
6105
      break;
6106
    case (MAXSCALEDENOM):
144✔
6107
      if (getDouble(&web->maxscaledenom, MS_NUM_CHECK_GTE, 0, -1) == -1)
144✔
6108
        return (-1);
6109
      break;
6110
    case (MAXTEMPLATE):
×
6111
      if (getString(&web->maxtemplate) == MS_FAILURE)
×
6112
        return (-1);
6113
      break;
6114
    case (METADATA):
2,247✔
6115
      if (loadHashTable(&(web->metadata)) != MS_SUCCESS)
2,247✔
6116
        return (-1);
6117
      break;
6118
    case (MINSCALEDENOM):
144✔
6119
      if (getDouble(&web->minscaledenom, MS_NUM_CHECK_GTE, 0, -1) == -1)
144✔
6120
        return (-1);
6121
      break;
6122
    case (MINTEMPLATE):
×
6123
      if (getString(&web->mintemplate) == MS_FAILURE)
×
6124
        return (-1);
6125
      break;
6126
    case (QUERYFORMAT): /* change to use validation in 6.0 */
59✔
6127
      free(web->queryformat);
59✔
6128
      web->queryformat = NULL; /* there is a default */
59✔
6129
      if (getString(&web->queryformat) == MS_FAILURE)
59✔
6130
        return (-1);
6131
      break;
6132
    case (TEMPLATE):
×
6133
      if (getString(&web->template) == MS_FAILURE)
×
6134
        return (-1); /* getString() cleans up previously allocated string */
6135
      break;
6136
    case (VALIDATION):
66✔
6137
      if (loadHashTable(&(web->validation)) != MS_SUCCESS)
66✔
6138
        return (-1);
6139
      break;
6140
    default:
×
6141
      if (strlen(msyystring_buffer) > 0) {
×
6142
        msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
6143
                   "loadWeb()", msyystring_buffer, msyylineno);
6144
        return (-1);
×
6145
      } else {
6146
        return (0); /* end of a string, not an error */
6147
      }
6148
    }
6149
  }
6150
}
6151

6152
int msUpdateWebFromString(webObj *web, char *string) {
×
6153
  if (!web || !string)
×
6154
    return MS_FAILURE;
6155

6156
  msAcquireLock(TLOCK_PARSER);
×
6157

6158
  msyystate = MS_TOKENIZE_STRING;
×
6159
  msyystring = string;
×
6160
  msyylex(); /* sets things up, but doesn't process any tokens */
×
6161

6162
  msyylineno = 1; /* start at line 1 */
×
6163

6164
  if (loadWeb(web, web->map) == -1) {
×
6165
    msReleaseLock(TLOCK_PARSER);
×
6166
    return MS_FAILURE; /* parse error */
×
6167
    ;
6168
  }
6169

6170
  msyylex_destroy();
×
6171
  msReleaseLock(TLOCK_PARSER);
×
6172
  return MS_SUCCESS;
×
6173
}
6174

6175
/*
6176
** Initialize, load and free a mapObj structure
6177
**
6178
** This really belongs in mapobject.c, but currently it also depends on
6179
** lots of other init methods in this file.
6180
*/
6181

6182
int initMap(mapObj *map) {
3,108✔
6183
  int i = 0;
6184
  MS_REFCNT_INIT(map);
3,108✔
6185

6186
  map->debug = (int)msGetGlobalDebugLevel();
3,108✔
6187

6188
  /* Set maxlayers = 0, layers[] and layerorder[] will be allocated as needed,
6189
   * on the first call to msGrowMapLayers()
6190
   */
6191
  map->numlayers = 0;
3,108✔
6192
  map->maxlayers = 0;
3,108✔
6193
  map->layers = NULL;
3,108✔
6194
  map->layerorder =
3,108✔
6195
      NULL; /* used to modify the order in which the layers are drawn */
6196

6197
  map->status = MS_ON;
3,108✔
6198
  map->name = msStrdup("MS");
3,108✔
6199
  map->extent.minx = map->extent.miny = map->extent.maxx = map->extent.maxy =
3,108✔
6200
      -1.0;
6201

6202
  map->scaledenom = -1.0;
3,108✔
6203
  map->resolution = MS_DEFAULT_RESOLUTION;    /* pixels per inch */
3,108✔
6204
  map->defresolution = MS_DEFAULT_RESOLUTION; /* pixels per inch */
3,108✔
6205

6206
  map->height = map->width = -1;
3,108✔
6207
  map->maxsize = MS_MAXIMAGESIZE_DEFAULT;
3,108✔
6208

6209
  map->gt.need_geotransform = MS_FALSE;
3,108✔
6210
  map->gt.rotation_angle = 0.0;
3,108✔
6211

6212
  map->units = MS_METERS;
3,108✔
6213
  map->cellsize = 0;
3,108✔
6214
  map->shapepath = NULL;
3,108✔
6215
  map->mappath = NULL;
3,108✔
6216
  map->sldurl = NULL;
3,108✔
6217

6218
  MS_INIT_COLOR(map->imagecolor, 255, 255, 255, 255); /* white */
3,108✔
6219

6220
  map->numoutputformats = 0;
3,108✔
6221
  map->outputformatlist = NULL;
3,108✔
6222
  map->outputformat = NULL;
3,108✔
6223

6224
  /* map->configoptions = msCreateHashTable();; */
6225
  initHashTable(&(map->configoptions));
3,108✔
6226

6227
  map->imagetype = NULL;
3,108✔
6228

6229
  map->palette.numcolors = 0;
3,108✔
6230

6231
  for (i = 0; i < MS_MAX_LABEL_PRIORITY; i++) {
34,188✔
6232
    map->labelcache.slots[i].labels =
31,080✔
6233
        NULL; /* cache is initialize at draw time */
6234
    map->labelcache.slots[i].cachesize = 0;
31,080✔
6235
    map->labelcache.slots[i].numlabels = 0;
31,080✔
6236
    map->labelcache.slots[i].markers = NULL;
31,080✔
6237
    map->labelcache.slots[i].markercachesize = 0;
31,080✔
6238
    map->labelcache.slots[i].nummarkers = 0;
31,080✔
6239
  }
6240

6241
  map->fontset.filename = NULL;
3,108✔
6242
  map->fontset.numfonts = 0;
3,108✔
6243

6244
  /* map->fontset.fonts = NULL; */
6245
  initHashTable(&(map->fontset.fonts));
3,108✔
6246

6247
  msInitSymbolSet(&map->symbolset);
3,108✔
6248
  map->symbolset.fontset = &(map->fontset);
3,108✔
6249
  map->symbolset.map = map;
3,108✔
6250

6251
  initLegend(&map->legend);
3,108✔
6252
  initScalebar(&map->scalebar);
3,108✔
6253
  initWeb(&map->web);
3,108✔
6254
  initReferenceMap(&map->reference);
3,108✔
6255
  initQueryMap(&map->querymap);
3,108✔
6256

6257
  map->projContext = msProjectionContextGetFromPool();
3,108✔
6258

6259
  if (msInitProjection(&(map->projection)) == -1)
3,108✔
6260
    return (-1);
6261
  if (msInitProjection(&(map->latlon)) == -1)
3,108✔
6262
    return (-1);
6263

6264
  msProjectionSetContext(&(map->projection), map->projContext);
3,108✔
6265
  msProjectionSetContext(&(map->latlon), map->projContext);
3,108✔
6266

6267
  /* initialize a default "geographic" projection */
6268
  map->latlon.numargs = 2;
3,108✔
6269
  map->latlon.args[0] = msStrdup("proj=latlong");
3,108✔
6270
  map->latlon.args[1] =
6,216✔
6271
      msStrdup("ellps=WGS84"); /* probably want a different ellipsoid */
3,108✔
6272
  if (msProcessProjection(&(map->latlon)) == -1)
3,108✔
6273
    return (-1);
6274

6275
  map->templatepattern = map->datapattern = NULL;
3,108✔
6276

6277
  /* Encryption key information - see mapcrypto.c */
6278
  map->encryption_key_loaded = MS_FALSE;
3,108✔
6279

6280
  msInitQuery(&(map->query));
3,108✔
6281

6282
#ifdef USE_V8_MAPSCRIPT
6283
  map->v8context = NULL;
6284
#endif
6285

6286
  map->config = NULL;
3,108✔
6287

6288
  return (0);
3,108✔
6289
}
6290

6291
/*
6292
** Ensure there is at least one free entry in the layers and layerorder
6293
** arrays of this mapObj. Grow the allocated layers/layerorder arrays if
6294
** necessary and allocate a new layer for layers[numlayers] if there is
6295
** not already one, setting its contents to all zero bytes (i.e. does not
6296
** call initLayer() on it).
6297
**
6298
** This function is safe to use for the initial allocation of the layers[]
6299
** and layerorder[] arrays as well (i.e. when maxlayers==0 and layers==NULL)
6300
**
6301
** Returns a reference to the new layerObj on success, NULL on error.
6302
*/
6303
layerObj *msGrowMapLayers(mapObj *map) {
13,113✔
6304
  /* Do we need to increase the size of layers/layerorder by
6305
   * MS_LAYER_ALLOCSIZE?
6306
   */
6307
  if (map->numlayers == map->maxlayers) {
13,113✔
6308
    layerObj **newLayersPtr;
6309
    int *newLayerorderPtr;
6310
    int i, newsize;
6311

6312
    newsize = map->maxlayers + MS_LAYER_ALLOCSIZE;
3,070✔
6313

6314
    /* Alloc/realloc layers */
6315
    newLayersPtr =
6316
        (layerObj **)realloc(map->layers, newsize * sizeof(layerObj *));
3,070✔
6317
    MS_CHECK_ALLOC(newLayersPtr, newsize * sizeof(layerObj *), NULL);
3,070✔
6318

6319
    map->layers = newLayersPtr;
3,070✔
6320

6321
    /* Alloc/realloc layerorder */
6322
    newLayerorderPtr = (int *)realloc(map->layerorder, newsize * sizeof(int));
3,070✔
6323
    MS_CHECK_ALLOC(newLayerorderPtr, newsize * sizeof(int), NULL);
3,070✔
6324

6325
    map->layerorder = newLayerorderPtr;
3,070✔
6326

6327
    map->maxlayers = newsize;
3,070✔
6328
    for (i = map->numlayers; i < map->maxlayers; i++) {
199,550✔
6329
      map->layers[i] = NULL;
196,480✔
6330
      map->layerorder[i] = 0;
196,480✔
6331
    }
6332
  }
6333

6334
  if (map->layers[map->numlayers] == NULL) {
13,113✔
6335
    map->layers[map->numlayers] = (layerObj *)calloc(1, sizeof(layerObj));
13,113✔
6336
    MS_CHECK_ALLOC(map->layers[map->numlayers], sizeof(layerObj), NULL);
13,113✔
6337
  }
6338

6339
  return map->layers[map->numlayers];
13,113✔
6340
}
6341

6342
int msFreeLabelCacheSlot(labelCacheSlotObj *cacheslot) {
42,910✔
6343
  int i, j;
6344

6345
  /* free the labels */
6346
  if (cacheslot->labels) {
42,910✔
6347
    for (i = 0; i < cacheslot->numlabels; i++) {
16,549✔
6348

6349
      for (j = 0; j < cacheslot->labels[i].numtextsymbols; j++) {
14,646✔
6350
        freeTextSymbol(cacheslot->labels[i].textsymbols[j]);
10,017✔
6351
        free(cacheslot->labels[i].textsymbols[j]);
10,017✔
6352
      }
6353
      msFree(cacheslot->labels[i].textsymbols);
4,629✔
6354

6355
      if (cacheslot->labels[i].leaderline) {
4,629✔
6356
        msFree(cacheslot->labels[i].leaderline->point);
32✔
6357
        msFree(cacheslot->labels[i].leaderline);
32✔
6358
        msFree(cacheslot->labels[i].leaderbbox);
32✔
6359
      }
6360
    }
6361
  }
6362
  msFree(cacheslot->labels);
42,910✔
6363
  cacheslot->labels = NULL;
42,910✔
6364
  cacheslot->cachesize = 0;
42,910✔
6365
  cacheslot->numlabels = 0;
42,910✔
6366

6367
  msFree(cacheslot->markers);
42,910✔
6368
  cacheslot->markers = NULL;
42,910✔
6369
  cacheslot->markercachesize = 0;
42,910✔
6370
  cacheslot->nummarkers = 0;
42,910✔
6371

6372
  return (MS_SUCCESS);
42,910✔
6373
}
6374

6375
int msFreeLabelCache(labelCacheObj *cache) {
4,291✔
6376
  int p;
6377

6378
  for (p = 0; p < MS_MAX_LABEL_PRIORITY; p++) {
47,201✔
6379
    if (msFreeLabelCacheSlot(&(cache->slots[p])) != MS_SUCCESS)
42,910✔
6380
      return MS_FAILURE;
6381
  }
6382

6383
  cache->num_allocated_rendered_members = cache->num_rendered_members = 0;
4,291✔
6384
  msFree(cache->rendered_text_symbols);
4,291✔
6385

6386
  return MS_SUCCESS;
4,291✔
6387
}
6388

6389
int msInitLabelCacheSlot(labelCacheSlotObj *cacheslot) {
11,920✔
6390

6391
  if (cacheslot->labels || cacheslot->markers)
11,920✔
6392
    msFreeLabelCacheSlot(cacheslot);
×
6393

6394
  cacheslot->labels = (labelCacheMemberObj *)malloc(
11,920✔
6395
      sizeof(labelCacheMemberObj) * MS_LABELCACHEINITSIZE);
6396
  MS_CHECK_ALLOC(cacheslot->labels,
11,920✔
6397
                 sizeof(labelCacheMemberObj) * MS_LABELCACHEINITSIZE,
6398
                 MS_FAILURE);
6399

6400
  cacheslot->cachesize = MS_LABELCACHEINITSIZE;
11,920✔
6401
  cacheslot->numlabels = 0;
11,920✔
6402

6403
  cacheslot->markers = (markerCacheMemberObj *)malloc(
11,920✔
6404
      sizeof(markerCacheMemberObj) * MS_LABELCACHEINITSIZE);
6405
  MS_CHECK_ALLOC(cacheslot->markers,
11,920✔
6406
                 sizeof(markerCacheMemberObj) * MS_LABELCACHEINITSIZE,
6407
                 MS_FAILURE);
6408

6409
  cacheslot->markercachesize = MS_LABELCACHEINITSIZE;
11,920✔
6410
  cacheslot->nummarkers = 0;
11,920✔
6411

6412
  return (MS_SUCCESS);
11,920✔
6413
}
6414

6415
int msInitLabelCache(labelCacheObj *cache) {
1,192✔
6416
  int p;
6417

6418
  for (p = 0; p < MS_MAX_LABEL_PRIORITY; p++) {
13,112✔
6419
    if (msInitLabelCacheSlot(&(cache->slots[p])) != MS_SUCCESS)
11,920✔
6420
      return MS_FAILURE;
6421
  }
6422
  cache->gutter = 0;
1,192✔
6423
  cache->num_allocated_rendered_members = cache->num_rendered_members = 0;
1,192✔
6424
  cache->rendered_text_symbols = NULL;
1,192✔
6425

6426
  return MS_SUCCESS;
1,192✔
6427
}
6428

6429
static void writeMap(FILE *stream, int indent, mapObj *map) {
1✔
6430
  int i;
6431
  colorObj c;
6432

6433
  writeBlockBegin(stream, indent, "MAP");
1✔
6434
  writeNumber(stream, indent, "ANGLE", 0, map->gt.rotation_angle);
1✔
6435
  writeHashTableInline(stream, indent, "CONFIG", &(map->configoptions));
1✔
6436
  writeNumber(stream, indent, "DEBUG", 0, map->debug);
1✔
6437
  writeNumber(stream, indent, "DEFRESOLUTION", 72.0, map->defresolution);
1✔
6438
  writeExtent(stream, indent, "EXTENT", map->extent);
1✔
6439
  writeString(stream, indent, "FONTSET", NULL, map->fontset.filename);
1✔
6440
  MS_INIT_COLOR(c, 255, 255, 255, 255);
1✔
6441
  writeColor(stream, indent, "IMAGECOLOR", &c, &(map->imagecolor));
1✔
6442
  writeString(stream, indent, "IMAGETYPE", NULL, map->imagetype);
1✔
6443
  writeNumber(stream, indent, "MAXSIZE", MS_MAXIMAGESIZE_DEFAULT, map->maxsize);
1✔
6444
  writeString(stream, indent, "NAME", NULL, map->name);
1✔
6445
  writeNumber(stream, indent, "RESOLUTION", 72.0, map->resolution);
1✔
6446
  writeString(stream, indent, "SHAPEPATH", NULL, map->shapepath);
1✔
6447
  writeDimension(stream, indent, "SIZE", map->width, map->height, NULL, NULL);
1✔
6448
  writeKeyword(stream, indent, "STATUS", map->status, 2, MS_ON, "ON", MS_OFF,
1✔
6449
               "OFF");
6450
  writeString(stream, indent, "SYMBOLSET", NULL, map->symbolset.filename);
1✔
6451
  writeKeyword(stream, indent, "UNITS", map->units, 7, MS_INCHES, "INCHES",
1✔
6452
               MS_FEET, "FEET", MS_MILES, "MILES", MS_METERS, "METERS",
6453
               MS_KILOMETERS, "KILOMETERS", MS_NAUTICALMILES, "NAUTICALMILES",
6454
               MS_DD, "DD");
6455
  writeLineFeed(stream);
6456

6457
  writeOutputformat(stream, indent, map);
1✔
6458

6459
  /* write symbol with INLINE tag in mapfile */
6460
  for (i = 0; i < map->symbolset.numsymbols; i++) {
5✔
6461
    if (map->symbolset.symbol[i]->inmapfile)
4✔
6462
      writeSymbol(map->symbolset.symbol[i], stream);
×
6463
  }
6464

6465
  writeProjection(stream, indent, &(map->projection));
1✔
6466

6467
  writeLegend(stream, indent, &(map->legend));
1✔
6468
  writeQueryMap(stream, indent, &(map->querymap));
1✔
6469
  writeReferenceMap(stream, indent, &(map->reference));
1✔
6470
  writeScalebar(stream, indent, &(map->scalebar));
1✔
6471
  writeWeb(stream, indent, &(map->web));
1✔
6472

6473
  for (i = 0; i < map->numlayers; i++)
8✔
6474
    writeLayer(stream, indent, GET_LAYER(map, map->layerorder[i]));
7✔
6475

6476
  writeBlockEnd(stream, indent, "MAP");
1✔
6477
}
1✔
6478

6479
char *msWriteMapToString(mapObj *map) {
×
6480
  msIOContext context;
6481
  msIOBuffer buffer;
6482

6483
  context.label = NULL;
×
6484
  context.write_channel = MS_TRUE;
×
6485
  context.readWriteFunc = msIO_bufferWrite;
×
6486
  context.cbData = &buffer;
×
6487
  buffer.data = NULL;
×
6488
  buffer.data_len = 0;
×
6489
  buffer.data_offset = 0;
×
6490

6491
  msIO_installHandlers(NULL, &context, NULL);
×
6492

6493
  writeMap(stdout, 0, map);
×
6494
  msIO_bufferWrite(&buffer, "", 1);
×
6495

6496
  msIO_installHandlers(NULL, NULL, NULL);
×
6497

6498
  return (char *)buffer.data;
×
6499
}
6500

6501
int msSaveMap(mapObj *map, char *filename) {
1✔
6502
  FILE *stream;
6503
  char szPath[MS_MAXPATHLEN];
6504

6505
  if (!map) {
1✔
6506
    msSetError(MS_MISCERR, "Map is undefined.", "msSaveMap()");
×
6507
    return (-1);
×
6508
  }
6509

6510
  if (!filename) {
1✔
6511
    msSetError(MS_MISCERR, "Filename is undefined.", "msSaveMap()");
×
6512
    return (-1);
×
6513
  }
6514

6515
  stream = fopen(msBuildPath(szPath, map->mappath, filename), "w");
1✔
6516
  if (!stream) {
1✔
6517
    msSetError(MS_IOERR, "(%s)", "msSaveMap()", filename);
×
6518
    return (-1);
×
6519
  }
6520

6521
  writeMap(stream, 0, map);
1✔
6522
  fclose(stream);
1✔
6523

6524
  return (0);
1✔
6525
}
6526

6527
static void writeConfig(FILE *stream, int indent, configObj *config) {
×
6528
  writeBlockBegin(stream, indent, "CONFIG");
×
6529
  writeHashTable(stream, indent, "ENV", &(config->env));
×
6530
  writeHashTable(stream, indent, "MAPS", &(config->maps));
×
6531
  writeBlockEnd(stream, indent, "CONFIG");
×
6532
}
×
6533

6534
int msSaveConfig(configObj *config, const char *filename) {
×
6535
  FILE *stream;
6536

6537
  if (!config) {
×
6538
    msSetError(MS_MISCERR, "Config is undefined.", "msSaveConfigMap()");
×
6539
    return (-1);
×
6540
  }
6541

6542
  if (!filename) {
×
6543
    msSetError(MS_MISCERR, "Filename is undefined.", "msSaveConfigMap()");
×
6544
    return (-1);
×
6545
  }
6546

6547
  stream = fopen(filename, "w");
×
6548
  if (!stream) {
×
6549
    msSetError(MS_IOERR, "(%s)", "msSaveConfig()", filename);
×
6550
    return (-1);
×
6551
  }
6552

6553
  writeConfig(stream, 0, config);
×
6554
  fclose(stream);
×
6555

6556
  return (0);
×
6557
}
6558

6559
static int loadMapInternal(mapObj *map) {
3,015✔
6560
  int foundMapToken = MS_FALSE;
6561
  int foundBomToken = MS_FALSE;
6562
  int token;
6563

6564
  for (;;) {
6565

6566
    token = msyylex();
47,201✔
6567

6568
    if (!foundBomToken && token == BOM) {
47,201✔
6569
      foundBomToken = MS_TRUE;
6570
      if (!foundMapToken) {
×
6571
        continue; /*skip a leading bom*/
×
6572
      }
6573
    }
6574
    if (!foundMapToken && token != MAP) {
47,201✔
6575
      msSetError(MS_IDENTERR,
2✔
6576
                 "First token must be MAP, this doesn't look like a mapfile.",
6577
                 "msLoadMap()");
6578
      return (MS_FAILURE);
2✔
6579
    }
6580

6581
    switch (token) {
47,199✔
6582

6583
    case (CONFIG): {
88✔
6584
      char *key = NULL, *value = NULL;
88✔
6585

6586
      if (getString(&key) == MS_FAILURE)
88✔
6587
        return MS_FAILURE;
×
6588

6589
      if (getString(&value) == MS_FAILURE) {
88✔
6590
        free(key);
×
6591
        return MS_FAILURE;
×
6592
      }
6593

6594
      if (msSetConfigOption(map, key, value) == MS_FAILURE) {
88✔
6595
        free(key);
×
6596
        free(value);
×
6597
        return MS_FAILURE;
×
6598
      }
6599

6600
      free(key);
88✔
6601
      free(value);
88✔
6602
    } break;
88✔
6603
    case (DEBUG):
102✔
6604
      if ((map->debug = getSymbol(3, MS_ON, MS_OFF, MS_NUMBER)) == -1)
102✔
6605
        return MS_FAILURE;
6606
      if (map->debug == MS_NUMBER) {
102✔
6607
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, 0, 5) == MS_FAILURE) {
32✔
6608
          msSetError(MS_MISCERR,
×
6609
                     "Invalid DEBUG level, must be between 0 and 5 (line %d)",
6610
                     "msLoadMap()", msyylineno);
6611
          return (-1);
×
6612
        }
6613
        map->debug = (int)msyynumber;
32✔
6614
      }
6615
      break;
6616
    case (END):
3,011✔
6617
      if (msyyin) {
3,011✔
6618
        fclose(msyyin);
3,008✔
6619
        msyyin = NULL;
3,008✔
6620
      }
6621

6622
      /*** Make config options current ***/
6623
      msApplyMapConfigOptions(map);
3,011✔
6624

6625
      /*** Compute rotated extent info if applicable ***/
6626
      msMapComputeGeotransform(map);
3,011✔
6627

6628
      /*** OUTPUTFORMAT related setup ***/
6629
      if (msPostMapParseOutputFormatSetup(map) == MS_FAILURE)
3,011✔
6630
        return MS_FAILURE;
6631

6632
      if (loadSymbolSet(&(map->symbolset), map) == -1)
3,011✔
6633
        return MS_FAILURE;
6634

6635
      if (resolveSymbolNames(map) == MS_FAILURE)
3,011✔
6636
        return MS_FAILURE;
6637

6638
      if (msLoadFontSet(&(map->fontset), map) == -1)
3,011✔
6639
        return MS_FAILURE;
×
6640

6641
      return MS_SUCCESS;
6642
      break;
6643
    case (EOF):
×
6644
      msSetError(MS_EOFERR, NULL, "msLoadMap()");
×
6645
      return MS_FAILURE;
×
6646
    case (EXTENT): {
2,852✔
6647
      if (getDouble(&(map->extent.minx), MS_NUM_CHECK_NONE, -1, -1) == -1)
2,852✔
6648
        return MS_FAILURE;
6649
      if (getDouble(&(map->extent.miny), MS_NUM_CHECK_NONE, -1, -1) == -1)
2,852✔
6650
        return MS_FAILURE;
6651
      if (getDouble(&(map->extent.maxx), MS_NUM_CHECK_NONE, -1, -1) == -1)
2,852✔
6652
        return MS_FAILURE;
6653
      if (getDouble(&(map->extent.maxy), MS_NUM_CHECK_NONE, -1, -1) == -1)
2,852✔
6654
        return MS_FAILURE;
6655
      if (!MS_VALID_EXTENT(map->extent)) {
2,852✔
6656
        msSetError(MS_MISCERR,
×
6657
                   "Given map extent is invalid. Check that it "
6658
                   "is in the form: minx, miny, maxx, maxy",
6659
                   "loadMapInternal()");
6660
        return MS_FAILURE;
×
6661
      }
6662
    } break;
6663
    case (ANGLE): {
8✔
6664
      double rotation_angle;
6665
      if (getDouble(&(rotation_angle), MS_NUM_CHECK_RANGE, -360, 360) == -1)
8✔
6666
        return MS_FAILURE;
×
6667
      msMapSetRotation(map, rotation_angle);
8✔
6668
    } break;
8✔
6669
    case (FONTSET):
1,862✔
6670
      if (getString(&map->fontset.filename) == MS_FAILURE)
1,862✔
6671
        return MS_FAILURE;
6672
      break;
6673
    case (IMAGECOLOR):
2,059✔
6674
      if (loadColor(&(map->imagecolor), NULL) != MS_SUCCESS)
2,059✔
6675
        return MS_FAILURE;
6676
      break;
6677
    case (IMAGETYPE):
1,391✔
6678
      msFree(map->imagetype);
1,391✔
6679
      map->imagetype = getToken();
1,391✔
6680
      break;
1,391✔
6681
    case (LATLON):
×
6682
      if (loadProjection(&map->latlon) == -1)
×
6683
        return MS_FAILURE;
6684
      break;
6685
    case (LAYER):
12,743✔
6686
      if (msGrowMapLayers(map) == NULL)
12,743✔
6687
        return MS_FAILURE;
6688
      if (initLayer((GET_LAYER(map, map->numlayers)), map) == -1)
12,743✔
6689
        return MS_FAILURE;
6690
      if (loadLayer((GET_LAYER(map, map->numlayers)), map) == -1)
12,743✔
6691
        return MS_FAILURE;
6692
      GET_LAYER(map, map->numlayers)->index =
12,743✔
6693
          map->numlayers; /* save the index */
6694
      /* Update the layer order list with the layer's index. */
6695
      map->layerorder[map->numlayers] = map->numlayers;
12,743✔
6696
      map->numlayers++;
12,743✔
6697
      break;
12,743✔
6698
    case (OUTPUTFORMAT):
1,309✔
6699
      if (loadOutputFormat(map) == -1)
1,309✔
6700
        return MS_FAILURE;
6701
      break;
6702
    case (LEGEND):
479✔
6703
      if (loadLegend(&(map->legend), map) == -1)
479✔
6704
        return MS_FAILURE;
6705
      break;
6706
    case (MAP):
6707
      foundMapToken = MS_TRUE;
6708
      break;
6709
    case (MAXSIZE):
265✔
6710
      if (getInteger(&(map->maxsize), MS_NUM_CHECK_GT, 0, -1) == -1)
265✔
6711
        return MS_FAILURE;
6712
      break;
6713
    case (NAME):
2,602✔
6714
      free(map->name);
2,602✔
6715
      map->name = NULL; /* erase default */
2,602✔
6716
      if (getString(&map->name) == MS_FAILURE)
2,602✔
6717
        return MS_FAILURE;
6718
      break;
6719
    case (PROJECTION):
2,097✔
6720
      if (loadProjection(&map->projection) == -1)
2,097✔
6721
        return MS_FAILURE;
6722
      break;
6723
    case (QUERYMAP):
165✔
6724
      if (loadQueryMap(&(map->querymap), map) == -1)
165✔
6725
        return MS_FAILURE;
6726
      break;
6727
    case (REFERENCE):
×
6728
      if (loadReferenceMap(&(map->reference), map) == -1)
×
6729
        return MS_FAILURE;
6730
      break;
6731
    case (RESOLUTION):
10✔
6732
      if (getDouble(&(map->resolution), MS_NUM_CHECK_RANGE, MS_RESOLUTION_MIN,
10✔
6733
                    MS_RESOLUTION_MAX) == -1)
6734
        return MS_FAILURE;
6735
      break;
6736
    case (DEFRESOLUTION):
15✔
6737
      if (getDouble(&(map->defresolution), MS_NUM_CHECK_RANGE,
15✔
6738
                    MS_RESOLUTION_MIN, MS_RESOLUTION_MAX) == -1)
6739
        return MS_FAILURE;
6740
      break;
6741
    case (SCALE):
×
6742
    case (SCALEDENOM):
6743
      if (getDouble(&(map->scaledenom), MS_NUM_CHECK_GTE, 1, -1) == -1)
×
6744
        return MS_FAILURE;
6745
      break;
6746
    case (SCALEBAR):
414✔
6747
      if (loadScalebar(&(map->scalebar)) == -1)
414✔
6748
        return MS_FAILURE;
6749
      break;
6750
    case (SHAPEPATH):
1,788✔
6751
      if (getString(&map->shapepath) == MS_FAILURE)
1,788✔
6752
        return MS_FAILURE;
6753
      break;
6754
    case (SIZE):
2,882✔
6755
      if (getInteger(&(map->width), MS_NUM_CHECK_RANGE, 1, map->maxsize) == -1)
2,882✔
6756
        return MS_FAILURE;
6757
      if (getInteger(&(map->height), MS_NUM_CHECK_RANGE, 1, map->maxsize) == -1)
2,882✔
6758
        return MS_FAILURE;
6759
      break;
6760
    case (STATUS):
2,093✔
6761
      if ((map->status = getSymbol(2, MS_ON, MS_OFF)) == -1)
2,093✔
6762
        return MS_FAILURE;
6763
      break;
6764
    case (SYMBOL):
576✔
6765
      if (msGrowSymbolSet(&(map->symbolset)) == NULL)
576✔
6766
        return MS_FAILURE;
6767
      if ((loadSymbol(map->symbolset.symbol[map->symbolset.numsymbols],
576✔
6768
                      map->mappath) == -1)) {
6769
        msFreeSymbol(map->symbolset.symbol[map->symbolset.numsymbols]);
×
6770
        free(map->symbolset.symbol[map->symbolset.numsymbols]);
×
6771
        map->symbolset.symbol[map->symbolset.numsymbols] = NULL;
×
6772
        return MS_FAILURE;
×
6773
      }
6774
      map->symbolset.symbol[map->symbolset.numsymbols]->inmapfile = MS_TRUE;
576✔
6775
      map->symbolset.numsymbols++;
576✔
6776
      break;
576✔
6777
    case (SYMBOLSET):
1,583✔
6778
      if (getString(&map->symbolset.filename) == MS_FAILURE)
1,583✔
6779
        return MS_FAILURE;
6780
      break;
6781
    case (UNITS):
1,466✔
6782
      if ((int)(map->units =
1,466✔
6783
                    getSymbol(7, MS_INCHES, MS_FEET, MS_MILES, MS_METERS,
1,466✔
6784
                              MS_KILOMETERS, MS_NAUTICALMILES, MS_DD)) == -1)
6785
        return MS_FAILURE;
6786
      break;
6787
    case (WEB):
2,326✔
6788
      if (loadWeb(&(map->web), map) == -1)
2,326✔
6789
        return MS_FAILURE;
6790
      break;
6791
    default:
×
6792
      msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
6793
                 "msLoadMap()", msyystring_buffer, msyylineno);
6794
      return MS_FAILURE;
×
6795
    }
6796
  } /* next token */
6797
}
6798

6799
static bool msGetCWD(char *szBuffer, size_t nBufferSize,
3,015✔
6800
                     const char *pszFunctionName) {
6801
  if (NULL == getcwd(szBuffer, nBufferSize)) {
3,015✔
6802
#ifndef _WIN32
6803
    if (errno == EACCES)
×
6804
      msSetError(MS_MISCERR,
×
6805
                 "getcwd() failed with EACCES: you may need to force the "
6806
                 "current directory in the mapserver launcher "
6807
                 "(e.g -d option of spawn-fcgi)",
6808
                 pszFunctionName);
6809
    else if (errno == ENAMETOOLONG)
×
6810
      msSetError(MS_MISCERR, "getcwd() returned a too long path",
×
6811
                 pszFunctionName);
6812
    else
6813
      msSetError(MS_MISCERR, "getcwd() failed with errno code %d",
×
6814
                 pszFunctionName, errno);
6815
#else
6816
    msSetError(MS_MISCERR, "getcwd() returned a too long path",
6817
               pszFunctionName);
6818
#endif
6819
    return FALSE;
×
6820
  }
6821
  return TRUE;
6822
}
6823

6824
/*
6825
 * Apply any SLD styles referenced in a LAYER's STYLEITEM
6826
 */
6827
static void applyStyleItemToLayer(mapObj *map) {
3,011✔
6828

6829
  // applying SLD can create cloned layers so store the original layer count
6830
  int layerCount = map->numlayers;
3,011✔
6831

6832
  for (int i = 0; i < layerCount; i++) {
15,754✔
6833
    layerObj *layer = GET_LAYER(map, i);
12,743✔
6834

6835
    if (layer->styleitem && STARTS_WITH_CI(layer->styleitem, "sld://")) {
12,743✔
6836
      const char *filename = layer->styleitem + strlen("sld://");
120✔
6837

6838
      if (*filename == '\0') {
120✔
6839
        msSetError(MS_IOERR, "Empty SLD filename: \"%s\".",
×
6840
                   "applyLayerDefaultSubstitutions()", layer->styleitem);
6841
      } else {
6842
        msSLDApplyFromFile(map, layer, filename);
120✔
6843
      }
6844
    }
6845
  }
6846
}
3,011✔
6847

6848
/*
6849
** Sets up string-based mapfile loading and calls loadMapInternal to do the
6850
*work.
6851
*/
6852
mapObj *msLoadMapFromString(char *buffer, char *new_mappath,
3✔
6853
                            const configObj *config) {
6854
  mapObj *map;
6855
  struct mstimeval starttime = {0}, endtime = {0};
3✔
6856
  char szPath[MS_MAXPATHLEN], szCWDPath[MS_MAXPATHLEN];
6857
  char *mappath = NULL;
6858
  int debuglevel;
6859

6860
  debuglevel = (int)msGetGlobalDebugLevel();
3✔
6861

6862
  if (debuglevel >= MS_DEBUGLEVEL_TUNING) {
3✔
6863
    /* In debug mode, track time spent loading/parsing mapfile. */
6864
    msGettimeofday(&starttime, NULL);
×
6865
  }
6866

6867
  if (!buffer) {
3✔
6868
    msSetError(MS_MISCERR, "No buffer to load.", "msLoadMapFromString()");
×
6869
    return (NULL);
×
6870
  }
6871

6872
  /*
6873
  ** Allocate mapObj structure
6874
  */
6875
  map = (mapObj *)calloc(1, sizeof(mapObj));
3✔
6876
  MS_CHECK_ALLOC(map, sizeof(mapObj), NULL);
3✔
6877

6878
  if (initMap(map) == -1) { /* initialize this map */
3✔
6879
    msFreeMap(map);
×
6880
    return (NULL);
×
6881
  }
6882

6883
  map->config = config; // create a read-only reference
3✔
6884

6885
  msAcquireLock(TLOCK_PARSER); /* might need to move this lock a bit higher, yup
3✔
6886
                                  (bug 2108) */
6887

6888
  msyystate = MS_TOKENIZE_STRING;
3✔
6889
  msyystring = buffer;
3✔
6890
  msyylex(); /* sets things up, but doesn't process any tokens */
3✔
6891

6892
  msyylineno = 1; /* start at line 1 (do lines mean anything here?) */
3✔
6893

6894
  /* If new_mappath is provided then use it, otherwise use the CWD */
6895
  if (!msGetCWD(szCWDPath, MS_MAXPATHLEN, "msLoadMapFromString()")) {
3✔
6896
    msFreeMap(map);
×
6897
    msReleaseLock(TLOCK_PARSER);
×
6898
    return (NULL);
×
6899
  }
6900
  if (new_mappath) {
3✔
6901
    mappath = msStrdup(new_mappath);
×
6902
    map->mappath = msStrdup(msBuildPath(szPath, szCWDPath, mappath));
×
6903
  } else
6904
    map->mappath = msStrdup(szCWDPath);
3✔
6905

6906
  msyybasepath = map->mappath; /* for INCLUDEs */
3✔
6907

6908
  if (loadMapInternal(map) != MS_SUCCESS) {
3✔
6909
    msFreeMap(map);
×
6910
    msReleaseLock(TLOCK_PARSER);
×
6911
    if (mappath != NULL)
×
6912
      free(mappath);
×
6913
    return NULL;
×
6914
  }
6915

6916
  if (mappath != NULL)
3✔
6917
    free(mappath);
×
6918
  msyylex_destroy();
3✔
6919

6920
  msReleaseLock(TLOCK_PARSER);
3✔
6921

6922
  applyStyleItemToLayer(map);
3✔
6923

6924
  if (debuglevel >= MS_DEBUGLEVEL_TUNING) {
3✔
6925
    /* In debug mode, report time spent loading/parsing mapfile. */
6926
    msGettimeofday(&endtime, NULL);
×
6927
    msDebug("msLoadMapFromString(): %.3fs\n",
×
6928
            (endtime.tv_sec + endtime.tv_usec / 1.0e6) -
×
6929
                (starttime.tv_sec + starttime.tv_usec / 1.0e6));
×
6930
  }
6931

6932
  if (resolveSymbolNames(map) == MS_FAILURE)
3✔
6933
    return NULL;
×
6934

6935
  return map;
6936
}
6937

6938
/*
6939
** Sets up file-based mapfile loading and calls loadMapInternal to do the work.
6940
*/
6941
mapObj *msLoadMap(const char *filename, const char *new_mappath,
3,013✔
6942
                  const configObj *config) {
6943
  mapObj *map;
6944
  struct mstimeval starttime = {0}, endtime = {0};
3,013✔
6945
  char szPath[MS_MAXPATHLEN], szCWDPath[MS_MAXPATHLEN];
6946
  int debuglevel;
6947

6948
  debuglevel = (int)msGetGlobalDebugLevel();
3,013✔
6949

6950
  if (debuglevel >= MS_DEBUGLEVEL_TUNING) {
3,013✔
6951
    /* In debug mode, track time spent loading/parsing mapfile. */
6952
    msGettimeofday(&starttime, NULL);
×
6953
  }
6954

6955
  if (!filename) {
3,013✔
6956
    msSetError(MS_MISCERR, "Filename is undefined.", "msLoadMap()");
×
6957
    return (NULL);
×
6958
  }
6959

6960
  const char *ms_mapfile_pattern =
6961
      CPLGetConfigOption("MS_MAPFILE_PATTERN", MS_DEFAULT_MAPFILE_PATTERN);
3,013✔
6962
  if (msEvalRegex(ms_mapfile_pattern, filename) != MS_TRUE) {
3,013✔
6963
    msSetError(MS_REGEXERR, "Filename validation failed.", "msLoadMap()");
×
6964
    return (NULL);
×
6965
  }
6966

6967
  /*
6968
  ** Allocate mapObj structure
6969
  */
6970
  map = (mapObj *)calloc(1, sizeof(mapObj));
3,013✔
6971
  MS_CHECK_ALLOC(map, sizeof(mapObj), NULL);
3,013✔
6972

6973
  if (initMap(map) == -1) { /* initialize this map */
3,013✔
6974
    msFreeMap(map);
×
6975
    return (NULL);
×
6976
  }
6977

6978
  map->config = config; // create a read-only reference
3,013✔
6979

6980
  msAcquireLock(TLOCK_PARSER); /* Steve: might need to move this lock a bit
3,013✔
6981
                                  higher; Umberto: done */
6982

6983
#ifdef USE_XMLMAPFILE
6984
  /* If the mapfile is an xml mapfile, transform it */
6985
  const char *ms_xmlmapfile_xslt =
6986
      CPLGetConfigOption("MS_XMLMAPFILE_XSLT", NULL);
6987
  if (ms_xmlmapfile_xslt &&
6988
      (msEvalRegex(MS_DEFAULT_XMLMAPFILE_PATTERN, filename) == MS_TRUE)) {
6989

6990
    msyyin = tmpfile();
6991
    if (msyyin == NULL) {
6992
      msSetError(MS_IOERR, "tmpfile() failed to create temporary file",
6993
                 "msLoadMap()");
6994
      msReleaseLock(TLOCK_PARSER);
6995
      msFreeMap(map);
6996
      return NULL;
6997
    }
6998

6999
    if (msTransformXmlMapfile(ms_xmlmapfile_xslt, filename, msyyin) !=
7000
        MS_SUCCESS) {
7001
      fclose(msyyin);
7002
      msFreeMap(map);
7003
      return NULL;
7004
    }
7005
    fseek(msyyin, 0, SEEK_SET);
7006
  } else {
7007
#endif
7008
    if ((msyyin = fopen(filename, "r")) == NULL) {
3,013✔
7009
      msSetError(MS_IOERR, "(%s)", "msLoadMap()", filename);
1✔
7010
      msReleaseLock(TLOCK_PARSER);
1✔
7011
      msFreeMap(map);
1✔
7012
      return NULL;
1✔
7013
    }
7014
#ifdef USE_XMLMAPFILE
7015
  }
7016
#endif
7017

7018
  msyystate = MS_TOKENIZE_FILE;
3,012✔
7019
  msyylex(); /* sets things up, but doesn't process any tokens */
3,012✔
7020

7021
  msyyrestart(msyyin); /* start at line beginning, line 1 */
3,012✔
7022
  msyylineno = 1;
3,012✔
7023

7024
  /* If new_mappath is provided then use it, otherwise use the location */
7025
  /* of the mapfile as the default path */
7026
  if (!msGetCWD(szCWDPath, MS_MAXPATHLEN, "msLoadMap()")) {
3,012✔
7027
    msReleaseLock(TLOCK_PARSER);
×
7028
    msFreeMap(map);
×
7029
    return NULL;
×
7030
  }
7031

7032
  if (new_mappath)
3,012✔
7033
    map->mappath = msStrdup(msBuildPath(szPath, szCWDPath, new_mappath));
×
7034
  else {
7035
    char *path = msGetPath(filename);
3,012✔
7036
    map->mappath = msStrdup(msBuildPath(szPath, szCWDPath, path));
3,012✔
7037
    free(path);
3,012✔
7038
  }
7039

7040
  msyybasepath = map->mappath; /* for INCLUDEs */
3,012✔
7041

7042
  if (loadMapInternal(map) != MS_SUCCESS) {
3,012✔
7043
    msFreeMap(map);
4✔
7044
    if (msyyin) {
4✔
7045
      msyycleanup_includes();
4✔
7046
      fclose(msyyin);
4✔
7047
      msyyin = NULL;
4✔
7048
    }
7049
    msReleaseLock(TLOCK_PARSER);
4✔
7050
    return NULL;
4✔
7051
  }
7052
  msReleaseLock(TLOCK_PARSER);
3,008✔
7053

7054
  applyStyleItemToLayer(map);
3,008✔
7055

7056
  if (debuglevel >= MS_DEBUGLEVEL_TUNING) {
3,008✔
7057
    /* In debug mode, report time spent loading/parsing mapfile. */
7058
    msGettimeofday(&endtime, NULL);
×
7059
    msDebug("msLoadMap(): %.3fs\n",
×
7060
            (endtime.tv_sec + endtime.tv_usec / 1.0e6) -
×
7061
                (starttime.tv_sec + starttime.tv_usec / 1.0e6));
×
7062
  }
7063

7064
  return map;
7065
}
7066

7067
static void hashTableSubstituteString(hashTableObj *hash, const char *from,
238✔
7068
                                      const char *to) {
7069
  const char *key, *val;
7070
  char *new_val;
7071
  key = msFirstKeyFromHashTable(hash);
238✔
7072
  while (key != NULL) {
311✔
7073
    val = msLookupHashTable(hash, key);
73✔
7074
    if (strcasestr(val, from)) {
73✔
7075
      new_val = msCaseReplaceSubstring(msStrdup(val), from, to);
15✔
7076
      msInsertHashTable(hash, key, new_val);
15✔
7077
      msFree(new_val);
15✔
7078
    }
7079
    key = msNextKeyFromHashTable(hash, key);
73✔
7080
  }
7081
}
238✔
7082

7083
static void classSubstituteString(classObj *class, const char *from,
164✔
7084
                                  const char *to) {
7085
  if (class->expression.string)
164✔
7086
    class->expression.string =
16✔
7087
        msCaseReplaceSubstring(class->expression.string, from, to);
16✔
7088
  if (class->text.string)
164✔
7089
    class->text.string = msCaseReplaceSubstring(class->text.string, from, to);
×
7090
  if (class->title)
164✔
7091
    class->title = msCaseReplaceSubstring(class->title, from, to);
×
7092
}
164✔
7093

7094
static void layerSubstituteString(layerObj *layer, const char *from,
114✔
7095
                                  const char *to) {
7096
  int c;
7097
  if (layer->data)
114✔
7098
    layer->data = msCaseReplaceSubstring(layer->data, from, to);
112✔
7099
  if (layer->tileindex)
114✔
7100
    layer->tileindex = msCaseReplaceSubstring(layer->tileindex, from, to);
×
7101
  if (layer->connection)
114✔
7102
    layer->connection = msCaseReplaceSubstring(layer->connection, from, to);
10✔
7103
  if (layer->filter.string)
114✔
7104
    layer->filter.string =
2✔
7105
        msCaseReplaceSubstring(layer->filter.string, from, to);
2✔
7106
  if (layer->mask)
114✔
7107
    layer->mask = msCaseReplaceSubstring(layer->mask, from, to); // new for 8.0
×
7108

7109
  /* The bindvalues are most useful when able to substitute values from the URL
7110
   */
7111
  hashTableSubstituteString(&layer->bindvals, from, to);
114✔
7112
  hashTableSubstituteString(&layer->metadata, from, to);
114✔
7113
  msLayerSubstituteProcessing(layer, from, to);
114✔
7114
  for (c = 0; c < layer->numclasses; c++) {
234✔
7115
    classSubstituteString(layer->class[c], from, to);
120✔
7116
  }
7117
}
114✔
7118

7119
static void mapSubstituteString(mapObj *map, const char *from, const char *to) {
6✔
7120
  int l;
7121
  for (l = 0; l < map->numlayers; l++) {
44✔
7122
    layerSubstituteString(GET_LAYER(map, l), from, to);
38✔
7123
  }
7124

7125
  /* output formats (#3751) */
7126
  for (l = 0; l < map->numoutputformats; l++) {
13✔
7127
    int o;
7128
    for (o = 0; o < map->outputformatlist[l]->numformatoptions; o++) {
13✔
7129
      map->outputformatlist[l]->formatoptions[o] = msCaseReplaceSubstring(
6✔
7130
          map->outputformatlist[l]->formatoptions[o], from, to);
6✔
7131
    }
7132
  }
7133

7134
  hashTableSubstituteString(&map->web.metadata, from, to);
6✔
7135
  if (map->web.template)
6✔
7136
    map->web.template = msCaseReplaceSubstring(map->web.template, from, to);
×
7137
}
6✔
7138

7139
static void applyOutputFormatDefaultSubstitutions(outputFormatObj *format,
6,938✔
7140
                                                  const char *option,
7141
                                                  hashTableObj *table) {
7142
  const char *filename;
7143

7144
  filename = msGetOutputFormatOption(format, option, NULL);
6,938✔
7145
  if (filename && strlen(filename) > 0) {
6,938✔
7146
    char *tmpfilename = msStrdup(filename);
490✔
7147
    const char *default_key = msFirstKeyFromHashTable(table);
490✔
7148
    while (default_key) {
502✔
7149
      if (!strncasecmp(default_key, "default_", 8)) {
12✔
7150
        char *new_filename = NULL;
7151
        size_t buffer_size = (strlen(default_key) - 5);
6✔
7152
        char *tag = (char *)msSmallMalloc(buffer_size);
6✔
7153
        snprintf(tag, buffer_size, "%%%s%%", &(default_key[8]));
6✔
7154

7155
        new_filename = msStrdup(tmpfilename);
6✔
7156
        new_filename = msCaseReplaceSubstring(
6✔
7157
            new_filename, tag, msLookupHashTable(table, default_key));
7158
        free(tag);
6✔
7159

7160
        msSetOutputFormatOption(format, option, new_filename);
6✔
7161
        free(new_filename);
6✔
7162
      }
7163
      default_key = msNextKeyFromHashTable(table, default_key);
12✔
7164
    }
7165
    msFree(tmpfilename);
490✔
7166
  }
7167
  return;
6,938✔
7168
}
7169

7170
static void applyClassDefaultSubstitutions(classObj *class,
11,477✔
7171
                                           hashTableObj *table) {
7172
  const char *default_key = msFirstKeyFromHashTable(table);
11,477✔
7173
  while (default_key) {
11,490✔
7174
    if (!strncasecmp(default_key, "default_", 8)) {
13✔
7175
      size_t buffer_size = (strlen(default_key) - 5);
×
7176
      char *tag = (char *)msSmallMalloc(buffer_size);
×
7177
      snprintf(tag, buffer_size, "%%%s%%", &(default_key[8]));
×
7178

7179
      classSubstituteString(class, tag, msLookupHashTable(table, default_key));
×
7180
      free(tag);
×
7181
    }
7182
    default_key = msNextKeyFromHashTable(table, default_key);
13✔
7183
  }
7184
  return;
11,477✔
7185
}
7186

7187
static void applyLayerDefaultSubstitutions(layerObj *layer,
19,174✔
7188
                                           hashTableObj *table) {
7189
  int i;
7190
  const char *default_key = msFirstKeyFromHashTable(table);
19,174✔
7191
  while (default_key) {
20,036✔
7192
    if (!strncasecmp(default_key, "default_", 8)) {
862✔
7193
      size_t buffer_size = (strlen(default_key) - 5);
42✔
7194
      const char *to = msLookupHashTable(table, default_key);
42✔
7195
      char *tag = (char *)msSmallMalloc(buffer_size);
42✔
7196
      snprintf(tag, buffer_size, "%%%s%%", &(default_key[8]));
42✔
7197

7198
      for (i = 0; i < layer->numclasses; i++) {
84✔
7199
        classSubstituteString(layer->class[i], tag, to);
42✔
7200
      }
7201
      layerSubstituteString(layer, tag, to);
42✔
7202
      free(tag);
42✔
7203
    }
7204
    default_key = msNextKeyFromHashTable(table, default_key);
862✔
7205
  }
7206

7207
  return;
19,174✔
7208
}
7209

7210
static void applyHashTableDefaultSubstitutions(hashTableObj *hashTab,
2,526✔
7211
                                               hashTableObj *table) {
7212
  const char *default_key = msFirstKeyFromHashTable(table);
2,526✔
7213
  while (default_key) {
2,621✔
7214
    if (!strncasecmp(default_key, "default_", 8)) {
95✔
7215
      size_t buffer_size = (strlen(default_key) - 5);
4✔
7216
      const char *to = msLookupHashTable(table, default_key);
4✔
7217
      char *tag = (char *)msSmallMalloc(buffer_size);
4✔
7218
      snprintf(tag, buffer_size, "%%%s%%", &(default_key[8]));
4✔
7219

7220
      hashTableSubstituteString(hashTab, tag, to);
4✔
7221
      free(tag);
4✔
7222
    }
7223
    default_key = msNextKeyFromHashTable(table, default_key);
95✔
7224
  }
7225
  return;
2,526✔
7226
}
7227

7228
/*
7229
** Loop through layer metadata for keys that have a default_%key% pattern to
7230
*replace
7231
** remaining %key% entries by their default value.
7232
*/
7233
void msApplyDefaultSubstitutions(mapObj *map) {
2,526✔
7234
  int i, j;
7235

7236
  /* output formats (#3751) */
7237
  for (i = 0; i < map->numoutputformats; i++) {
5,995✔
7238
    applyOutputFormatDefaultSubstitutions(map->outputformatlist[i], "filename",
3,469✔
7239
                                          &(map->web.validation));
7240
    applyOutputFormatDefaultSubstitutions(map->outputformatlist[i], "JSONP",
3,469✔
7241
                                          &(map->web.validation));
7242
  }
7243

7244
  for (i = 0; i < map->numlayers; i++) {
12,113✔
7245
    layerObj *layer = GET_LAYER(map, i);
9,587✔
7246

7247
    for (j = 0; j < layer->numclasses;
21,064✔
7248
         j++) { /* class settings take precedence...  */
11,477✔
7249
      classObj *class = GET_CLASS(map, i, j);
11,477✔
7250
      applyClassDefaultSubstitutions(class, &(class->validation));
11,477✔
7251
    }
7252

7253
    applyLayerDefaultSubstitutions(
9,587✔
7254
        layer, &(layer->validation)); /* ...then layer settings... */
7255
    applyLayerDefaultSubstitutions(
9,587✔
7256
        layer, &(map->web.validation)); /* ...and finally web settings */
7257
  }
7258
  applyHashTableDefaultSubstitutions(&map->web.metadata,
2,526✔
7259
                                     &(map->web.validation));
7260
}
2,526✔
7261

7262
char *_get_param_value(const char *key, char **names, char **values,
439✔
7263
                       int npairs) {
7264
  if (npairs <= 0)
439✔
7265
    return NULL; // bail, no point searching
7266

7267
  if (getenv(key)) { /* environment override */
433✔
7268
    return getenv(key);
1✔
7269
  }
7270
  while (npairs) {
2,321✔
7271
    npairs--;
1,933✔
7272
    if (strcasecmp(key, names[npairs]) == 0) {
1,933✔
7273
      return values[npairs];
44✔
7274
    }
7275
  }
7276
  return NULL;
7277
}
7278

7279
void msApplySubstitutions(mapObj *map, char **names, char **values,
1,937✔
7280
                          int npairs) {
7281
  int l;
7282
  const char *key, *value, *validation;
7283
  char *tag;
7284
  for (l = 0; l < map->numlayers; l++) {
9,900✔
7285
    int c;
7286
    layerObj *lp = GET_LAYER(map, l);
7,963✔
7287
    for (c = 0; c < lp->numclasses; c++) {
17,797✔
7288
      classObj *cp = lp->class[c];
9,834✔
7289
      key = NULL;
7290
      while ((key = msNextKeyFromHashTable(&cp->validation, key))) {
9,847✔
7291
        value = _get_param_value(key, names, values, npairs);
13✔
7292
        if (!value)
13✔
7293
          continue; /*parameter was not in url*/
11✔
7294
        validation = msLookupHashTable(&cp->validation, key);
2✔
7295
        if (msEvalRegex(validation, value)) {
2✔
7296
          /* we've found a substitution and it validates correctly, now let's
7297
           * apply it */
7298
          tag = msSmallMalloc(strlen(key) + 3);
2✔
7299
          sprintf(tag, "%%%s%%", key);
7300
          classSubstituteString(cp, tag, value);
2✔
7301
          free(tag);
2✔
7302
        } else {
7303
          msSetError(MS_REGEXERR, "Parameter pattern validation failed.",
×
7304
                     "msApplySubstitutions()");
7305
          if (map->debug || lp->debug) {
×
7306
            msDebug("layer (%s), class %d: failed to validate (%s=%s) for "
×
7307
                    "regex (%s)\n",
7308
                    lp->name, c, key, value, validation);
7309
          }
7310
        }
7311
      }
7312
    }
7313
    key = NULL;
7314
    while ((key = msNextKeyFromHashTable(&lp->validation, key))) {
8,294✔
7315
      value = _get_param_value(key, names, values, npairs);
331✔
7316
      if (!value)
331✔
7317
        continue; /*parameter was not in url*/
296✔
7318
      validation = msLookupHashTable(&lp->validation, key);
35✔
7319
      if (msEvalRegex(validation, value)) {
35✔
7320
        /* we've found a substitution and it validates correctly, now let's
7321
         * apply it */
7322
        tag = msSmallMalloc(strlen(key) + 3);
34✔
7323
        sprintf(tag, "%%%s%%", key);
7324
        layerSubstituteString(lp, tag, value);
34✔
7325
        free(tag);
34✔
7326
      } else {
7327
        msSetError(MS_REGEXERR, "Parameter pattern validation failed.",
1✔
7328
                   "msApplySubstitutions()");
7329
        if (map->debug || lp->debug) {
1✔
7330
          msDebug("layer (%s): failed to validate (%s=%s) for regex (%s)\n",
×
7331
                  lp->name, key, value, validation);
7332
        }
7333
      }
7334
    }
7335
  }
7336
  key = NULL;
7337
  while ((key = msNextKeyFromHashTable(&map->web.validation, key))) {
2,032✔
7338
    value = _get_param_value(key, names, values, npairs);
95✔
7339
    if (!value)
95✔
7340
      continue; /*parameter was not in url*/
87✔
7341
    validation = msLookupHashTable(&map->web.validation, key);
8✔
7342
    if (msEvalRegex(validation, value)) {
8✔
7343
      /* we've found a substitution and it validates correctly, now let's apply
7344
       * it */
7345
      tag = msSmallMalloc(strlen(key) + 3);
6✔
7346
      sprintf(tag, "%%%s%%", key);
7347
      mapSubstituteString(map, tag, value);
6✔
7348
      free(tag);
6✔
7349
    } else {
7350
      msSetError(MS_REGEXERR, "Parameter pattern validation failed.",
2✔
7351
                 "msApplySubstitutions()");
7352
      if (map->debug) {
2✔
7353
        msDebug("failed to validate (%s=%s) for regex (%s)\n", key, value,
×
7354
                validation);
7355
      }
7356
    }
7357
  }
7358
}
1,937✔
7359

7360
/*
7361
** Returns an array with one entry per mapfile token.  Useful to manipulate
7362
** mapfiles in MapScript.
7363
**
7364
** The returned array should be freed using msFreeCharArray().
7365
*/
7366
static char **tokenizeMapInternal(char *filename, int *ret_numtokens) {
×
7367
  char **tokens = NULL;
7368
  int numtokens = 0, numtokens_allocated = 0;
7369
  size_t buffer_size = 0;
7370

7371
  *ret_numtokens = 0;
×
7372

7373
  if (!filename) {
×
7374
    msSetError(MS_MISCERR, "Filename is undefined.", "msTokenizeMap()");
×
7375
    return NULL;
×
7376
  }
7377

7378
  /*
7379
  ** Check map filename to make sure it's legal
7380
  */
7381
  const char *ms_mapfile_pattern =
7382
      CPLGetConfigOption("MS_MAPFILE_PATTERN", MS_DEFAULT_MAPFILE_PATTERN);
×
7383
  if (msEvalRegex(ms_mapfile_pattern, filename) != MS_TRUE) {
×
7384
    msSetError(MS_REGEXERR, "Filename validation failed.", "msTokenizeMap()");
×
7385
    return (NULL);
×
7386
  }
7387

7388
  if ((msyyin = fopen(filename, "r")) == NULL) {
×
7389
    msSetError(MS_IOERR, "(%s)", "msTokenizeMap()", filename);
×
7390
    return NULL;
×
7391
  }
7392

7393
  msyystate = MS_TOKENIZE_FILE; /* restore lexer state to INITIAL, and do return
×
7394
                                   comments */
7395
  msyylex();
×
7396
  msyyreturncomments = 1; /* want all tokens, including comments */
×
7397

7398
  msyyrestart(msyyin); /* start at line beginning, line 1 */
×
7399
  msyylineno = 1;
×
7400

7401
  numtokens = 0;
7402
  numtokens_allocated = 256;
7403
  tokens = (char **)malloc(numtokens_allocated * sizeof(char *));
×
7404
  if (tokens == NULL) {
×
7405
    msSetError(MS_MEMERR, NULL, "msTokenizeMap()");
×
7406
    fclose(msyyin);
×
7407
    return NULL;
×
7408
  }
7409

7410
  for (;;) {
7411

7412
    if (numtokens_allocated <= numtokens) {
×
7413
      numtokens_allocated *=
×
7414
          2; /* double size of the array every time we reach the limit */
7415
      char **tokensNew =
7416
          (char **)realloc(tokens, numtokens_allocated * sizeof(char *));
×
7417
      if (tokensNew == NULL) {
×
7418
        msSetError(MS_MEMERR, "Realloc() error.", "msTokenizeMap()");
×
7419
        fclose(msyyin);
×
7420
        for (int i = 0; i < numtokens; i++)
×
7421
          msFree(tokens[i]);
×
7422
        msFree(tokens);
×
7423
        return NULL;
×
7424
      }
7425
      tokens = tokensNew;
7426
    }
7427

7428
    switch (msyylex()) {
×
7429
    case (EOF): /* This is the normal way out... cleanup and exit */
×
7430
      fclose(msyyin);
×
7431
      *ret_numtokens = numtokens;
×
7432
      return (tokens);
×
7433
      break;
7434
    case (MS_STRING):
×
7435
      buffer_size = strlen(msyystring_buffer) + 2 + 1;
×
7436
      tokens[numtokens] = (char *)msSmallMalloc(buffer_size);
×
7437
      snprintf(tokens[numtokens], buffer_size, "\"%s\"", msyystring_buffer);
×
7438
      break;
7439
    case (MS_EXPRESSION):
×
7440
      buffer_size = strlen(msyystring_buffer) + 2 + 1;
×
7441
      tokens[numtokens] = (char *)msSmallMalloc(buffer_size);
×
7442
      snprintf(tokens[numtokens], buffer_size, "(%s)", msyystring_buffer);
×
7443
      break;
7444
    case (MS_REGEX):
×
7445
      buffer_size = strlen(msyystring_buffer) + 2 + 1;
×
7446
      tokens[numtokens] = (char *)msSmallMalloc(buffer_size);
×
7447
      snprintf(tokens[numtokens], buffer_size, "/%s/", msyystring_buffer);
×
7448
      break;
7449
    default:
×
7450
      tokens[numtokens] = msStrdup(msyystring_buffer);
×
7451
      break;
×
7452
    }
7453

7454
    if (tokens[numtokens] == NULL) {
×
7455
      int i;
7456
      msSetError(MS_MEMERR, NULL, "msTokenizeMap()");
×
7457
      fclose(msyyin);
×
7458
      for (i = 0; i < numtokens; i++)
×
7459
        msFree(tokens[i]);
×
7460
      msFree(tokens);
×
7461
      return NULL;
×
7462
    }
7463

7464
    numtokens++;
×
7465
  }
7466

7467
  return NULL; /* should never get here */
7468
}
7469

7470
/*
7471
** Wraps tokenizeMapInternal
7472
*/
7473
char **msTokenizeMap(char *filename, int *numtokens) {
×
7474
  char **tokens;
7475

7476
  msAcquireLock(TLOCK_PARSER);
×
7477
  tokens = tokenizeMapInternal(filename, numtokens);
×
7478
  msReleaseLock(TLOCK_PARSER);
×
7479

7480
  return tokens;
×
7481
}
7482

7483
void msCloseConnections(mapObj *map) {
3,099✔
7484
  int i;
7485
  layerObj *lp;
7486

7487
  for (i = 0; i < map->numlayers; i++) {
16,216✔
7488
    lp = (GET_LAYER(map, i));
13,117✔
7489

7490
    /* If the vtable is null, then the layer is never accessed or used -> skip
7491
     * it
7492
     */
7493
    if (lp->vtable) {
13,117✔
7494
      lp->vtable->LayerCloseConnection(lp);
3,324✔
7495
    }
7496
  }
7497
}
3,099✔
7498

7499
void initResultCache(resultCacheObj *resultcache) {
1,825✔
7500
  if (resultcache) {
1,825✔
7501
    resultcache->results = NULL;
1,825✔
7502
    resultcache->numresults = 0;
1,825✔
7503
    resultcache->cachesize = 0;
1,825✔
7504
    resultcache->bounds.minx = resultcache->bounds.miny =
1,825✔
7505
        resultcache->bounds.maxx = resultcache->bounds.maxy = -1;
1,825✔
7506
    resultcache->previousBounds = resultcache->bounds;
1,825✔
7507
  }
7508
}
1,825✔
7509

7510
void cleanupResultCache(resultCacheObj *resultcache) {
941✔
7511
  if (resultcache) {
941✔
7512
    if (resultcache->results) {
941✔
7513
      int i;
7514
      for (i = 0; i < resultcache->numresults; i++) {
4,957✔
7515
        if (resultcache->results[i].shape) {
4,242✔
7516
          msFreeShape(resultcache->results[i].shape);
12✔
7517
          msFree(resultcache->results[i].shape);
12✔
7518
        }
7519
      }
7520
      free(resultcache->results);
715✔
7521
    }
7522
    resultcache->results = NULL;
941✔
7523
    initResultCache(resultcache);
941✔
7524
  }
7525
}
941✔
7526

7527
static int resolveSymbolNames(mapObj *map) {
7528
  int i, j;
7529

7530
  /* step through layers and classes to resolve symbol names */
7531
  for (i = 0; i < map->numlayers; i++) {
7532
    for (j = 0; j < GET_LAYER(map, i)->numclasses; j++) {
7533
      if (classResolveSymbolNames(GET_LAYER(map, i)->class[j]) != MS_SUCCESS)
7534
        return MS_FAILURE;
7535
    }
7536
  }
7537

7538
  return MS_SUCCESS;
7539
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc