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

geographika / mapserver / 17709373190

14 Sep 2025 09:32AM UTC coverage: 41.466% (+0.09%) from 41.375%
17709373190

push

github

geographika
Add index templates

62086 of 149729 relevant lines covered (41.47%)

25036.08 hits per line

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

68.33
/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,
26✔
106
                        const char *pattern2, const char *pattern3,
107
                        const char *pattern4) {
108
  if (msEvalRegex(pattern1, value) == MS_TRUE)
26✔
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,825✔
121
  ms_regex_t re;
122
  int errcode = ms_regcomp(&re, e, MS_REG_EXTENDED | MS_REG_NOSUB);
1,825✔
123
  if (errcode != 0) {
1,825✔
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,825✔
131
  return MS_TRUE;
1,825✔
132
}
133

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

137
  if (!e || !s)
7,058✔
138
    return (MS_FALSE);
139

140
  int errcode = ms_regcomp(&re, e, MS_REG_EXTENDED | MS_REG_NOSUB);
7,048✔
141
  if (errcode != 0) {
7,048✔
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 */
7,047✔
150
    ms_regfree(&re);
1,832✔
151
    return (MS_FALSE);
1,832✔
152
  }
153
  ms_regfree(&re);
5,215✔
154

155
  return (MS_TRUE);
5,215✔
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) {
133,124✔
190
  int i;
191
  if (!array)
133,124✔
192
    return;
193
  for (i = 0; i < num_items; i++)
519,981✔
194
    msFree(array[i]);
403,124✔
195
  msFree(array);
116,857✔
196
}
197

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

207
  symbol = msyylex();
118,221✔
208

209
  va_start(argp, n);
118,221✔
210
  while (i < n) { /* check each symbol in the list */
188,024✔
211
    if (symbol == va_arg(argp, int)) {
188,024✔
212
      va_end(argp);
118,221✔
213
      return (symbol);
118,221✔
214
    }
215
    i++;
69,803✔
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,788✔
229
  int symbol;
230
  va_list argp;
231
  int i = 0;
232

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

235
  va_start(argp, n);
2,788✔
236
  while (i < n) { /* check each symbol in the list */
2,880✔
237
    if (symbol == va_arg(argp, int)) {
2,863✔
238
      va_end(argp);
2,771✔
239
      return (symbol);
2,771✔
240
    }
241
    i++;
92✔
242
  }
243

244
  va_end(argp);
17✔
245
  return (-1);
17✔
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();
757✔
254
  return msStrdup(msyystring_buffer);
3,509✔
255
}
256

257
/*
258
** Load a string from the map file. A "string" is defined in lexer.l.
259
*/
260
int getString(char **s) {
168,173✔
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) {
168,173✔
265
    if (*s)
168,173✔
266
      free(*s); /* avoid leak */
3,095✔
267
    *s = msStrdup(msyystring_buffer);
168,173✔
268
    return (MS_SUCCESS);
168,173✔
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,
149,998✔
277
                  double value2) {
278
  if (num_check_type == MS_NUM_CHECK_NONE) {
149,998✔
279
    return MS_SUCCESS;
280
  } else if (num_check_type == MS_NUM_CHECK_RANGE && number >= value1 &&
77,348✔
281
             number <= value2) {
282
    return MS_SUCCESS;
283
  } else if (num_check_type == MS_NUM_CHECK_GT && number > value1) {
17,203✔
284
    return MS_SUCCESS;
285
  } else if (num_check_type == MS_NUM_CHECK_GTE && number >= value1) {
8,506✔
286
    return MS_SUCCESS;
8,506✔
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) {
72,897✔
296
  if (msyylex() == MS_NUMBER) {
72,897✔
297
    if (msCheckNumber(msyynumber, num_check_type, value1, value2) ==
72,897✔
298
        MS_SUCCESS) {
299
      *d = msyynumber;
72,897✔
300
      return (0);
72,897✔
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,709✔
313
  if (msyylex() == MS_NUMBER) {
60,709✔
314
    if (msCheckNumber(msyynumber, num_check_type, value1, value2) ==
60,709✔
315
        MS_SUCCESS) {
316
      *i = (int)msyynumber;
60,709✔
317
      return (0);
60,709✔
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,169✔
409
                     int try_addimage_if_notfound) {
410
  int i;
411

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

415
  /* symbol 0 has no name */
416
  for (i = 1; i < symbols->numsymbols; i++) {
8,742✔
417
    if (symbols->symbol[i]->name)
8,442✔
418
      if (strcasecmp(symbols->symbol[i]->name, name) == 0)
8,277✔
419
        return (i);
2,869✔
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,129✔
433
  int i;
434

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

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

447
int loadColor(colorObj *color, attributeBindingObj *binding) {
24,448✔
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,448✔
458
    if ((symbol = getSymbol(3, MS_NUMBER, MS_BINDING, MS_STRING)) == -1)
20,418✔
459
      return MS_FAILURE;
460
  } else {
461
    if ((symbol = getSymbol(2, MS_NUMBER, MS_STRING)) == -1)
4,030✔
462
      return MS_FAILURE;
463
  }
464

465
  color->alpha = 255;
24,448✔
466
  if (symbol == MS_NUMBER) {
24,448✔
467
    if (msyynumber >= -255 && msyynumber <= 255) {
24,053✔
468
      color->red = (int)msyynumber;
24,053✔
469
    } else {
470
      return MS_FAILURE;
471
    }
472
    if (getInteger(&(color->green), MS_NUM_CHECK_RANGE, -255, 255) == -1)
24,053✔
473
      return MS_FAILURE;
474
    if (getInteger(&(color->blue), MS_NUM_CHECK_RANGE, -255, 255) == -1)
24,053✔
475
      return MS_FAILURE;
476
  } else if (symbol == MS_STRING) {
395✔
477
    int len = strlen(msyystring_buffer);
372✔
478
    if (msyystring_buffer[0] == '#' &&
372✔
479
        (len == 7 || len == 9)) { /* got a hex color w/optional alpha */
372✔
480
      hex[0] = msyystring_buffer[1];
372✔
481
      hex[1] = msyystring_buffer[2];
372✔
482
      color->red = msHexToInt(hex);
372✔
483
      hex[0] = msyystring_buffer[3];
372✔
484
      hex[1] = msyystring_buffer[4];
372✔
485
      color->green = msHexToInt(hex);
372✔
486
      hex[0] = msyystring_buffer[5];
372✔
487
      hex[1] = msyystring_buffer[6];
372✔
488
      color->blue = msHexToInt(hex);
372✔
489
      if (len == 9) {
372✔
490
        hex[0] = msyystring_buffer[7];
41✔
491
        hex[1] = msyystring_buffer[8];
41✔
492
        color->alpha = msHexToInt(hex);
41✔
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);
23✔
503
    binding->item = msStrdup(msyystring_buffer);
23✔
504
    binding->index = -1;
23✔
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,
128✔
588
                         int size, ...) {
589
  va_list argp;
590
  int i, j = 0;
591
  const char *s;
592

593
  va_start(argp, size);
128✔
594
  while (j < size) { /* check each value/keyword mapping in the list, values
537✔
595
                        with no match are ignored */
596
    i = va_arg(argp, int);
448✔
597
    s = va_arg(argp, const char *);
448✔
598
    if (value == i) {
448✔
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++;
409✔
605
  }
606
  va_end(argp);
89✔
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))
10✔
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,163✔
949
                                        shapeObj *shape) {
950
  featureListNodeObjPtr node;
951

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

954
  msInitShape(&(node->shape));
3,163✔
955
  if (msCopyShape(shape, &(node->shape)) == -1) {
3,163✔
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,163✔
966
  node->next = NULL;
3,163✔
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,163✔
971
    *list = node;
2,472✔
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,163✔
983

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

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

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

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

1008
  while (ret < 0) {
2,787✔
1009
    switch (msyylex()) {
7,168✔
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):
4,381✔
1018
      if (points->numpoints == buffer_size) { /* just add it to the end */
4,381✔
1019
        pointObj *newPoints = (pointObj *)realloc(
48✔
1020
            points->point,
48✔
1021
            sizeof(pointObj) * (buffer_size + MS_FEATUREINCREMENT));
48✔
1022
        if (newPoints == NULL) {
48✔
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;
48✔
1031
        buffer_size += MS_FEATUREINCREMENT;
1032
      }
1033

1034
      points->point[points->numpoints].x = atof(msyystring_buffer);
4,381✔
1035
      if (getDouble(&(points->point[points->numpoints].y), MS_NUM_CHECK_NONE,
4,381✔
1036
                    -1, -1) == -1) {
1037
        ret = MS_FAILURE;
1038
        break;
1039
      }
1040
      points->numpoints++;
4,381✔
1041
      break;
4,381✔
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) {
2,787✔
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,799✔
1059
  int status = MS_SUCCESS;
1060
  featureListNodeObjPtr *list = &(player->features);
2,799✔
1061
  multipointObj points = {0, NULL};
2,799✔
1062
  shapeObj *shape = NULL;
1063

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

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

1070
  for (;;) {
1071
    switch (msyylex()) {
6,734✔
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,799✔
1078
      if (player->features != NULL && player->features->tailifhead != NULL)
2,799✔
1079
        shape->index = player->features->tailifhead->shape.index + 1;
446✔
1080
      else
1081
        shape->index = 0;
2,353✔
1082
      if (insertFeatureList(list, shape) == NULL)
2,799✔
1083
        status = MS_FAILURE;
1084

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

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

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

1102
      if (status == MS_FAILURE) {
2,787✔
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) {
8✔
1208
  for (;;) {
1209
    switch (msyylex()) {
35✔
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):
7✔
1218
      if (getString(&(pLayer->grid->labelformat)) == MS_FAILURE) {
7✔
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):
4✔
1234
      if (getDouble(&(pLayer->grid->maxarcs), MS_NUM_CHECK_GT, 0, -1) == -1)
4✔
1235
        return (-1);
1236
      break;
1237
    case (MININTERVAL):
4✔
1238
      if (getDouble(&(pLayer->grid->minincrement), MS_NUM_CHECK_GT, 0, -1) ==
4✔
1239
          -1)
1240
        return (-1);
1241
      break;
1242
    case (MAXINTERVAL):
8✔
1243
      if (getDouble(&(pLayer->grid->maxincrement), MS_NUM_CHECK_GT, 0, -1) ==
8✔
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):
4✔
1253
      if (getDouble(&(pLayer->grid->maxsubdivides), MS_NUM_CHECK_GT, 0, -1) ==
4✔
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,131✔
1282
  p->gt.need_geotransform = MS_FALSE;
11,131✔
1283

1284
  if (p->proj != NULL || p->numargs != 0) {
11,131✔
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,571✔
1294
    case (EOF):
×
1295
      msSetError(MS_EOFERR, NULL, "loadProjection()");
×
1296
      return (-1);
×
1297
    case (END):
11,131✔
1298
      if (p->numargs == 1 && strstr(p->args[0], "+") != NULL) {
11,131✔
1299
        char *one_line_def = p->args[0];
1300
        int result;
1301

1302
        p->args[0] = NULL;
531✔
1303
        p->numargs = 0;
531✔
1304
        result = msLoadProjectionString(p, one_line_def);
531✔
1305
        free(one_line_def);
531✔
1306
        return result;
531✔
1307
      } else {
1308
        if (p->numargs != 0)
10,600✔
1309
          return msProcessProjection(p);
10,600✔
1310
        else
1311
          return 0;
1312
      }
1313
      break;
1314
    case (MS_STRING):
11,440✔
1315
    case (MS_AUTO):
1316
      if (p->numargs == MS_MAXPROJARGS) {
11,440✔
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,440✔
1324
      p->numargs++;
11,440✔
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,
5,767✔
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);
5,767✔
1348
  if (strncasecmp(value, pszPrefix, prefix_len) != 0)
5,767✔
1349
    return -1;
1350

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

1356
  buffer_size = 10 + strlen(code) + 1;
4,989✔
1357
  init_string = (char *)msSmallMalloc(buffer_size);
4,989✔
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);
4,989✔
1363
  p->args[0] = init_string;
4,989✔
1364
  p->numargs = 1;
4,989✔
1365

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

1371
  return 0;
1372
}
1373

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

1378
static int msLoadProjectionStringCRSLike(projectionObj *p, const char *value,
293✔
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);
293✔
1386
  if (strncasecmp(value, pszPrefix, prefix_len) != 0)
293✔
1387
    return -1;
1388

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

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

1396
  if (strcasecmp(id, "84") == 0 || strcasecmp(id, "CRS84") == 0)
14✔
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);
14✔
1409
  p->args[0] = msStrdup(init_string);
14✔
1410
  p->numargs = 1;
14✔
1411

1412
  return 0;
14✔
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,292✔
1423
  assert(p);
1424

1425
  msFreeProjectionExceptContext(p);
3,292✔
1426

1427
  p->gt.need_geotransform = MS_FALSE;
3,292✔
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,292✔
1439
    return msProcessProjection(p);
3,254✔
1440
  }
1441

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

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

1447
  int num_params = 0;
77✔
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) {
77✔
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,919✔
1482
  assert(p);
1483
  p->gt.need_geotransform = MS_FALSE;
2,919✔
1484

1485
  msFreeProjectionExceptContext(p);
2,919✔
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,919✔
1494
    char *trimmed;
1495
    int i, i_out = 0;
1496

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

1504
    p->args = msStringSplit(trimmed, '+', &p->numargs);
1,093✔
1505
    free(trimmed);
1,093✔
1506
  } else if (strncasecmp(value, "AUTO:", 5) == 0 ||
1,826✔
1507
             strncasecmp(value, "AUTO2:", 6) == 0) {
1,826✔
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,826✔
1516
    /* Assume long/lat ordering. Use msLoadProjectionStringEPSG() if wanting to
1517
     * follow EPSG axis */
1518
  } else if (msLoadProjectionStringEPSGLike(
203✔
1519
                 p, value, "urn:ogc:def:crs:EPSG:", MS_TRUE) == 0) {
1520
  } else if (msLoadProjectionStringEPSGLike(
124✔
1521
                 p, value, "urn:EPSG:geographicCRS:", MS_TRUE) == 0) {
1522
  } else if (msLoadProjectionStringEPSGLike(
120✔
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:") ==
120✔
1529
             0) {
1530
  } else if (msLoadProjectionStringEPSGLike(
114✔
1531
                 p, value, "http://www.opengis.net/def/crs/EPSG/", MS_TRUE) ==
1532
             0) {
1533
    /* URI projection support */
1534
  } else if (msLoadProjectionStringCRSLike(
88✔
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(
88✔
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) {
85✔
1543
  } else if (msLoadProjectionCodeString(p, value) == 0) {
77✔
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);
67✔
1551
  }
1552

1553
  return msProcessProjection(p);
2,919✔
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,720✔
1583
  int i;
1584

1585
  MS_REFCNT_INIT(label);
18,720✔
1586

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

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

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

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

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

1619
  label->force = MS_OFF;
18,720✔
1620
  label->priority = MS_DEFAULT_LABEL_PRIORITY;
18,720✔
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,720✔
1626
  label->styles = NULL;
18,720✔
1627

1628
  label->numbindings = 0;
18,720✔
1629
  label->nexprbindings = 0;
18,720✔
1630
  for (i = 0; i < MS_LABEL_BINDING_LENGTH; i++) {
243,360✔
1631
    label->bindings[i].item = NULL;
224,640✔
1632
    label->bindings[i].index = -1;
224,640✔
1633
    msInitExpression(&(label->exprBindings[i]));
224,640✔
1634
  }
1635

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

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

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

1644
  return;
18,720✔
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,211✔
1659
  int i;
1660

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

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

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

1677
  for (i = 0; i < MS_LABEL_BINDING_LENGTH; i++) {
242,359✔
1678
    msFree(label->bindings[i].item);
223,716✔
1679
    msFreeExpression(&(label->exprBindings[i]));
223,716✔
1680
  }
1681

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

1685
  if (label->leader) {
18,643✔
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,604✔
1736
  int symbol;
1737

1738
  for (;;) {
1739
    switch (msyylex()) {
20,927✔
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,458✔
1787
      if (loadColor(&(label->color),
3,458✔
1788
                    &(label->bindings[MS_LABEL_BINDING_COLOR])) != MS_SUCCESS)
1789
        return (-1);
1790
      if (label->bindings[MS_LABEL_BINDING_COLOR].item)
3,458✔
1791
        label->numbindings++;
3✔
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,047✔
1809
      if ((symbol = getSymbol(2, MS_STRING, MS_BINDING)) == -1)
2,047✔
1810
        return (-1);
1811

1812
      if (symbol == MS_STRING) {
2,047✔
1813
        if (label->font != NULL)
2,047✔
1814
          msFree(label->font);
×
1815
        label->font = msStrdup(msyystring_buffer);
2,047✔
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):
266✔
1859
      if (getInteger(&(label->maxlength), MS_NUM_CHECK_GT, 0, -1) == -1)
266✔
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):
579✔
1923
      if (loadColor(&(label->outlinecolor),
579✔
1924
                    &(label->bindings[MS_LABEL_BINDING_OUTLINECOLOR])) !=
1925
          MS_SUCCESS)
1926
        return (-1);
1927
      if (label->bindings[MS_LABEL_BINDING_OUTLINECOLOR].item)
579✔
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):
646✔
1935
      if ((label->partials = getSymbol(2, MS_TRUE, MS_FALSE)) == -1)
646✔
1936
        return (-1);
1937
      break;
1938
    case (POSITION):
1,485✔
1939
      if ((label->position =
1,485✔
1940
               getSymbol(11, MS_UL, MS_UC, MS_UR, MS_CL, MS_CC, MS_CR, MS_LL,
1,485✔
1941
                         MS_LC, MS_LR, MS_AUTO, MS_BINDING)) == -1)
1942
        return (-1);
1943
      if (label->position == MS_BINDING) {
1,485✔
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,677✔
2013
      if (label->bindings[MS_LABEL_BINDING_SIZE].item) {
2,677✔
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,677✔
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,677✔
2024
                              MS_SMALL, MS_MEDIUM, MS_LARGE, MS_GIANT)) == -1)
2025
        return (-1);
2026

2027
      if (symbol == MS_NUMBER) {
2,677✔
2028
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_GT, 0, -1) == MS_FAILURE) {
2,174✔
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,174✔
2035
      } else if (symbol == MS_BINDING) {
503✔
2036
        label->bindings[MS_LABEL_BINDING_SIZE].item =
3✔
2037
            msStrdup(msyystring_buffer);
3✔
2038
        label->numbindings++;
3✔
2039
      } else if (symbol == MS_EXPRESSION) {
500✔
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;
498✔
2047
      break;
2048
    case (STYLE):
1,166✔
2049
      if (msGrowLabelStyles(label) == NULL)
1,166✔
2050
        return (-1);
2051
      initStyle(label->styles[label->numstyles]);
1,166✔
2052
      if (loadStyle(label->styles[label->numstyles]) != MS_SUCCESS) {
1,166✔
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,166✔
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,166✔
2063
      break;
1,166✔
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,514✔
2078
      if (getSymbol(2, MS_TRUETYPE, MS_BITMAP) == -1)
2,514✔
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,400,318✔
2266
  memset(exp, 0, sizeof(*exp));
2267
  exp->type = MS_STRING;
1,400,318✔
2268
}
1,400,318✔
2269

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

2274
  if (!exp)
822,688✔
2275
    return;
2276

2277
  if (exp->tokens) {
822,688✔
2278
    node = exp->tokens;
2279
    while (node != NULL) {
9,464✔
2280
      nextNode = node->next;
8,211✔
2281

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

2284
      switch (node->token) {
8,211✔
2285
      case MS_TOKEN_BINDING_DOUBLE:
1,659✔
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,659✔
2290
        break;
1,659✔
2291
      case MS_TOKEN_LITERAL_TIME:
2292
        /* anything to do? */
2293
        break;
2294
      case MS_TOKEN_LITERAL_STRING:
285✔
2295
        msFree(node->tokenval.strval);
285✔
2296
        break;
285✔
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,211✔
2304
      node = nextNode;
2305
    }
2306
    exp->tokens = exp->curtoken = NULL;
1,253✔
2307
  }
2308
}
2309

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

2321
int loadExpression(expressionObj *exp) {
4,757✔
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,757✔
2326
  if ((exp->type = getSymbol(6, MS_STRING, MS_EXPRESSION, MS_REGEX, MS_ISTRING,
4,757✔
2327
                             MS_IREGEX, MS_LIST)) == -1)
2328
    return (-1);
2329
  if (exp->string != NULL) {
4,757✔
2330
    msFree(exp->string);
×
2331
    msFree(exp->native_string);
×
2332
  }
2333
  exp->string = msStrdup(msyystring_buffer);
4,757✔
2334
  exp->native_string = NULL;
4,757✔
2335

2336
  if (exp->type == MS_ISTRING) {
4,757✔
2337
    exp->flags = exp->flags | MS_EXP_INSENSITIVE;
19✔
2338
    exp->type = MS_STRING;
19✔
2339
  } else if (exp->type == MS_IREGEX) {
4,738✔
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,788✔
2360
  int retval = MS_FAILURE;
2361

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

2366
  return retval;
2,788✔
2367
}
2368

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

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

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

2382
    if (exp->type == MS_ISTRING) {
2,771✔
2383
      exp->type = MS_STRING;
×
2384
      exp->flags = exp->flags | MS_EXP_INSENSITIVE;
×
2385
    } else if (exp->type == MS_IREGEX) {
2,771✔
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;
17✔
2393
    if ((strlen(value) - strlen(msyystring_buffer)) == 2)
17✔
2394
      exp->string = msStrdup(msyystring_buffer); /* value was quoted */
3✔
2395
    else
2396
      exp->string = msStrdup(value); /* use the whole value */
14✔
2397
  }
2398

2399
  return (0);
2,788✔
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,368✔
2474
  assert(ptable);
2475

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

2493
      free(key);
92,847✔
2494
      free(data);
92,847✔
2495
      break;
92,847✔
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,837✔
2557
  cluster->maxdistance = 10;
13,837✔
2558
  cluster->buffer = 0;
13,837✔
2559
  cluster->region = NULL;
13,837✔
2560
  msInitExpression(&(cluster->group));
13,837✔
2561
  msInitExpression(&(cluster->filter));
13,837✔
2562
}
13,837✔
2563

2564
void freeCluster(clusterObj *cluster) {
13,802✔
2565
  msFree(cluster->region);
13,802✔
2566
  msFreeExpression(&(cluster->group));
13,802✔
2567
  msFreeExpression(&(cluster->filter));
13,802✔
2568
}
13,802✔
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,842✔
2677
  int i;
2678
  MS_REFCNT_INIT(style);
24,842✔
2679
  MS_INIT_COLOR(style->color, -1, -1, -1, 255); /* must explicitly set colors */
24,842✔
2680
  MS_INIT_COLOR(style->outlinecolor, -1, -1, -1, 255);
24,842✔
2681
  /* New Color Range fields*/
2682
  MS_INIT_COLOR(style->mincolor, -1, -1, -1, 255);
24,842✔
2683
  MS_INIT_COLOR(style->maxcolor, -1, -1, -1, 255);
24,842✔
2684
  style->minvalue = 0.0;
24,842✔
2685
  style->maxvalue = 1.0;
24,842✔
2686
  style->rangeitem = NULL;
24,842✔
2687
  /* End Color Range fields*/
2688
  style->symbol = 0; /* there is always a default symbol*/
24,842✔
2689
  style->symbolname = NULL;
24,842✔
2690
  style->size = -1; /* in SIZEUNITS (layerObj) */
24,842✔
2691
  style->minsize = MS_MINSYMBOLSIZE;
24,842✔
2692
  style->maxsize = MS_MAXSYMBOLSIZE;
24,842✔
2693
  style->width = 1;        /* in pixels */
24,842✔
2694
  style->outlinewidth = 0; /* in pixels */
24,842✔
2695
  style->minwidth = MS_MINSYMBOLWIDTH;
24,842✔
2696
  style->maxwidth = MS_MAXSYMBOLWIDTH;
24,842✔
2697
  style->minscaledenom = style->maxscaledenom = -1.0;
24,842✔
2698
  style->offsetx = style->offsety = 0;                   /* no offset */
24,842✔
2699
  style->polaroffsetpixel = style->polaroffsetangle = 0; /* no polar offset */
24,842✔
2700
  style->angle = 0;
24,842✔
2701
  style->autoangle = MS_FALSE;
24,842✔
2702
  style->antialiased = MS_TRUE;
24,842✔
2703
  style->opacity = 100; /* fully opaque */
24,842✔
2704

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

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

2715
  style->numbindings = 0;
24,842✔
2716
  style->nexprbindings = 0;
24,842✔
2717
  for (i = 0; i < MS_STYLE_BINDING_LENGTH; i++) {
322,946✔
2718
    style->bindings[i].item = NULL;
298,104✔
2719
    style->bindings[i].index = -1;
298,104✔
2720
    msInitExpression(&(style->exprBindings[i]));
298,104✔
2721
  }
2722

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

2726
  return MS_SUCCESS;
24,842✔
2727
}
2728

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

2732
  for (;;) {
2733
    switch (msyylex()) {
48,901✔
2734
      /* New Color Range fields*/
2735
    case (COLORRANGE):
48✔
2736
      /*These are both in one line now*/
2737
      if (loadColor(&(style->mincolor), NULL) != MS_SUCCESS)
48✔
2738
        return (MS_FAILURE);
2739
      if (loadColor(&(style->maxcolor), NULL) != MS_SUCCESS)
48✔
2740
        return (MS_FAILURE);
2741
      break;
2742
    case (DATARANGE):
48✔
2743
      /*These are both in one line now*/
2744
      if (getDouble(&(style->minvalue), MS_NUM_CHECK_NONE, -1, -1) == -1)
48✔
2745
        return (MS_FAILURE);
2746
      if (getDouble(&(style->maxvalue), MS_NUM_CHECK_NONE, -1, -1) == -1)
48✔
2747
        return (MS_FAILURE);
2748
      break;
2749
    case (RANGEITEM):
16✔
2750
      if (getString(&style->rangeitem) == MS_FAILURE)
16✔
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,469✔
2785
      if (loadColor(&(style->color),
12,469✔
2786
                    &(style->bindings[MS_STYLE_BINDING_COLOR])) != MS_SUCCESS)
2787
        return (MS_FAILURE);
2788
      if (style->bindings[MS_STYLE_BINDING_COLOR].item)
12,469✔
2789
        style->numbindings++;
20✔
2790
      break;
2791
    case (EOF):
×
2792
      msSetError(MS_EOFERR, NULL, "loadStyle()");
×
2793
      return (MS_FAILURE); /* missing END (probably) */
×
2794
    case (END): {
13,900✔
2795
      int alpha;
2796

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

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

2804
        style->mincolor.alpha = alpha;
244✔
2805
        style->maxcolor.alpha = alpha;
244✔
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,201✔
2832
      int s;
2833
      if ((s = getSymbol(2, MS_STRING, MS_EXPRESSION)) == -1)
1,201✔
2834
        return (MS_FAILURE);
2835
      if (s == MS_STRING)
1,201✔
2836
        msStyleSetGeomTransform(style, msyystring_buffer);
1,165✔
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):
176✔
2875
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
176✔
2876
        return (MS_FAILURE);
2877
      if (symbol == MS_NUMBER)
176✔
2878
        style->offsetx = (double)msyynumber; // any double ok
176✔
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)
176✔
2888
        return (MS_FAILURE);
2889
      if (symbol == MS_NUMBER)
176✔
2890
        style->offsety = (double)msyynumber; // any double ok
176✔
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):
248✔
2900
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
248✔
2901
        return (MS_FAILURE);
2902
      if (symbol == MS_NUMBER)
248✔
2903
        style->opacity = MS_MAX(MS_MIN((int)msyynumber, 100),
248✔
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,912✔
2914
      if (loadColor(&(style->outlinecolor),
3,912✔
2915
                    &(style->bindings[MS_STYLE_BINDING_OUTLINECOLOR])) !=
2916
          MS_SUCCESS)
2917
        return (MS_FAILURE);
2918
      if (style->bindings[MS_STYLE_BINDING_OUTLINECOLOR].item)
3,912✔
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;
164✔
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)
236✔
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,790✔
2975
      if (style->exprBindings[MS_STYLE_BINDING_SIZE].string) {
5,790✔
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,790✔
2981
        return (MS_FAILURE);
2982
      if (symbol == MS_NUMBER) {
5,790✔
2983
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_GT, 0, -1) == MS_FAILURE) {
5,692✔
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,692✔
2990
      } else if (symbol == MS_EXPRESSION) {
98✔
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)
92✔
2998
          msFree(style->bindings[MS_STYLE_BINDING_SIZE].item);
3✔
2999
        style->bindings[MS_STYLE_BINDING_SIZE].item =
92✔
3000
            msStrdup(msyystring_buffer);
92✔
3001
        style->numbindings++;
92✔
3002
      }
3003
      break;
3004
    case (STYLE):
3005
      break; /* for string loads */
3006
    case (SYMBOL):
6,987✔
3007
      if ((symbol = getSymbol(3, MS_NUMBER, MS_STRING, MS_BINDING)) == -1)
6,987✔
3008
        return (MS_FAILURE);
3009
      if (symbol == MS_NUMBER) {
6,987✔
3010
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_GTE, 0, -1) == MS_FAILURE) {
4,542✔
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,542✔
3018
          msFree(style->symbolname);
×
3019
          style->symbolname = NULL;
×
3020
        }
3021
        style->symbol = (int)msyynumber;
4,542✔
3022
      } else if (symbol == MS_STRING) {
2,445✔
3023
        if (style->symbolname != NULL)
2,429✔
3024
          msFree(style->symbolname);
×
3025
        style->symbolname = msStrdup(msyystring_buffer);
2,429✔
3026
      } else {
3027
        if (style->bindings[MS_STYLE_BINDING_SYMBOL].item != NULL)
16✔
3028
          msFree(style->bindings[MS_STYLE_BINDING_SYMBOL].item);
×
3029
        style->bindings[MS_STYLE_BINDING_SYMBOL].item =
16✔
3030
            msStrdup(msyystring_buffer);
16✔
3031
        style->numbindings++;
16✔
3032
      }
3033
      break;
3034
    case (WIDTH):
3,433✔
3035
      if ((symbol = getSymbol(2, MS_NUMBER, MS_BINDING)) == -1)
3,433✔
3036
        return (MS_FAILURE);
3037
      if (symbol == MS_NUMBER) {
3,433✔
3038
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_GTE, 0, -1) == MS_FAILURE) {
3,415✔
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,415✔
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) {
4✔
3092
  if (!style || !string)
4✔
3093
    return MS_FAILURE;
3094

3095
  msAcquireLock(TLOCK_PARSER);
4✔
3096

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

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

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

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

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

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

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

3125
  for (i = 0; i < MS_STYLE_BINDING_LENGTH; i++) {
322,413✔
3126
    msFree(style->bindings[i].item);
297,612✔
3127
    msFreeExpression(&(style->exprBindings[i]));
297,612✔
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) {
19,020✔
3292
  class->status = MS_ON;
19,020✔
3293
  class->debug = MS_OFF;
19,020✔
3294
  MS_REFCNT_INIT(class);
19,020✔
3295
  class->isfallback = FALSE;
19,020✔
3296

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

3302
  class->template = NULL;
19,020✔
3303

3304
  initHashTable(&(class->metadata));
19,020✔
3305
  initHashTable(&(class->validation));
19,020✔
3306

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

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

3316
  class->numlabels = class->maxlabels = 0;
19,020✔
3317
  class->labels = NULL;
19,020✔
3318

3319
  class->keyimage = NULL;
19,020✔
3320

3321
  class->group = NULL;
19,020✔
3322

3323
  class->leader = NULL;
19,020✔
3324

3325
  class->sizeunits = MS_INHERIT;
19,020✔
3326
  class->scalefactor = 1.0;
19,020✔
3327

3328
  return (0);
19,020✔
3329
}
3330

3331
int freeClass(classObj *class) {
19,094✔
3332
  int i;
3333

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

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

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

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

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

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

3368
  if (class->leader) {
18,979✔
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,993✔
3390
  /* Do we need to increase the size of styles[] by  MS_STYLE_ALLOCSIZE?
3391
   */
3392
  if (class->numstyles == class->maxstyles) {
18,993✔
3393
    styleObj **newStylePtr;
3394
    int i, newsize;
3395

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

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

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

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

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

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

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

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

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

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

3445
  return label->styles[label->numstyles];
5,818✔
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,208✔
3485
  if (c == NULL)
3,208✔
3486
    return MS_FAILURE;
3487

3488
  if (idx < 0) {
3,208✔
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,414✔
3498
    if (msGrowClassStyles(c) == NULL)
3,206✔
3499
      return MS_FAILURE;
3500

3501
    if (initStyle(c->styles[c->numstyles]) == MS_FAILURE) {
3,206✔
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,206✔
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) {
51✔
3520
  int i;
3521

3522
  /* reset labels */
3523
  for (i = 0; i < class->numlabels; i++) {
54✔
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;
51✔
3532

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

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

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

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

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

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

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

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

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

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

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

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

3586
  for (;;) {
3587
    switch (msyylex()) {
43,180✔
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,300✔
3610
      if (loadExpression(&(class->expression)) == -1)
3,300✔
3611
        return (-1); /* loadExpression() cleans up previously allocated
3612
                        expression */
3613
      break;
3614
    case (GROUP):
1,690✔
3615
      if (getString(&class->group) == MS_FAILURE)
1,690✔
3616
        return (-1); /* getString() cleans up previously allocated string */
3617
      break;
3618
    case (KEYIMAGE):
29✔
3619
      if (getString(&class->keyimage) == MS_FAILURE)
29✔
3620
        return (-1); /* getString() cleans up previously allocated string */
3621
      break;
3622
    case (LABEL):
3,114✔
3623
      if (msGrowClassLabels(class) == NULL)
3,114✔
3624
        return (-1);
3625
      initLabel(class->labels[class->numlabels]);
3,114✔
3626
      class->labels[class->numlabels]->size =
3,114✔
3627
          MS_MEDIUM; /* only set a default if the LABEL section is present */
3628
      if (loadLabel(class->labels[class->numlabels]) == -1) {
3,114✔
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,114✔
3635
      break;
3,114✔
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):
8,002✔
3663
      if (getString(&class->name) == MS_FAILURE)
8,002✔
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,715✔
3671
      if (msGrowClassStyles(class) == NULL)
12,715✔
3672
        return (-1);
3673
      initStyle(class->styles[class->numstyles]);
12,715✔
3674
      if (loadStyle(class->styles[class->numstyles]) != MS_SUCCESS) {
12,715✔
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,715✔
3681
      break;
12,715✔
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):
478✔
3687
      if (loadExpression(&(class->text)) == -1)
478✔
3688
        return (-1); /* loadExpression() cleans up previously allocated
3689
                        expression */
3690
      if ((class->text.type != MS_STRING) &&
478✔
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):
32✔
3700
      if (getString(&class->title) == MS_FAILURE)
32✔
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
    case (FALLBACK):
3✔
3708
      if ((class->isfallback = getSymbol(2, MS_TRUE, MS_FALSE)) == -1)
3✔
3709
        return (-1);
3710
      break;
3711
    default:
×
3712
      if (strlen(msyystring_buffer) > 0) {
×
3713
        msSetError(MS_IDENTERR, "Parsing error near (%s):(line %d)",
×
3714
                   "loadClass()", msyystring_buffer, msyylineno);
3715
        return (-1);
×
3716
      } else {
3717
        return (0); /* end of a string, not an error */
3718
      }
3719
    }
3720
  }
3721
}
3722

3723
static int classResolveSymbolNames(classObj *class) {
12,925✔
3724
  int i, j;
3725
  int try_addimage_if_notfound = MS_TRUE;
3726

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

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

3762
  return MS_SUCCESS;
3763
}
3764

3765
int msUpdateClassFromString(classObj *class, char *string) {
×
3766
  if (!class || !string)
×
3767
    return MS_FAILURE;
3768

3769
  msAcquireLock(TLOCK_PARSER);
×
3770

3771
  msyystate = MS_TOKENIZE_STRING;
×
3772
  msyystring = string;
×
3773
  msyylex(); /* sets things up, but doesn't process any tokens */
×
3774

3775
  msyylineno = 1; /* start at line 1 */
×
3776

3777
  if (loadClass(class, class->layer) == -1) {
×
3778
    msReleaseLock(TLOCK_PARSER);
×
3779
    return MS_FAILURE; /* parse error */
×
3780
    ;
3781
  }
3782

3783
  msyylex_destroy();
×
3784
  msReleaseLock(TLOCK_PARSER);
×
3785

3786
  if (classResolveSymbolNames(class) != MS_SUCCESS)
×
3787
    return MS_FAILURE;
3788

3789
  return MS_SUCCESS;
3790
}
3791

3792
static void writeClass(FILE *stream, int indent, classObj *class) {
9✔
3793
  int i;
3794

3795
  if (class->status == MS_DELETE)
9✔
3796
    return;
3797

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

3825
char *msWriteClassToString(classObj *class) {
×
3826
  msIOContext context;
3827
  msIOBuffer buffer;
3828

3829
  context.label = NULL;
×
3830
  context.write_channel = MS_TRUE;
×
3831
  context.readWriteFunc = msIO_bufferWrite;
×
3832
  context.cbData = &buffer;
×
3833
  buffer.data = NULL;
×
3834
  buffer.data_len = 0;
×
3835
  buffer.data_offset = 0;
×
3836

3837
  msIO_installHandlers(NULL, &context, NULL);
×
3838

3839
  writeClass(stdout, -1, class);
×
3840
  msIO_bufferWrite(&buffer, "", 1);
×
3841

3842
  msIO_installHandlers(NULL, NULL, NULL);
×
3843

3844
  return (char *)buffer.data;
×
3845
}
3846

3847
int initCompositingFilter(CompositingFilter *filter) {
×
3848
  filter->filter = NULL;
×
3849
  filter->next = NULL;
×
3850
  return MS_SUCCESS;
×
3851
}
3852

3853
void freeCompositingFilter(CompositingFilter *filter) {
82✔
3854
  if (!filter)
82✔
3855
    return;
3856
  if (filter->next)
×
3857
    freeCompositingFilter(filter->next);
×
3858
  free(filter->filter);
×
3859
  free(filter);
×
3860
}
3861

3862
int initLayerCompositer(LayerCompositer *compositer) {
82✔
3863
  compositer->comp_op = MS_COMPOP_SRC_OVER;
82✔
3864
  compositer->opacity = 100;
82✔
3865
  compositer->next = NULL;
82✔
3866
  compositer->filter = NULL;
82✔
3867
  return MS_SUCCESS;
82✔
3868
}
3869

3870
void freeLayerCompositer(LayerCompositer *compositer) {
82✔
3871
  if (!compositer)
82✔
3872
    return;
3873
  if (compositer->next)
82✔
3874
    freeLayerCompositer(compositer->next);
×
3875
  freeCompositingFilter(compositer->filter);
82✔
3876
  free(compositer);
82✔
3877
}
3878

3879
/*
3880
** Initialize, load and free a single layer structure
3881
*/
3882
int initLayer(layerObj *layer, mapObj *map) {
13,837✔
3883
  if (layer == NULL) {
13,837✔
3884
    msSetError(MS_MEMERR, "Layer is null", "initLayer()");
×
3885
    return (-1);
×
3886
  }
3887
  layer->debug = (int)msGetGlobalDebugLevel();
13,837✔
3888
  MS_REFCNT_INIT(layer);
13,837✔
3889

3890
  /* Set maxclasses = 0, class[] will be allocated as needed on first call
3891
   * to msGrowLayerClasses()
3892
   */
3893
  layer->numclasses = 0;
13,837✔
3894
  layer->maxclasses = 0;
13,837✔
3895
  layer->class = NULL;
13,837✔
3896

3897
  layer->name = NULL;
13,837✔
3898
  layer->group = NULL;
13,837✔
3899
  layer->status = MS_OFF;
13,837✔
3900
  layer->data = NULL;
13,837✔
3901
  layer->rendermode = MS_FIRST_MATCHING_CLASS;
13,837✔
3902

3903
  layer->map = map; /* point back to the encompassing structure */
13,837✔
3904

3905
  layer->type = -1;
13,837✔
3906

3907
  layer->toleranceunits = MS_PIXELS;
13,837✔
3908
  layer->tolerance =
13,837✔
3909
      -1; /* perhaps this should have a different value based on type */
3910

3911
  layer->symbolscaledenom = -1.0; /* -1 means nothing is set */
13,837✔
3912
  layer->scalefactor = 1.0;
13,837✔
3913
  layer->maxscaledenom = -1.0;
13,837✔
3914
  layer->minscaledenom = -1.0;
13,837✔
3915
  layer->minfeaturesize = -1; /* no limit */
13,837✔
3916
  layer->maxgeowidth = -1.0;
13,837✔
3917
  layer->mingeowidth = -1.0;
13,837✔
3918

3919
  layer->sizeunits = MS_PIXELS;
13,837✔
3920

3921
  layer->maxfeatures = -1; /* no quota */
13,837✔
3922
  layer->startindex = -1;  /*used for pagination*/
13,837✔
3923

3924
  layer->scaletokens = NULL;
13,837✔
3925
  layer->numscaletokens = 0;
13,837✔
3926

3927
  layer->template = layer->header = layer->footer = NULL;
13,837✔
3928

3929
  layer->transform = MS_TRUE;
13,837✔
3930

3931
  layer->classitem = NULL;
13,837✔
3932
  layer->classitemindex = -1;
13,837✔
3933

3934
  layer->units = MS_METERS;
13,837✔
3935
  if (msInitProjection(&(layer->projection)) == -1)
13,837✔
3936
    return (-1);
3937

3938
  if (map) {
13,837✔
3939
    msProjectionInheritContextFrom(&(layer->projection), &(map->projection));
13,806✔
3940
  }
3941

3942
  layer->project = MS_TRUE;
13,837✔
3943
  layer->reprojectorLayerToMap = NULL;
13,837✔
3944
  layer->reprojectorMapToLayer = NULL;
13,837✔
3945

3946
  initCluster(&layer->cluster);
13,837✔
3947

3948
  MS_INIT_COLOR(layer->offsite, -1, -1, -1, 255);
13,837✔
3949

3950
  layer->labelcache = MS_ON;
13,837✔
3951
  layer->postlabelcache = MS_FALSE;
13,837✔
3952

3953
  layer->labelitem = NULL;
13,837✔
3954
  layer->labelitemindex = -1;
13,837✔
3955

3956
  layer->labelmaxscaledenom = -1;
13,837✔
3957
  layer->labelminscaledenom = -1;
13,837✔
3958

3959
  layer->tileitem = msStrdup("location");
13,837✔
3960
  layer->tileitemindex = -1;
13,837✔
3961
  layer->tileindex = NULL;
13,837✔
3962
  layer->tilesrs = NULL;
13,837✔
3963

3964
  layer->bandsitem = NULL;
13,837✔
3965
  layer->bandsitemindex = -1;
13,837✔
3966

3967
  layer->currentfeature = layer->features = NULL;
13,837✔
3968

3969
  layer->connection = NULL;
13,837✔
3970
  layer->plugin_library = NULL;
13,837✔
3971
  layer->plugin_library_original = NULL;
13,837✔
3972
  layer->connectiontype = MS_SHAPEFILE;
13,837✔
3973
  layer->vtable = NULL;
13,837✔
3974
  layer->classgroup = NULL;
13,837✔
3975

3976
  layer->layerinfo = NULL;
13,837✔
3977
  layer->wfslayerinfo = NULL;
13,837✔
3978

3979
  layer->items = NULL;
13,837✔
3980
  layer->iteminfo = NULL;
13,837✔
3981
  layer->numitems = 0;
13,837✔
3982

3983
  layer->resultcache = NULL;
13,837✔
3984

3985
  msInitExpression(&(layer->filter));
13,837✔
3986
  layer->filteritem = NULL;
13,837✔
3987
  layer->filteritemindex = -1;
13,837✔
3988

3989
  layer->
3990
    requires
3991
  = layer->labelrequires = NULL;
13,837✔
3992

3993
  initHashTable(&(layer->metadata));
13,837✔
3994
  initHashTable(&(layer->bindvals));
13,837✔
3995
  initHashTable(&(layer->validation));
13,837✔
3996

3997
  layer->styleitem = NULL;
13,837✔
3998
  layer->styleitemindex = -1;
13,837✔
3999

4000
  layer->processing = NULL;
13,837✔
4001
  layer->numjoins = 0;
13,837✔
4002
  layer->joins = (joinObj *)malloc(MS_MAXJOINS * sizeof(joinObj));
13,837✔
4003
  MS_CHECK_ALLOC(layer->joins, MS_MAXJOINS * sizeof(joinObj), -1);
13,837✔
4004

4005
  layer->extent.minx = -1.0;
13,837✔
4006
  layer->extent.miny = -1.0;
13,837✔
4007
  layer->extent.maxx = -1.0;
13,837✔
4008
  layer->extent.maxy = -1.0;
13,837✔
4009

4010
  layer->mask = NULL;
13,837✔
4011
  layer->maskimage = NULL;
13,837✔
4012
  layer->grid = NULL;
13,837✔
4013

4014
  msInitExpression(&(layer->_geomtransform));
13,837✔
4015
  layer->_geomtransform.type = MS_GEOMTRANSFORM_NONE;
13,837✔
4016

4017
  msInitExpression(&(layer->utfdata));
13,837✔
4018
  layer->utfitem = NULL;
13,837✔
4019
  layer->utfitemindex = -1;
13,837✔
4020

4021
  layer->encoding = NULL;
13,837✔
4022

4023
  layer->sortBy.nProperties = 0;
13,837✔
4024
  layer->sortBy.properties = NULL;
13,837✔
4025
  layer->orig_st = NULL;
13,837✔
4026

4027
  layer->compositer = NULL;
13,837✔
4028

4029
  initHashTable(&(layer->connectionoptions));
13,837✔
4030

4031
  return (0);
13,837✔
4032
}
4033

4034
int initScaleToken(scaleTokenObj *token) {
74✔
4035
  token->n_entries = 0;
74✔
4036
  token->name = NULL;
74✔
4037
  token->tokens = NULL;
74✔
4038
  return MS_SUCCESS;
74✔
4039
}
4040

4041
int freeScaleTokenEntry(scaleTokenEntryObj *token) {
168✔
4042
  msFree(token->value);
168✔
4043
  return MS_SUCCESS;
168✔
4044
}
4045

4046
int freeScaleToken(scaleTokenObj *scaletoken) {
74✔
4047
  int i;
4048
  msFree(scaletoken->name);
74✔
4049
  for (i = 0; i < scaletoken->n_entries; i++) {
242✔
4050
    freeScaleTokenEntry(&scaletoken->tokens[i]);
168✔
4051
  }
4052
  msFree(scaletoken->tokens);
74✔
4053
  return MS_SUCCESS;
74✔
4054
}
4055

4056
int freeLayer(layerObj *layer) {
14,137✔
4057
  int i;
4058
  if (!layer)
14,137✔
4059
    return MS_FAILURE;
4060
  if (MS_REFCNT_DECR_IS_NOT_ZERO(layer)) {
14,137✔
4061
    return MS_FAILURE;
4062
  }
4063

4064
  if (layer->debug >= MS_DEBUGLEVEL_VVV)
13,802✔
4065
    msDebug("freeLayer(): freeing layer at %p.\n", layer);
21✔
4066

4067
  if (msLayerIsOpen(layer))
13,802✔
4068
    msLayerClose(layer);
888✔
4069

4070
  msFree(layer->name);
13,802✔
4071
  msFree(layer->encoding);
13,802✔
4072
  msFree(layer->group);
13,802✔
4073
  msFree(layer->data);
13,802✔
4074
  msFree(layer->classitem);
13,802✔
4075
  msFree(layer->labelitem);
13,802✔
4076
  msFree(layer->header);
13,802✔
4077
  msFree(layer->footer);
13,802✔
4078
  msFree(layer->template);
13,802✔
4079
  msFree(layer->tileindex);
13,802✔
4080
  msFree(layer->tileitem);
13,802✔
4081
  msFree(layer->tilesrs);
13,802✔
4082
  msFree(layer->bandsitem);
13,802✔
4083
  msFree(layer->plugin_library);
13,802✔
4084
  msFree(layer->plugin_library_original);
13,802✔
4085
  msFree(layer->connection);
13,802✔
4086
  msFree(layer->vtable);
13,802✔
4087
  msFree(layer->classgroup);
13,802✔
4088

4089
  msProjectDestroyReprojector(layer->reprojectorLayerToMap);
13,802✔
4090
  msProjectDestroyReprojector(layer->reprojectorMapToLayer);
13,802✔
4091
  msFreeProjection(&(layer->projection));
13,802✔
4092
  msFreeExpression(&layer->_geomtransform);
13,802✔
4093

4094
  freeCluster(&layer->cluster);
13,802✔
4095

4096
  for (i = 0; i < layer->maxclasses; i++) {
105,378✔
4097
    if (layer->class[i] != NULL) {
91,576✔
4098
      layer->class[i]->layer = NULL;
18,773✔
4099
      if (freeClass(layer->class[i]) == MS_SUCCESS) {
18,773✔
4100
        msFree(layer->class[i]);
18,766✔
4101
      }
4102
    }
4103
  }
4104
  msFree(layer->class);
13,802✔
4105

4106
  if (layer->numscaletokens > 0) {
13,802✔
4107
    for (i = 0; i < layer->numscaletokens; i++) {
120✔
4108
      freeScaleToken(&layer->scaletokens[i]);
74✔
4109
    }
4110
    msFree(layer->scaletokens);
46✔
4111
  }
4112

4113
  if (layer->features)
13,802✔
4114
    freeFeatureList(layer->features);
2,363✔
4115

4116
  if (layer->resultcache) {
13,802✔
4117
    cleanupResultCache(layer->resultcache);
895✔
4118
    msFree(layer->resultcache);
895✔
4119
  }
4120

4121
  msFree(layer->styleitem);
13,802✔
4122

4123
  msFree(layer->filteritem);
13,802✔
4124
  msFreeExpression(&(layer->filter));
13,802✔
4125

4126
  msFree(layer->requires);
13,802✔
4127
  msFree(layer->labelrequires);
13,802✔
4128

4129
  msFreeHashItems(&(layer->metadata));
13,802✔
4130
  msFreeHashItems(&(layer->validation));
13,802✔
4131
  msFreeHashItems(&layer->bindvals);
13,802✔
4132

4133
  CSLDestroy(layer->processing);
13,802✔
4134

4135
  for (i = 0; i < layer->numjoins; i++) /* each join */
13,802✔
4136
    freeJoin(&(layer->joins[i]));
×
4137
  msFree(layer->joins);
13,802✔
4138
  layer->numjoins = 0;
13,802✔
4139

4140
  layer->classgroup = NULL;
13,802✔
4141

4142
  msFree(layer->mask);
13,802✔
4143
  if (layer->maskimage) {
13,802✔
4144
    msFreeImage(layer->maskimage);
47✔
4145
  }
4146

4147
  if (layer->compositer) {
13,802✔
4148
    freeLayerCompositer(layer->compositer);
82✔
4149
  }
4150

4151
  if (layer->grid) {
13,802✔
4152
    freeGrid(layer->grid);
8✔
4153
    msFree(layer->grid);
8✔
4154
  }
4155

4156
  msFreeExpression(&(layer->utfdata));
13,802✔
4157
  msFree(layer->utfitem);
13,802✔
4158

4159
  for (i = 0; i < layer->sortBy.nProperties; i++)
13,815✔
4160
    msFree(layer->sortBy.properties[i].item);
13✔
4161
  msFree(layer->sortBy.properties);
13,802✔
4162

4163
  msFreeHashItems(&layer->connectionoptions);
13,802✔
4164

4165
  return MS_SUCCESS;
13,802✔
4166
}
4167

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

4187
    newsize = layer->maxclasses + MS_CLASS_ALLOCSIZE;
11,476✔
4188

4189
    /* Alloc/realloc classes */
4190
    newClassPtr =
4191
        (classObj **)realloc(layer->class, newsize * sizeof(classObj *));
11,476✔
4192
    MS_CHECK_ALLOC(newClassPtr, newsize * sizeof(classObj *), NULL);
11,476✔
4193

4194
    layer->class = newClassPtr;
11,476✔
4195
    layer->maxclasses = newsize;
11,476✔
4196
    for (i = layer->numclasses; i < layer->maxclasses; i++) {
103,284✔
4197
      layer->class[i] = NULL;
91,808✔
4198
    }
4199
  }
4200

4201
  if (layer->class[layer->numclasses] == NULL) {
19,014✔
4202
    layer->class[layer->numclasses] = (classObj *)calloc(1, sizeof(classObj));
19,014✔
4203
    MS_CHECK_ALLOC(layer->class[layer->numclasses], sizeof(classObj), NULL);
19,014✔
4204
  }
4205

4206
  return layer->class[layer->numclasses];
19,014✔
4207
}
4208

4209
scaleTokenObj *msGrowLayerScaletokens(layerObj *layer) {
74✔
4210
  layer->scaletokens = msSmallRealloc(
148✔
4211
      layer->scaletokens, (layer->numscaletokens + 1) * sizeof(scaleTokenObj));
74✔
4212
  memset(&layer->scaletokens[layer->numscaletokens], 0, sizeof(scaleTokenObj));
74✔
4213
  return &layer->scaletokens[layer->numscaletokens];
74✔
4214
}
4215

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

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

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

4346
#define SIZEOF_COMP_OPS ((int)(sizeof(CompOps) / sizeof(CompOps[0])))
4347

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

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

4402
  layer->map = (mapObj *)map;
12,947✔
4403

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

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

4522
      if (layer->type == MS_LAYER_POLYGON)
2,799✔
4523
        type = MS_SHAPE_POLYGON;
4524
      else if (layer->type == MS_LAYER_LINE)
2,687✔
4525
        type = MS_SHAPE_LINE;
4526
      else
4527
        type = MS_SHAPE_POINT;
4528

4529
      layer->connectiontype = MS_INLINE;
2,799✔
4530

4531
      if (loadFeature(layer, type) == MS_FAILURE)
2,799✔
4532
        return (-1);
4533
      break;
4534
    case (FILTER):
546✔
4535
      if (loadExpression(&(layer->filter)) == -1)
546✔
4536
        return (-1); /* loadExpression() cleans up previously allocated
4537
                        expression */
4538
      break;
4539
    case (FILTERITEM):
221✔
4540
      if (getString(&layer->filteritem) == MS_FAILURE)
221✔
4541
        return (-1); /* getString() cleans up previously allocated string */
4542
      break;
4543
    case (FOOTER):
572✔
4544
      if (getString(&layer->footer) == MS_FAILURE)
572✔
4545
        return (-1); /* getString() cleans up previously allocated string */
4546
      break;
4547
    case (GRID):
8✔
4548
      layer->connectiontype = MS_GRATICULE;
8✔
4549
      if (layer->grid) {
8✔
4550
        freeGrid(layer->grid);
×
4551
        msFree(layer->grid);
×
4552
      }
4553
      layer->grid = (void *)malloc(sizeof(graticuleObj));
8✔
4554
      MS_CHECK_ALLOC(layer->grid, sizeof(graticuleObj), -1);
8✔
4555

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

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

4657
    case (CONNECTIONOPTIONS):
2✔
4658
      if (loadHashTable(&(layer->connectionoptions)) != MS_SUCCESS)
2✔
4659
        return (-1);
4660
      break;
4661
    case (MS_PLUGIN): {
×
4662
      int rv;
4663
      if (map->config) { // value *must* represent a config key
×
4664
        char *value = NULL;
×
4665
        const char *plugin_library = NULL;
4666

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

4826
int msUpdateLayerFromString(layerObj *layer, char *string) {
27✔
4827
  int i;
4828

4829
  if (!layer || !string)
27✔
4830
    return MS_FAILURE;
4831

4832
  msAcquireLock(TLOCK_PARSER);
27✔
4833

4834
  msyystate = MS_TOKENIZE_STRING;
27✔
4835
  msyystring = string;
27✔
4836
  msyylex(); /* sets things up, but doesn't process any tokens */
27✔
4837

4838
  msyylineno = 1; /* start at line 1 */
27✔
4839

4840
  if (loadLayer(layer, layer->map) == -1) {
27✔
4841
    msReleaseLock(TLOCK_PARSER);
×
4842
    return MS_FAILURE; /* parse error */
×
4843
    ;
4844
  }
4845

4846
  msyylex_destroy();
27✔
4847
  msReleaseLock(TLOCK_PARSER);
27✔
4848

4849
  /* step through classes to resolve symbol names */
4850
  for (i = 0; i < layer->numclasses; i++) {
27✔
4851
    if (classResolveSymbolNames(layer->class[i]) != MS_SUCCESS)
×
4852
      return MS_FAILURE;
4853
  }
4854

4855
  return MS_SUCCESS;
4856
}
4857

4858
static void writeCompositingFilter(FILE *stream, int indent,
4859
                                   CompositingFilter *filter) {
4860
  while (filter) {
×
4861
    writeString(stream, indent, "COMPFILTER", "", filter->filter);
×
4862
    filter = filter->next;
×
4863
  }
4864
}
4865

4866
static void writeLayerCompositer(FILE *stream, int indent,
7✔
4867
                                 LayerCompositer *compositor) {
4868
  indent++;
7✔
4869
  while (compositor) {
7✔
4870
    writeBlockBegin(stream, indent, "COMPOSITE");
×
4871
    writeCompositingFilter(stream, indent, compositor->filter);
×
4872
    if (compositor->comp_op != MS_COMPOP_SRC_OVER) {
×
4873

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

4895
  if (layer->status == MS_DELETE)
7✔
4896
    return;
4897

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

4925
  if (layer->_geomtransform.type == MS_GEOMTRANSFORM_EXPRESSION) {
7✔
4926
    writeIndent(stream, indent + 1);
×
4927
    fprintf(stream, "GEOMTRANSFORM (%s)\n", layer->_geomtransform.string);
×
4928
  }
4929

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

4993
  /* write potentially multiply occurring objects last */
4994
  for (i = 0; i < layer->numscaletokens; i++)
7✔
4995
    writeScaleToken(stream, indent, &(layer->scaletokens[i]));
×
4996
  for (i = 0; i < layer->numjoins; i++)
7✔
4997
    writeJoin(stream, indent, &(layer->joins[i]));
×
4998
  for (i = 0; i < layer->numclasses; i++)
16✔
4999
    writeClass(stream, indent, layer->class[i]);
9✔
5000

5001
  if (layer->grid && layer->connectiontype == MS_GRATICULE)
7✔
5002
    writeGrid(stream, indent, layer->grid);
×
5003
  else {
5004
    current = layer->features;
7✔
5005
    while (current != NULL) {
10✔
5006
      writeFeature(stream, indent, &(current->shape));
3✔
5007
      current = current->next;
3✔
5008
    }
5009
  }
5010

5011
  writeBlockEnd(stream, indent, "LAYER");
7✔
5012
  writeLineFeed(stream);
5013
}
5014

5015
char *msWriteLayerToString(layerObj *layer) {
×
5016
  msIOContext context;
5017
  msIOBuffer buffer;
5018

5019
  context.label = NULL;
×
5020
  context.write_channel = MS_TRUE;
×
5021
  context.readWriteFunc = msIO_bufferWrite;
×
5022
  context.cbData = &buffer;
×
5023
  buffer.data = NULL;
×
5024
  buffer.data_len = 0;
×
5025
  buffer.data_offset = 0;
×
5026

5027
  msIO_installHandlers(NULL, &context, NULL);
×
5028

5029
  writeLayer(stdout, -1, layer);
×
5030
  msIO_bufferWrite(&buffer, "", 1);
×
5031

5032
  msIO_installHandlers(NULL, NULL, NULL);
×
5033

5034
  return (char *)buffer.data;
×
5035
}
5036

5037
/*
5038
** Initialize, load and free a referenceMapObj structure
5039
*/
5040
void initReferenceMap(referenceMapObj *ref) {
3,194✔
5041
  ref->height = ref->width = 0;
3,194✔
5042
  ref->extent.minx = ref->extent.miny = ref->extent.maxx = ref->extent.maxy =
3,194✔
5043
      -1.0;
5044
  ref->image = NULL;
3,194✔
5045
  MS_INIT_COLOR(ref->color, 255, 0, 0, 255);
3,194✔
5046
  MS_INIT_COLOR(ref->outlinecolor, 0, 0, 0, 255);
3,194✔
5047
  ref->status = MS_OFF;
3,194✔
5048
  ref->marker = 0;
3,194✔
5049
  ref->markername = NULL;
3,194✔
5050
  ref->markersize = 0;
3,194✔
5051
  ref->minboxsize = 3;
3,194✔
5052
  ref->maxboxsize = 0;
3,194✔
5053
  ref->map = NULL;
3,194✔
5054
}
3,194✔
5055

5056
void freeReferenceMap(referenceMapObj *ref) {
3,146✔
5057
  msFree(ref->image);
3,146✔
5058
  msFree(ref->markername);
3,146✔
5059
}
3,146✔
5060

5061
int loadReferenceMap(referenceMapObj *ref, mapObj *map) {
×
5062
  int state;
5063

5064
  ref->map = (mapObj *)map;
×
5065

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

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

5169
int msUpdateReferenceMapFromString(referenceMapObj *ref, char *string) {
×
5170
  if (!ref || !string)
×
5171
    return MS_FAILURE;
5172

5173
  msAcquireLock(TLOCK_PARSER);
×
5174

5175
  msyystate = MS_TOKENIZE_STRING;
×
5176
  msyystring = string;
×
5177
  msyylex(); /* sets things up, but doesn't process any tokens */
×
5178

5179
  msyylineno = 1; /* start at line 1 */
×
5180

5181
  if (loadReferenceMap(ref, ref->map) == -1) {
×
5182
    msReleaseLock(TLOCK_PARSER);
×
5183
    return MS_FAILURE; /* parse error */
×
5184
    ;
5185
  }
5186

5187
  msyylex_destroy();
×
5188
  msReleaseLock(TLOCK_PARSER);
×
5189
  return MS_SUCCESS;
×
5190
}
5191

5192
static void writeReferenceMap(FILE *stream, int indent, referenceMapObj *ref) {
1✔
5193
  colorObj c;
5194

5195
  if (!ref->image)
1✔
5196
    return;
1✔
5197

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

5218
char *msWriteReferenceMapToString(referenceMapObj *ref) {
×
5219
  msIOContext context;
5220
  msIOBuffer buffer;
5221

5222
  context.label = NULL;
×
5223
  context.write_channel = MS_TRUE;
×
5224
  context.readWriteFunc = msIO_bufferWrite;
×
5225
  context.cbData = &buffer;
×
5226
  buffer.data = NULL;
×
5227
  buffer.data_len = 0;
×
5228
  buffer.data_offset = 0;
×
5229

5230
  msIO_installHandlers(NULL, &context, NULL);
×
5231

5232
  writeReferenceMap(stdout, -1, ref);
×
5233
  msIO_bufferWrite(&buffer, "", 1);
×
5234

5235
  msIO_installHandlers(NULL, NULL, NULL);
×
5236

5237
  return (char *)buffer.data;
×
5238
}
5239

5240
#define MAX_FORMATOPTIONS 100
5241

5242
static int loadOutputFormat(mapObj *map) {
1,367✔
5243
  char *name = NULL;
5244
  char *mimetype = NULL;
1,367✔
5245
  char *driver = NULL;
5246
  char *extension = NULL;
1,367✔
5247
  int imagemode = MS_NOOVERRIDE;
5248
  int transparent = MS_NOOVERRIDE;
5249
  char *formatoptions[MAX_FORMATOPTIONS];
5250
  int numformatoptions = 0;
5251
  char *value = NULL;
1,367✔
5252

5253
  for (;;) {
5254
    switch (msyylex()) {
8,712✔
5255
    case (EOF):
×
5256
      msSetError(MS_EOFERR, NULL, "loadOutputFormat()");
×
5257
      goto load_output_error;
×
5258

5259
    case (END): {
1,367✔
5260
      outputFormatObj *format;
5261

5262
      if (driver == NULL) {
1,367✔
5263
        msSetError(MS_MISCERR,
×
5264
                   "OUTPUTFORMAT clause lacks DRIVER keyword near (%s):(%d)",
5265
                   "loadOutputFormat()", msyystring_buffer, msyylineno);
5266
        goto load_output_error;
×
5267
      }
5268

5269
      format = msCreateDefaultOutputFormat(map, driver, name, NULL);
1,367✔
5270
      if (format == NULL) {
1,367✔
5271
        msSetError(MS_MISCERR,
2✔
5272
                   "OUTPUTFORMAT (%s) clause references driver (%s), but this "
5273
                   "driver isn't configured.",
5274
                   "loadOutputFormat()", name, driver);
5275
        goto load_output_error;
2✔
5276
      }
5277
      msFree(name);
1,365✔
5278
      name = NULL;
5279
      msFree(driver);
1,365✔
5280
      driver = NULL;
5281

5282
      if (transparent != MS_NOOVERRIDE)
1,365✔
5283
        format->transparent = transparent;
122✔
5284
      if (extension != NULL) {
1,365✔
5285
        msFree(format->extension);
716✔
5286
        format->extension = extension;
716✔
5287
        extension = NULL;
716✔
5288
      }
5289
      if (mimetype != NULL) {
1,365✔
5290
        msFree(format->mimetype);
1,129✔
5291
        format->mimetype = mimetype;
1,129✔
5292
        mimetype = NULL;
1,129✔
5293
      }
5294
      if (imagemode != MS_NOOVERRIDE) {
1,365✔
5295
        if (format->renderer != MS_RENDER_WITH_AGG ||
757✔
5296
            imagemode != MS_IMAGEMODE_PC256) {
5297
          /* don't force to PC256 with agg, this can happen when using mapfile
5298
           * defined GD outputformats that are now falling back to agg/png8
5299
           */
5300
          format->imagemode = imagemode;
748✔
5301
        }
5302

5303
        if (transparent == MS_NOOVERRIDE) {
757✔
5304
          if (imagemode == MS_IMAGEMODE_RGB)
679✔
5305
            format->transparent = MS_FALSE;
59✔
5306
          else if (imagemode == MS_IMAGEMODE_RGBA)
620✔
5307
            format->transparent = MS_TRUE;
24✔
5308
        }
5309
        if (format->imagemode == MS_IMAGEMODE_INT16 ||
757✔
5310
            format->imagemode == MS_IMAGEMODE_FLOAT32 ||
757✔
5311
            format->imagemode == MS_IMAGEMODE_BYTE)
5312
          format->renderer = MS_RENDER_WITH_RAWDATA;
587✔
5313
      }
5314
      while (numformatoptions--) {
3,278✔
5315
        char *key = strchr(formatoptions[numformatoptions], '=');
1,913✔
5316
        if (!key || !*(key + 1)) {
1,913✔
5317
          msSetError(
×
5318
              MS_MISCERR,
5319
              "Failed to parse FORMATOPTION, expecting \"KEY=VALUE\" syntax.",
5320
              "loadOutputFormat()");
5321
          goto load_output_error;
×
5322
        }
5323
        *key = 0;
1,913✔
5324
        key++;
1,913✔
5325
        msSetOutputFormatOption(format, formatoptions[numformatoptions], key);
1,913✔
5326
        free(formatoptions[numformatoptions]);
1,913✔
5327
      }
5328

5329
      format->inmapfile = MS_TRUE;
1,365✔
5330

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

5415
/*
5416
** utility function to write an output format structure to file
5417
*/
5418
static void writeOutputformatobject(FILE *stream, int indent,
1✔
5419
                                    outputFormatObj *outputformat) {
5420
  int i = 0;
5421
  if (!outputformat)
1✔
5422
    return;
5423

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

5444
/*
5445
** Write the output formats to file
5446
*/
5447
static void writeOutputformat(FILE *stream, int indent, mapObj *map) {
1✔
5448
  int i = 0;
5449
  if (!map->outputformat)
1✔
5450
    return;
5451

5452
  writeOutputformatobject(stream, indent, map->outputformat);
1✔
5453
  for (i = 0; i < map->numoutputformats; i++) {
3✔
5454
    if (map->outputformatlist[i]->inmapfile == MS_TRUE &&
2✔
5455
        strcmp(map->outputformatlist[i]->name, map->outputformat->name) != 0)
1✔
5456
      writeOutputformatobject(stream, indent, map->outputformatlist[i]);
×
5457
  }
5458
}
5459

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

5481
void freeLegend(legendObj *legend) {
3,146✔
5482
  if (legend->template)
3,146✔
5483
    free(legend->template);
1✔
5484
  freeLabel(&(legend->label));
3,146✔
5485
}
3,146✔
5486

5487
int loadLegend(legendObj *legend, mapObj *map) {
480✔
5488
  legend->map = (mapObj *)map;
480✔
5489

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

5563
int msUpdateLegendFromString(legendObj *legend, char *string) {
×
5564
  if (!legend || !string)
×
5565
    return MS_FAILURE;
5566

5567
  msAcquireLock(TLOCK_PARSER);
×
5568

5569
  msyystate = MS_TOKENIZE_STRING;
×
5570
  msyystring = string;
×
5571
  msyylex(); /* sets things up, but doesn't process any tokens */
×
5572

5573
  msyylineno = 1; /* start at line 1 */
×
5574

5575
  if (loadLegend(legend, legend->map) == -1) {
×
5576
    msReleaseLock(TLOCK_PARSER);
×
5577
    return MS_FAILURE; /* parse error */
×
5578
    ;
5579
  }
5580

5581
  msyylex_destroy();
×
5582
  msReleaseLock(TLOCK_PARSER);
×
5583
  return MS_SUCCESS;
×
5584
}
5585

5586
static void writeLegend(FILE *stream, int indent, legendObj *legend) {
1✔
5587
  colorObj c;
5588

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

5614
char *msWriteLegendToString(legendObj *legend) {
×
5615
  msIOContext context;
5616
  msIOBuffer buffer;
5617

5618
  context.label = NULL;
×
5619
  context.write_channel = MS_TRUE;
×
5620
  context.readWriteFunc = msIO_bufferWrite;
×
5621
  context.cbData = &buffer;
×
5622
  buffer.data = NULL;
×
5623
  buffer.data_len = 0;
×
5624
  buffer.data_offset = 0;
×
5625

5626
  msIO_installHandlers(NULL, &context, NULL);
×
5627

5628
  writeLegend(stdout, -1, legend);
×
5629
  msIO_bufferWrite(&buffer, "", 1);
×
5630

5631
  msIO_installHandlers(NULL, NULL, NULL);
×
5632

5633
  return (char *)buffer.data;
×
5634
}
5635

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

5662
void freeScalebar(scalebarObj *scalebar) { freeLabel(&(scalebar->label)); }
3,146✔
5663

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

5762
int msUpdateScalebarFromString(scalebarObj *scalebar, char *string) {
×
5763
  if (!scalebar || !string)
×
5764
    return MS_FAILURE;
5765

5766
  msAcquireLock(TLOCK_PARSER);
×
5767

5768
  msyystate = MS_TOKENIZE_STRING;
×
5769
  msyystring = string;
×
5770
  msyylex(); /* sets things up, but doesn't process any tokens */
×
5771

5772
  msyylineno = 1; /* start at line 1 */
×
5773

5774
  if (loadScalebar(scalebar) == -1) {
×
5775
    msReleaseLock(TLOCK_PARSER);
×
5776
    return MS_FAILURE; /* parse error */
×
5777
    ;
5778
  }
5779

5780
  msyylex_destroy();
×
5781
  msReleaseLock(TLOCK_PARSER);
×
5782
  return MS_SUCCESS;
×
5783
}
5784

5785
static void writeScalebar(FILE *stream, int indent, scalebarObj *scalebar) {
1✔
5786
  colorObj c;
5787

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

5820
char *msWriteScalebarToString(scalebarObj *scalebar) {
×
5821
  msIOContext context;
5822
  msIOBuffer buffer;
5823

5824
  context.label = NULL;
×
5825
  context.write_channel = MS_TRUE;
×
5826
  context.readWriteFunc = msIO_bufferWrite;
×
5827
  context.cbData = &buffer;
×
5828
  buffer.data = NULL;
×
5829
  buffer.data_len = 0;
×
5830
  buffer.data_offset = 0;
×
5831

5832
  msIO_installHandlers(NULL, &context, NULL);
×
5833

5834
  writeScalebar(stdout, -1, scalebar);
×
5835
  msIO_bufferWrite(&buffer, "", 1);
×
5836

5837
  msIO_installHandlers(NULL, NULL, NULL);
×
5838

5839
  return (char *)buffer.data;
×
5840
}
5841

5842
/*
5843
** Initialize a queryMapObj structure
5844
*/
5845
void initQueryMap(queryMapObj *querymap) {
3,155✔
5846
  querymap->width = querymap->height = -1;
3,155✔
5847
  querymap->style = MS_HILITE;
3,155✔
5848
  querymap->status = MS_OFF;
3,155✔
5849
  MS_INIT_COLOR(querymap->color, 255, 255, 0, 255); /* yellow */
3,155✔
5850
}
3,155✔
5851

5852
int loadQueryMap(queryMapObj *querymap, mapObj *map) {
165✔
5853
  querymap->map = (mapObj *)map;
165✔
5854

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

5911
int msUpdateQueryMapFromString(queryMapObj *querymap, char *string) {
×
5912
  if (!querymap || !string)
×
5913
    return MS_FAILURE;
5914

5915
  msAcquireLock(TLOCK_PARSER);
×
5916

5917
  msyystate = MS_TOKENIZE_STRING;
×
5918
  msyystring = string;
×
5919
  msyylex(); /* sets things up, but doesn't process any tokens */
×
5920

5921
  msyylineno = 1; /* start at line 1 */
×
5922

5923
  if (loadQueryMap(querymap, querymap->map) == -1) {
×
5924
    msReleaseLock(TLOCK_PARSER);
×
5925
    return MS_FAILURE; /* parse error */
×
5926
    ;
5927
  }
5928

5929
  msyylex_destroy();
×
5930
  msReleaseLock(TLOCK_PARSER);
×
5931
  return MS_SUCCESS;
×
5932
}
5933

5934
static void writeQueryMap(FILE *stream, int indent, queryMapObj *querymap) {
1✔
5935
  colorObj c;
5936

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

5953
char *msWriteQueryMapToString(queryMapObj *querymap) {
×
5954
  msIOContext context;
5955
  msIOBuffer buffer;
5956

5957
  context.label = NULL;
×
5958
  context.write_channel = MS_TRUE;
×
5959
  context.readWriteFunc = msIO_bufferWrite;
×
5960
  context.cbData = &buffer;
×
5961
  buffer.data = NULL;
×
5962
  buffer.data_len = 0;
×
5963
  buffer.data_offset = 0;
×
5964

5965
  msIO_installHandlers(NULL, &context, NULL);
×
5966

5967
  writeQueryMap(stdout, -1, querymap);
×
5968
  msIO_bufferWrite(&buffer, "", 1);
×
5969

5970
  msIO_installHandlers(NULL, NULL, NULL);
×
5971

5972
  return (char *)buffer.data;
×
5973
}
5974

5975
/*
5976
** Initialize a webObj structure
5977
*/
5978
void initWeb(webObj *web) {
3,155✔
5979
  web->template = NULL;
3,155✔
5980
  web->header = web->footer = NULL;
3,155✔
5981
  web->error = web->empty = NULL;
3,155✔
5982
  web->mintemplate = web->maxtemplate = NULL;
3,155✔
5983
  web->minscaledenom = web->maxscaledenom = -1;
3,155✔
5984
  web->imagepath = msStrdup("");
3,155✔
5985
  web->temppath = NULL;
3,155✔
5986
  web->imageurl = msStrdup("");
3,155✔
5987

5988
  initHashTable(&(web->metadata));
3,155✔
5989
  initHashTable(&(web->validation));
3,155✔
5990

5991
  web->map = NULL;
3,155✔
5992
  web->queryformat = msStrdup("text/html");
3,155✔
5993
  web->legendformat = msStrdup("text/html");
3,155✔
5994
  web->browseformat = msStrdup("text/html");
3,155✔
5995
}
3,155✔
5996

5997
void freeWeb(webObj *web) {
3,146✔
5998
  msFree(web->template);
3,146✔
5999
  msFree(web->header);
3,146✔
6000
  msFree(web->footer);
3,146✔
6001
  msFree(web->error);
3,146✔
6002
  msFree(web->empty);
3,146✔
6003
  msFree(web->maxtemplate);
3,146✔
6004
  msFree(web->mintemplate);
3,146✔
6005
  msFree(web->imagepath);
3,146✔
6006
  msFree(web->temppath);
3,146✔
6007
  msFree(web->imageurl);
3,146✔
6008
  msFree(web->queryformat);
3,146✔
6009
  msFree(web->legendformat);
3,146✔
6010
  msFree(web->browseformat);
3,146✔
6011
  msFreeHashItems(&(web->metadata));
3,146✔
6012
  msFreeHashItems(&(web->validation));
3,146✔
6013
}
3,146✔
6014

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

6039
char *msWriteWebToString(webObj *web) {
×
6040
  msIOContext context;
6041
  msIOBuffer buffer;
6042

6043
  context.label = NULL;
×
6044
  context.write_channel = MS_TRUE;
×
6045
  context.readWriteFunc = msIO_bufferWrite;
×
6046
  context.cbData = &buffer;
×
6047
  buffer.data = NULL;
×
6048
  buffer.data_len = 0;
×
6049
  buffer.data_offset = 0;
×
6050

6051
  msIO_installHandlers(NULL, &context, NULL);
×
6052

6053
  writeWeb(stdout, -1, web);
×
6054
  msIO_bufferWrite(&buffer, "", 1);
×
6055

6056
  msIO_installHandlers(NULL, NULL, NULL);
×
6057

6058
  return (char *)buffer.data;
×
6059
}
6060

6061
int loadWeb(webObj *web, mapObj *map) {
2,366✔
6062
  web->map = (mapObj *)map;
2,366✔
6063

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

6160
int msUpdateWebFromString(webObj *web, char *string) {
×
6161
  if (!web || !string)
×
6162
    return MS_FAILURE;
6163

6164
  msAcquireLock(TLOCK_PARSER);
×
6165

6166
  msyystate = MS_TOKENIZE_STRING;
×
6167
  msyystring = string;
×
6168
  msyylex(); /* sets things up, but doesn't process any tokens */
×
6169

6170
  msyylineno = 1; /* start at line 1 */
×
6171

6172
  if (loadWeb(web, web->map) == -1) {
×
6173
    msReleaseLock(TLOCK_PARSER);
×
6174
    return MS_FAILURE; /* parse error */
×
6175
    ;
6176
  }
6177

6178
  msyylex_destroy();
×
6179
  msReleaseLock(TLOCK_PARSER);
×
6180
  return MS_SUCCESS;
×
6181
}
6182

6183
/*
6184
** Initialize, load and free a mapObj structure
6185
**
6186
** This really belongs in mapobject.c, but currently it also depends on
6187
** lots of other init methods in this file.
6188
*/
6189

6190
int initMap(mapObj *map) {
3,155✔
6191
  int i = 0;
6192
  MS_REFCNT_INIT(map);
3,155✔
6193

6194
  map->debug = (int)msGetGlobalDebugLevel();
3,155✔
6195

6196
  /* Set maxlayers = 0, layers[] and layerorder[] will be allocated as needed,
6197
   * on the first call to msGrowMapLayers()
6198
   */
6199
  map->numlayers = 0;
3,155✔
6200
  map->maxlayers = 0;
3,155✔
6201
  map->layers = NULL;
3,155✔
6202
  map->layerorder =
3,155✔
6203
      NULL; /* used to modify the order in which the layers are drawn */
6204

6205
  map->status = MS_ON;
3,155✔
6206
  map->name = msStrdup("MS");
3,155✔
6207
  map->extent.minx = map->extent.miny = map->extent.maxx = map->extent.maxy =
3,155✔
6208
      -1.0;
6209

6210
  map->scaledenom = -1.0;
3,155✔
6211
  map->resolution = MS_DEFAULT_RESOLUTION;    /* pixels per inch */
3,155✔
6212
  map->defresolution = MS_DEFAULT_RESOLUTION; /* pixels per inch */
3,155✔
6213

6214
  map->height = map->width = -1;
3,155✔
6215
  map->maxsize = MS_MAXIMAGESIZE_DEFAULT;
3,155✔
6216

6217
  map->gt.need_geotransform = MS_FALSE;
3,155✔
6218
  map->gt.rotation_angle = 0.0;
3,155✔
6219

6220
  map->units = MS_METERS;
3,155✔
6221
  map->cellsize = 0;
3,155✔
6222
  map->shapepath = NULL;
3,155✔
6223
  map->mappath = NULL;
3,155✔
6224
  map->sldurl = NULL;
3,155✔
6225

6226
  MS_INIT_COLOR(map->imagecolor, 255, 255, 255, 255); /* white */
3,155✔
6227

6228
  map->numoutputformats = 0;
3,155✔
6229
  map->outputformatlist = NULL;
3,155✔
6230
  map->outputformat = NULL;
3,155✔
6231

6232
  /* map->configoptions = msCreateHashTable();; */
6233
  initHashTable(&(map->configoptions));
3,155✔
6234

6235
  map->imagetype = NULL;
3,155✔
6236

6237
  map->palette.numcolors = 0;
3,155✔
6238

6239
  for (i = 0; i < MS_MAX_LABEL_PRIORITY; i++) {
34,705✔
6240
    map->labelcache.slots[i].labels =
31,550✔
6241
        NULL; /* cache is initialize at draw time */
6242
    map->labelcache.slots[i].cachesize = 0;
31,550✔
6243
    map->labelcache.slots[i].numlabels = 0;
31,550✔
6244
    map->labelcache.slots[i].markers = NULL;
31,550✔
6245
    map->labelcache.slots[i].markercachesize = 0;
31,550✔
6246
    map->labelcache.slots[i].nummarkers = 0;
31,550✔
6247
  }
6248

6249
  map->fontset.filename = NULL;
3,155✔
6250
  map->fontset.numfonts = 0;
3,155✔
6251

6252
  /* map->fontset.fonts = NULL; */
6253
  initHashTable(&(map->fontset.fonts));
3,155✔
6254

6255
  msInitSymbolSet(&map->symbolset);
3,155✔
6256
  map->symbolset.fontset = &(map->fontset);
3,155✔
6257
  map->symbolset.map = map;
3,155✔
6258

6259
  initLegend(&map->legend);
3,155✔
6260
  initScalebar(&map->scalebar);
3,155✔
6261
  initWeb(&map->web);
3,155✔
6262
  initReferenceMap(&map->reference);
3,155✔
6263
  initQueryMap(&map->querymap);
3,155✔
6264

6265
  map->projContext = msProjectionContextGetFromPool();
3,155✔
6266

6267
  if (msInitProjection(&(map->projection)) == -1)
3,155✔
6268
    return (-1);
6269
  if (msInitProjection(&(map->latlon)) == -1)
3,155✔
6270
    return (-1);
6271

6272
  msProjectionSetContext(&(map->projection), map->projContext);
3,155✔
6273
  msProjectionSetContext(&(map->latlon), map->projContext);
3,155✔
6274

6275
  /* initialize a default "geographic" projection */
6276
  map->latlon.numargs = 2;
3,155✔
6277
  map->latlon.args[0] = msStrdup("proj=latlong");
3,155✔
6278
  map->latlon.args[1] =
6,310✔
6279
      msStrdup("ellps=WGS84"); /* probably want a different ellipsoid */
3,155✔
6280
  if (msProcessProjection(&(map->latlon)) == -1)
3,155✔
6281
    return (-1);
6282

6283
  map->templatepattern = map->datapattern = NULL;
3,155✔
6284

6285
  /* Encryption key information - see mapcrypto.c */
6286
  map->encryption_key_loaded = MS_FALSE;
3,155✔
6287

6288
  msInitQuery(&(map->query));
3,155✔
6289

6290
#ifdef USE_V8_MAPSCRIPT
6291
  map->v8context = NULL;
6292
#endif
6293

6294
  map->config = NULL;
3,155✔
6295

6296
  return (0);
3,155✔
6297
}
6298

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

6320
    newsize = map->maxlayers + MS_LAYER_ALLOCSIZE;
3,114✔
6321

6322
    /* Alloc/realloc layers */
6323
    newLayersPtr =
6324
        (layerObj **)realloc(map->layers, newsize * sizeof(layerObj *));
3,114✔
6325
    MS_CHECK_ALLOC(newLayersPtr, newsize * sizeof(layerObj *), NULL);
3,114✔
6326

6327
    map->layers = newLayersPtr;
3,114✔
6328

6329
    /* Alloc/realloc layerorder */
6330
    newLayerorderPtr = (int *)realloc(map->layerorder, newsize * sizeof(int));
3,114✔
6331
    MS_CHECK_ALLOC(newLayerorderPtr, newsize * sizeof(int), NULL);
3,114✔
6332

6333
    map->layerorder = newLayerorderPtr;
3,114✔
6334

6335
    map->maxlayers = newsize;
3,114✔
6336
    for (i = map->numlayers; i < map->maxlayers; i++) {
202,410✔
6337
      map->layers[i] = NULL;
199,296✔
6338
      map->layerorder[i] = 0;
199,296✔
6339
    }
6340
  }
6341

6342
  if (map->layers[map->numlayers] == NULL) {
13,290✔
6343
    map->layers[map->numlayers] = (layerObj *)calloc(1, sizeof(layerObj));
13,290✔
6344
    MS_CHECK_ALLOC(map->layers[map->numlayers], sizeof(layerObj), NULL);
13,290✔
6345
  }
6346

6347
  return map->layers[map->numlayers];
13,290✔
6348
}
6349

6350
int msFreeLabelCacheSlot(labelCacheSlotObj *cacheslot) {
43,550✔
6351
  int i, j;
6352

6353
  /* free the labels */
6354
  if (cacheslot->labels) {
43,550✔
6355
    for (i = 0; i < cacheslot->numlabels; i++) {
16,739✔
6356

6357
      for (j = 0; j < cacheslot->labels[i].numtextsymbols; j++) {
14,686✔
6358
        freeTextSymbol(cacheslot->labels[i].textsymbols[j]);
10,037✔
6359
        free(cacheslot->labels[i].textsymbols[j]);
10,037✔
6360
      }
6361
      msFree(cacheslot->labels[i].textsymbols);
4,649✔
6362

6363
      if (cacheslot->labels[i].leaderline) {
4,649✔
6364
        msFree(cacheslot->labels[i].leaderline->point);
32✔
6365
        msFree(cacheslot->labels[i].leaderline);
32✔
6366
        msFree(cacheslot->labels[i].leaderbbox);
32✔
6367
      }
6368
    }
6369
  }
6370
  msFree(cacheslot->labels);
43,550✔
6371
  cacheslot->labels = NULL;
43,550✔
6372
  cacheslot->cachesize = 0;
43,550✔
6373
  cacheslot->numlabels = 0;
43,550✔
6374

6375
  msFree(cacheslot->markers);
43,550✔
6376
  cacheslot->markers = NULL;
43,550✔
6377
  cacheslot->markercachesize = 0;
43,550✔
6378
  cacheslot->nummarkers = 0;
43,550✔
6379

6380
  return (MS_SUCCESS);
43,550✔
6381
}
6382

6383
int msFreeLabelCache(labelCacheObj *cache) {
4,355✔
6384
  int p;
6385

6386
  for (p = 0; p < MS_MAX_LABEL_PRIORITY; p++) {
47,905✔
6387
    if (msFreeLabelCacheSlot(&(cache->slots[p])) != MS_SUCCESS)
43,550✔
6388
      return MS_FAILURE;
6389
  }
6390

6391
  cache->num_allocated_rendered_members = cache->num_rendered_members = 0;
4,355✔
6392
  msFree(cache->rendered_text_symbols);
4,355✔
6393

6394
  return MS_SUCCESS;
4,355✔
6395
}
6396

6397
int msInitLabelCacheSlot(labelCacheSlotObj *cacheslot) {
12,090✔
6398

6399
  if (cacheslot->labels || cacheslot->markers)
12,090✔
6400
    msFreeLabelCacheSlot(cacheslot);
×
6401

6402
  cacheslot->labels = (labelCacheMemberObj *)malloc(
12,090✔
6403
      sizeof(labelCacheMemberObj) * MS_LABELCACHEINITSIZE);
6404
  MS_CHECK_ALLOC(cacheslot->labels,
12,090✔
6405
                 sizeof(labelCacheMemberObj) * MS_LABELCACHEINITSIZE,
6406
                 MS_FAILURE);
6407

6408
  cacheslot->cachesize = MS_LABELCACHEINITSIZE;
12,090✔
6409
  cacheslot->numlabels = 0;
12,090✔
6410

6411
  cacheslot->markers = (markerCacheMemberObj *)malloc(
12,090✔
6412
      sizeof(markerCacheMemberObj) * MS_LABELCACHEINITSIZE);
6413
  MS_CHECK_ALLOC(cacheslot->markers,
12,090✔
6414
                 sizeof(markerCacheMemberObj) * MS_LABELCACHEINITSIZE,
6415
                 MS_FAILURE);
6416

6417
  cacheslot->markercachesize = MS_LABELCACHEINITSIZE;
12,090✔
6418
  cacheslot->nummarkers = 0;
12,090✔
6419

6420
  return (MS_SUCCESS);
12,090✔
6421
}
6422

6423
int msInitLabelCache(labelCacheObj *cache) {
1,209✔
6424
  int p;
6425

6426
  for (p = 0; p < MS_MAX_LABEL_PRIORITY; p++) {
13,299✔
6427
    if (msInitLabelCacheSlot(&(cache->slots[p])) != MS_SUCCESS)
12,090✔
6428
      return MS_FAILURE;
6429
  }
6430
  cache->gutter = 0;
1,209✔
6431
  cache->num_allocated_rendered_members = cache->num_rendered_members = 0;
1,209✔
6432
  cache->rendered_text_symbols = NULL;
1,209✔
6433

6434
  return MS_SUCCESS;
1,209✔
6435
}
6436

6437
static void writeMap(FILE *stream, int indent, mapObj *map) {
1✔
6438
  int i;
6439
  colorObj c;
6440

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

6465
  writeOutputformat(stream, indent, map);
1✔
6466

6467
  /* write symbol with INLINE tag in mapfile */
6468
  for (i = 0; i < map->symbolset.numsymbols; i++) {
5✔
6469
    if (map->symbolset.symbol[i]->inmapfile)
4✔
6470
      writeSymbol(map->symbolset.symbol[i], stream);
×
6471
  }
6472

6473
  writeProjection(stream, indent, &(map->projection));
1✔
6474

6475
  writeLegend(stream, indent, &(map->legend));
1✔
6476
  writeQueryMap(stream, indent, &(map->querymap));
1✔
6477
  writeReferenceMap(stream, indent, &(map->reference));
1✔
6478
  writeScalebar(stream, indent, &(map->scalebar));
1✔
6479
  writeWeb(stream, indent, &(map->web));
1✔
6480

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

6484
  writeBlockEnd(stream, indent, "MAP");
1✔
6485
}
1✔
6486

6487
char *msWriteMapToString(mapObj *map) {
×
6488
  msIOContext context;
6489
  msIOBuffer buffer;
6490

6491
  context.label = NULL;
×
6492
  context.write_channel = MS_TRUE;
×
6493
  context.readWriteFunc = msIO_bufferWrite;
×
6494
  context.cbData = &buffer;
×
6495
  buffer.data = NULL;
×
6496
  buffer.data_len = 0;
×
6497
  buffer.data_offset = 0;
×
6498

6499
  msIO_installHandlers(NULL, &context, NULL);
×
6500

6501
  writeMap(stdout, 0, map);
×
6502
  msIO_bufferWrite(&buffer, "", 1);
×
6503

6504
  msIO_installHandlers(NULL, NULL, NULL);
×
6505

6506
  return (char *)buffer.data;
×
6507
}
6508

6509
int msSaveMap(mapObj *map, char *filename) {
1✔
6510
  FILE *stream;
6511
  char szPath[MS_MAXPATHLEN];
6512

6513
  if (!map) {
1✔
6514
    msSetError(MS_MISCERR, "Map is undefined.", "msSaveMap()");
×
6515
    return (-1);
×
6516
  }
6517

6518
  if (!filename) {
1✔
6519
    msSetError(MS_MISCERR, "Filename is undefined.", "msSaveMap()");
×
6520
    return (-1);
×
6521
  }
6522

6523
  stream = fopen(msBuildPath(szPath, map->mappath, filename), "w");
1✔
6524
  if (!stream) {
1✔
6525
    msSetErrorWithStatus(MS_IOERR, MS_HTTP_500_INTERNAL_SERVER_ERROR, "(%s)",
×
6526
                         "msSaveMap()", filename);
6527
    return (-1);
×
6528
  }
6529

6530
  writeMap(stream, 0, map);
1✔
6531
  fclose(stream);
1✔
6532

6533
  return (0);
1✔
6534
}
6535

6536
static void writeConfig(FILE *stream, int indent, configObj *config) {
×
6537
  writeBlockBegin(stream, indent, "CONFIG");
×
6538
  writeHashTable(stream, indent, "ENV", &(config->env));
×
6539
  writeHashTable(stream, indent, "MAPS", &(config->maps));
×
6540
  writeBlockEnd(stream, indent, "CONFIG");
×
6541
}
×
6542

6543
int msSaveConfig(configObj *config, const char *filename) {
×
6544
  FILE *stream;
6545

6546
  if (!config) {
×
6547
    msSetError(MS_MISCERR, "Config is undefined.", "msSaveConfigMap()");
×
6548
    return (-1);
×
6549
  }
6550

6551
  if (!filename) {
×
6552
    msSetError(MS_MISCERR, "Filename is undefined.", "msSaveConfigMap()");
×
6553
    return (-1);
×
6554
  }
6555

6556
  stream = fopen(filename, "w");
×
6557
  if (!stream) {
×
6558
    msSetErrorWithStatus(MS_IOERR, MS_HTTP_500_INTERNAL_SERVER_ERROR, "(%s)",
×
6559
                         "msSaveConfig()", filename);
6560
    return (-1);
×
6561
  }
6562

6563
  writeConfig(stream, 0, config);
×
6564
  fclose(stream);
×
6565

6566
  return (0);
×
6567
}
6568

6569
static int loadMapInternal(mapObj *map) {
3,060✔
6570
  int foundMapToken = MS_FALSE;
6571
  int foundBomToken = MS_FALSE;
6572
  int token;
6573

6574
  for (;;) {
6575

6576
    token = msyylex();
47,924✔
6577

6578
    if (!foundBomToken && token == BOM) {
47,924✔
6579
      foundBomToken = MS_TRUE;
6580
      if (!foundMapToken) {
×
6581
        continue; /*skip a leading bom*/
×
6582
      }
6583
    }
6584
    if (!foundMapToken && token != MAP) {
47,924✔
6585
      msSetError(MS_IDENTERR,
2✔
6586
                 "First token must be MAP, this doesn't look like a mapfile.",
6587
                 "msLoadMap()");
6588
      return (MS_FAILURE);
2✔
6589
    }
6590

6591
    switch (token) {
47,922✔
6592

6593
    case (CONFIG): {
88✔
6594
      char *key = NULL, *value = NULL;
88✔
6595

6596
      if (getString(&key) == MS_FAILURE)
88✔
6597
        return MS_FAILURE;
×
6598

6599
      if (getString(&value) == MS_FAILURE) {
88✔
6600
        free(key);
×
6601
        return MS_FAILURE;
×
6602
      }
6603

6604
      if (msSetConfigOption(map, key, value) == MS_FAILURE) {
88✔
6605
        free(key);
×
6606
        free(value);
×
6607
        return MS_FAILURE;
×
6608
      }
6609

6610
      free(key);
88✔
6611
      free(value);
88✔
6612
    } break;
88✔
6613
    case (DEBUG):
102✔
6614
      if ((map->debug = getSymbol(3, MS_ON, MS_OFF, MS_NUMBER)) == -1)
102✔
6615
        return MS_FAILURE;
6616
      if (map->debug == MS_NUMBER) {
102✔
6617
        if (msCheckNumber(msyynumber, MS_NUM_CHECK_RANGE, 0, 5) == MS_FAILURE) {
32✔
6618
          msSetError(MS_MISCERR,
×
6619
                     "Invalid DEBUG level, must be between 0 and 5 (line %d)",
6620
                     "msLoadMap()", msyylineno);
6621
          return (-1);
×
6622
        }
6623
        map->debug = (int)msyynumber;
32✔
6624
      }
6625
      break;
6626
    case (END):
3,056✔
6627
      if (msyyin) {
3,056✔
6628
        fclose(msyyin);
3,053✔
6629
        msyyin = NULL;
3,053✔
6630
      }
6631

6632
      /*** Make config options current ***/
6633
      msApplyMapConfigOptions(map);
3,056✔
6634

6635
      /*** Compute rotated extent info if applicable ***/
6636
      msMapComputeGeotransform(map);
3,056✔
6637

6638
      /*** OUTPUTFORMAT related setup ***/
6639
      if (msPostMapParseOutputFormatSetup(map) == MS_FAILURE)
3,056✔
6640
        return MS_FAILURE;
6641

6642
      if (loadSymbolSet(&(map->symbolset), map) == -1)
3,056✔
6643
        return MS_FAILURE;
6644

6645
      if (resolveSymbolNames(map) == MS_FAILURE)
3,056✔
6646
        return MS_FAILURE;
6647

6648
      if (msLoadFontSet(&(map->fontset), map) == -1)
3,056✔
6649
        return MS_FAILURE;
6650

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

6809
static bool msGetCWD(char *szBuffer, size_t nBufferSize,
3,060✔
6810
                     const char *pszFunctionName) {
6811
  if (NULL == getcwd(szBuffer, nBufferSize)) {
3,060✔
6812
#ifndef _WIN32
6813
    if (errno == EACCES)
×
6814
      msSetError(MS_MISCERR,
×
6815
                 "getcwd() failed with EACCES: you may need to force the "
6816
                 "current directory in the mapserver launcher "
6817
                 "(e.g -d option of spawn-fcgi)",
6818
                 pszFunctionName);
6819
    else if (errno == ENAMETOOLONG)
×
6820
      msSetError(MS_MISCERR, "getcwd() returned a too long path",
×
6821
                 pszFunctionName);
6822
    else
6823
      msSetError(MS_MISCERR, "getcwd() failed with errno code %d",
×
6824
                 pszFunctionName, errno);
6825
#else
6826
    msSetError(MS_MISCERR, "getcwd() returned a too long path",
6827
               pszFunctionName);
6828
#endif
6829
    return FALSE;
×
6830
  }
6831
  return TRUE;
6832
}
6833

6834
/*
6835
 * Apply any SLD styles referenced in a LAYER's STYLEITEM
6836
 */
6837
static void applyStyleItemToLayer(mapObj *map) {
3,056✔
6838

6839
  // applying SLD can create cloned layers so store the original layer count
6840
  int layerCount = map->numlayers;
3,056✔
6841

6842
  for (int i = 0; i < layerCount; i++) {
15,976✔
6843
    layerObj *layer = GET_LAYER(map, i);
12,920✔
6844

6845
    if (layer->styleitem && STARTS_WITH_CI(layer->styleitem, "sld://")) {
12,920✔
6846
      const char *filename = layer->styleitem + strlen("sld://");
123✔
6847

6848
      if (*filename == '\0') {
123✔
6849
        msSetErrorWithStatus(MS_IOERR, MS_HTTP_500_INTERNAL_SERVER_ERROR,
×
6850
                             "Empty SLD filename: \"%s\".",
6851
                             "applyLayerDefaultSubstitutions()",
6852
                             layer->styleitem);
6853
      } else {
6854
        msSLDApplyFromFile(map, layer, filename);
123✔
6855
      }
6856
    }
6857
  }
6858
}
3,056✔
6859

6860
/*
6861
** Sets up string-based mapfile loading and calls loadMapInternal to do the
6862
*work.
6863
*/
6864
mapObj *msLoadMapFromString(char *buffer, char *new_mappath,
3✔
6865
                            const configObj *config) {
6866
  mapObj *map;
6867
  struct mstimeval starttime = {0}, endtime = {0};
3✔
6868
  char szPath[MS_MAXPATHLEN], szCWDPath[MS_MAXPATHLEN];
6869
  char *mappath = NULL;
6870
  int debuglevel;
6871

6872
  debuglevel = (int)msGetGlobalDebugLevel();
3✔
6873

6874
  if (debuglevel >= MS_DEBUGLEVEL_TUNING) {
3✔
6875
    /* In debug mode, track time spent loading/parsing mapfile. */
6876
    msGettimeofday(&starttime, NULL);
×
6877
  }
6878

6879
  if (!buffer) {
3✔
6880
    msSetError(MS_MISCERR, "No buffer to load.", "msLoadMapFromString()");
×
6881
    return (NULL);
×
6882
  }
6883

6884
  /*
6885
  ** Allocate mapObj structure
6886
  */
6887
  map = (mapObj *)calloc(1, sizeof(mapObj));
3✔
6888
  MS_CHECK_ALLOC(map, sizeof(mapObj), NULL);
3✔
6889

6890
  if (initMap(map) == -1) { /* initialize this map */
3✔
6891
    msFreeMap(map);
×
6892
    return (NULL);
×
6893
  }
6894

6895
  map->config = config; // create a read-only reference
3✔
6896

6897
  msAcquireLock(TLOCK_PARSER); /* might need to move this lock a bit higher, yup
3✔
6898
                                  (bug 2108) */
6899

6900
  msyystate = MS_TOKENIZE_STRING;
3✔
6901
  msyystring = buffer;
3✔
6902
  msyylex(); /* sets things up, but doesn't process any tokens */
3✔
6903

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

6906
  /* If new_mappath is provided then use it, otherwise use the CWD */
6907
  if (!msGetCWD(szCWDPath, MS_MAXPATHLEN, "msLoadMapFromString()")) {
3✔
6908
    msFreeMap(map);
×
6909
    msReleaseLock(TLOCK_PARSER);
×
6910
    return (NULL);
×
6911
  }
6912
  if (new_mappath) {
3✔
6913
    mappath = msStrdup(new_mappath);
×
6914
    map->mappath = msStrdup(msBuildPath(szPath, szCWDPath, mappath));
×
6915
  } else
6916
    map->mappath = msStrdup(szCWDPath);
3✔
6917

6918
  msyybasepath = map->mappath; /* for INCLUDEs */
3✔
6919

6920
  if (loadMapInternal(map) != MS_SUCCESS) {
3✔
6921
    msFreeMap(map);
×
6922
    msReleaseLock(TLOCK_PARSER);
×
6923
    if (mappath != NULL)
×
6924
      free(mappath);
×
6925
    return NULL;
×
6926
  }
6927

6928
  if (mappath != NULL)
3✔
6929
    free(mappath);
×
6930
  msyylex_destroy();
3✔
6931

6932
  msReleaseLock(TLOCK_PARSER);
3✔
6933

6934
  applyStyleItemToLayer(map);
3✔
6935

6936
  if (debuglevel >= MS_DEBUGLEVEL_TUNING) {
3✔
6937
    /* In debug mode, report time spent loading/parsing mapfile. */
6938
    msGettimeofday(&endtime, NULL);
×
6939
    msDebug("msLoadMapFromString(): %.3fs\n",
×
6940
            (endtime.tv_sec + endtime.tv_usec / 1.0e6) -
×
6941
                (starttime.tv_sec + starttime.tv_usec / 1.0e6));
×
6942
  }
6943

6944
  if (resolveSymbolNames(map) == MS_FAILURE)
3✔
6945
    return NULL;
6946

6947
  return map;
6948
}
6949

6950
/*
6951
** Sets up file-based mapfile loading and calls loadMapInternal to do the work.
6952
*/
6953
mapObj *msLoadMap(const char *filename, const char *new_mappath,
3,060✔
6954
                  const configObj *config) {
6955
  mapObj *map;
6956
  struct mstimeval starttime = {0}, endtime = {0};
3,060✔
6957
  char szPath[MS_MAXPATHLEN], szCWDPath[MS_MAXPATHLEN];
6958
  int debuglevel;
6959

6960
  debuglevel = (int)msGetGlobalDebugLevel();
3,060✔
6961

6962
  if (debuglevel >= MS_DEBUGLEVEL_TUNING) {
3,060✔
6963
    /* In debug mode, track time spent loading/parsing mapfile. */
6964
    msGettimeofday(&starttime, NULL);
×
6965
  }
6966

6967
  if (!filename) {
3,060✔
6968
    msSetError(MS_MISCERR, "Filename is undefined.", "msLoadMap()");
×
6969
    return (NULL);
×
6970
  }
6971

6972
  const char *ms_mapfile_pattern =
6973
      CPLGetConfigOption("MS_MAPFILE_PATTERN", MS_DEFAULT_MAPFILE_PATTERN);
3,060✔
6974
  if (msEvalRegex(ms_mapfile_pattern, filename) != MS_TRUE) {
3,060✔
6975
    msSetError(MS_REGEXERR, "Filename validation failed.", "msLoadMap()");
×
6976
    return (NULL);
×
6977
  }
6978

6979
  /*
6980
  ** Allocate mapObj structure
6981
  */
6982
  map = (mapObj *)calloc(1, sizeof(mapObj));
3,060✔
6983
  MS_CHECK_ALLOC(map, sizeof(mapObj), NULL);
3,060✔
6984

6985
  if (initMap(map) == -1) { /* initialize this map */
3,060✔
6986
    msFreeMap(map);
×
6987
    return (NULL);
×
6988
  }
6989

6990
  map->config = config; // create a read-only reference
3,060✔
6991

6992
  msAcquireLock(TLOCK_PARSER); /* Steve: might need to move this lock a bit
3,060✔
6993
                                  higher; Umberto: done */
6994

6995
#ifdef USE_XMLMAPFILE
6996
  /* If the mapfile is an xml mapfile, transform it */
6997
  const char *ms_xmlmapfile_xslt =
6998
      CPLGetConfigOption("MS_XMLMAPFILE_XSLT", NULL);
6999
  if (ms_xmlmapfile_xslt &&
7000
      (msEvalRegex(MS_DEFAULT_XMLMAPFILE_PATTERN, filename) == MS_TRUE)) {
7001

7002
    msyyin = tmpfile();
7003
    if (msyyin == NULL) {
7004
      msSetErrorWithStatus(MS_IOERR, MS_HTTP_500_INTERNAL_SERVER_ERROR,
7005
                           "tmpfile() failed to create temporary file",
7006
                           "msLoadMap()");
7007
      msReleaseLock(TLOCK_PARSER);
7008
      msFreeMap(map);
7009
      return NULL;
7010
    }
7011

7012
    if (msTransformXmlMapfile(ms_xmlmapfile_xslt, filename, msyyin) !=
7013
        MS_SUCCESS) {
7014
      fclose(msyyin);
7015
      msFreeMap(map);
7016
      return NULL;
7017
    }
7018
    fseek(msyyin, 0, SEEK_SET);
7019
  } else {
7020
#endif
7021
    if ((msyyin = fopen(filename, "r")) == NULL) {
3,060✔
7022
      msSetErrorWithStatus(MS_IOERR, MS_HTTP_500_INTERNAL_SERVER_ERROR, "(%s)",
3✔
7023
                           "msLoadMap()", filename);
7024
      msReleaseLock(TLOCK_PARSER);
3✔
7025
      msFreeMap(map);
3✔
7026
      return NULL;
3✔
7027
    }
7028
#ifdef USE_XMLMAPFILE
7029
  }
7030
#endif
7031

7032
  msyystate = MS_TOKENIZE_FILE;
3,057✔
7033
  msyylex(); /* sets things up, but doesn't process any tokens */
3,057✔
7034

7035
  msyyrestart(msyyin); /* start at line beginning, line 1 */
3,057✔
7036
  msyylineno = 1;
3,057✔
7037

7038
  /* If new_mappath is provided then use it, otherwise use the location */
7039
  /* of the mapfile as the default path */
7040
  if (!msGetCWD(szCWDPath, MS_MAXPATHLEN, "msLoadMap()")) {
3,057✔
7041
    msReleaseLock(TLOCK_PARSER);
×
7042
    msFreeMap(map);
×
7043
    return NULL;
×
7044
  }
7045

7046
  if (new_mappath)
3,057✔
7047
    map->mappath = msStrdup(msBuildPath(szPath, szCWDPath, new_mappath));
×
7048
  else {
7049
    char *path = msGetPath(filename);
3,057✔
7050
    map->mappath = msStrdup(msBuildPath(szPath, szCWDPath, path));
3,057✔
7051
    free(path);
3,057✔
7052
  }
7053

7054
  msyybasepath = map->mappath; /* for INCLUDEs */
3,057✔
7055

7056
  if (loadMapInternal(map) != MS_SUCCESS) {
3,057✔
7057
    msFreeMap(map);
4✔
7058
    if (msyyin) {
4✔
7059
      msyycleanup_includes();
4✔
7060
      fclose(msyyin);
4✔
7061
      msyyin = NULL;
4✔
7062
    }
7063
    msReleaseLock(TLOCK_PARSER);
4✔
7064
    return NULL;
4✔
7065
  }
7066
  msReleaseLock(TLOCK_PARSER);
3,053✔
7067

7068
  applyStyleItemToLayer(map);
3,053✔
7069

7070
  if (debuglevel >= MS_DEBUGLEVEL_TUNING) {
3,053✔
7071
    /* In debug mode, report time spent loading/parsing mapfile. */
7072
    msGettimeofday(&endtime, NULL);
×
7073
    msDebug("msLoadMap(): %.3fs\n",
×
7074
            (endtime.tv_sec + endtime.tv_usec / 1.0e6) -
×
7075
                (starttime.tv_sec + starttime.tv_usec / 1.0e6));
×
7076
  }
7077

7078
  return map;
7079
}
7080

7081
static void hashTableSubstituteString(hashTableObj *hash, const char *from,
238✔
7082
                                      const char *to) {
7083
  const char *key, *val;
7084
  char *new_val;
7085
  key = msFirstKeyFromHashTable(hash);
238✔
7086
  while (key != NULL) {
311✔
7087
    val = msLookupHashTable(hash, key);
73✔
7088
    if (strcasestr(val, from)) {
73✔
7089
      new_val = msCaseReplaceSubstring(msStrdup(val), from, to);
15✔
7090
      msInsertHashTable(hash, key, new_val);
15✔
7091
      msFree(new_val);
15✔
7092
    }
7093
    key = msNextKeyFromHashTable(hash, key);
73✔
7094
  }
7095
}
238✔
7096

7097
static void classSubstituteString(classObj *class, const char *from,
164✔
7098
                                  const char *to) {
7099
  if (class->expression.string)
164✔
7100
    class->expression.string =
16✔
7101
        msCaseReplaceSubstring(class->expression.string, from, to);
16✔
7102
  if (class->text.string)
164✔
7103
    class->text.string = msCaseReplaceSubstring(class->text.string, from, to);
×
7104
  if (class->title)
164✔
7105
    class->title = msCaseReplaceSubstring(class->title, from, to);
×
7106
}
164✔
7107

7108
static void layerSubstituteString(layerObj *layer, const char *from,
114✔
7109
                                  const char *to) {
7110
  int c;
7111
  if (layer->data)
114✔
7112
    layer->data = msCaseReplaceSubstring(layer->data, from, to);
112✔
7113
  if (layer->tileindex)
114✔
7114
    layer->tileindex = msCaseReplaceSubstring(layer->tileindex, from, to);
×
7115
  if (layer->connection)
114✔
7116
    layer->connection = msCaseReplaceSubstring(layer->connection, from, to);
10✔
7117
  if (layer->filter.string)
114✔
7118
    layer->filter.string =
2✔
7119
        msCaseReplaceSubstring(layer->filter.string, from, to);
2✔
7120
  if (layer->mask)
114✔
7121
    layer->mask = msCaseReplaceSubstring(layer->mask, from, to); // new for 8.0
×
7122

7123
  /* The bindvalues are most useful when able to substitute values from the URL
7124
   */
7125
  hashTableSubstituteString(&layer->bindvals, from, to);
114✔
7126
  hashTableSubstituteString(&layer->metadata, from, to);
114✔
7127
  msLayerSubstituteProcessing(layer, from, to);
114✔
7128
  for (c = 0; c < layer->numclasses; c++) {
234✔
7129
    classSubstituteString(layer->class[c], from, to);
120✔
7130
  }
7131
}
114✔
7132

7133
static void mapSubstituteString(mapObj *map, const char *from, const char *to) {
6✔
7134
  int l;
7135
  for (l = 0; l < map->numlayers; l++) {
44✔
7136
    layerSubstituteString(GET_LAYER(map, l), from, to);
38✔
7137
  }
7138

7139
  /* output formats (#3751) */
7140
  for (l = 0; l < map->numoutputformats; l++) {
13✔
7141
    int o;
7142
    for (o = 0; o < map->outputformatlist[l]->numformatoptions; o++) {
13✔
7143
      map->outputformatlist[l]->formatoptions[o] = msCaseReplaceSubstring(
6✔
7144
          map->outputformatlist[l]->formatoptions[o], from, to);
6✔
7145
    }
7146
  }
7147

7148
  hashTableSubstituteString(&map->web.metadata, from, to);
6✔
7149
  if (map->web.template)
6✔
7150
    map->web.template = msCaseReplaceSubstring(map->web.template, from, to);
×
7151
}
6✔
7152

7153
static void applyOutputFormatDefaultSubstitutions(outputFormatObj *format,
7,118✔
7154
                                                  const char *option,
7155
                                                  hashTableObj *table) {
7156
  const char *filename;
7157

7158
  filename = msGetOutputFormatOption(format, option, NULL);
7,118✔
7159
  if (filename && strlen(filename) > 0) {
7,118✔
7160
    char *tmpfilename = msStrdup(filename);
535✔
7161
    const char *default_key = msFirstKeyFromHashTable(table);
535✔
7162
    while (default_key) {
547✔
7163
      if (!strncasecmp(default_key, "default_", 8)) {
12✔
7164
        char *new_filename = NULL;
7165
        size_t buffer_size = (strlen(default_key) - 5);
6✔
7166
        char *tag = (char *)msSmallMalloc(buffer_size);
6✔
7167
        snprintf(tag, buffer_size, "%%%s%%", &(default_key[8]));
6✔
7168

7169
        new_filename = msStrdup(tmpfilename);
6✔
7170
        new_filename = msCaseReplaceSubstring(
6✔
7171
            new_filename, tag, msLookupHashTable(table, default_key));
7172
        free(tag);
6✔
7173

7174
        msSetOutputFormatOption(format, option, new_filename);
6✔
7175
        free(new_filename);
6✔
7176
      }
7177
      default_key = msNextKeyFromHashTable(table, default_key);
12✔
7178
    }
7179
    msFree(tmpfilename);
535✔
7180
  }
7181
  return;
7,118✔
7182
}
7183

7184
static void applyClassDefaultSubstitutions(classObj *class,
11,593✔
7185
                                           hashTableObj *table) {
7186
  const char *default_key = msFirstKeyFromHashTable(table);
11,593✔
7187
  while (default_key) {
11,606✔
7188
    if (!strncasecmp(default_key, "default_", 8)) {
13✔
7189
      size_t buffer_size = (strlen(default_key) - 5);
×
7190
      char *tag = (char *)msSmallMalloc(buffer_size);
×
7191
      snprintf(tag, buffer_size, "%%%s%%", &(default_key[8]));
×
7192

7193
      classSubstituteString(class, tag, msLookupHashTable(table, default_key));
×
7194
      free(tag);
×
7195
    }
7196
    default_key = msNextKeyFromHashTable(table, default_key);
13✔
7197
  }
7198
  return;
11,593✔
7199
}
7200

7201
static void applyLayerDefaultSubstitutions(layerObj *layer,
19,526✔
7202
                                           hashTableObj *table) {
7203
  int i;
7204
  const char *default_key = msFirstKeyFromHashTable(table);
19,526✔
7205
  while (default_key) {
20,393✔
7206
    if (!strncasecmp(default_key, "default_", 8)) {
867✔
7207
      size_t buffer_size = (strlen(default_key) - 5);
42✔
7208
      const char *to = msLookupHashTable(table, default_key);
42✔
7209
      char *tag = (char *)msSmallMalloc(buffer_size);
42✔
7210
      snprintf(tag, buffer_size, "%%%s%%", &(default_key[8]));
42✔
7211

7212
      for (i = 0; i < layer->numclasses; i++) {
84✔
7213
        classSubstituteString(layer->class[i], tag, to);
42✔
7214
      }
7215
      layerSubstituteString(layer, tag, to);
42✔
7216
      free(tag);
42✔
7217
    }
7218
    default_key = msNextKeyFromHashTable(table, default_key);
867✔
7219
  }
7220

7221
  return;
19,526✔
7222
}
7223

7224
static void applyHashTableDefaultSubstitutions(hashTableObj *hashTab,
2,570✔
7225
                                               hashTableObj *table) {
7226
  const char *default_key = msFirstKeyFromHashTable(table);
2,570✔
7227
  while (default_key) {
2,665✔
7228
    if (!strncasecmp(default_key, "default_", 8)) {
95✔
7229
      size_t buffer_size = (strlen(default_key) - 5);
4✔
7230
      const char *to = msLookupHashTable(table, default_key);
4✔
7231
      char *tag = (char *)msSmallMalloc(buffer_size);
4✔
7232
      snprintf(tag, buffer_size, "%%%s%%", &(default_key[8]));
4✔
7233

7234
      hashTableSubstituteString(hashTab, tag, to);
4✔
7235
      free(tag);
4✔
7236
    }
7237
    default_key = msNextKeyFromHashTable(table, default_key);
95✔
7238
  }
7239
  return;
2,570✔
7240
}
7241

7242
/*
7243
** Loop through layer metadata for keys that have a default_%key% pattern to
7244
*replace
7245
** remaining %key% entries by their default value.
7246
*/
7247
void msApplyDefaultSubstitutions(mapObj *map) {
2,570✔
7248
  int i, j;
7249

7250
  /* output formats (#3751) */
7251
  for (i = 0; i < map->numoutputformats; i++) {
6,129✔
7252
    applyOutputFormatDefaultSubstitutions(map->outputformatlist[i], "filename",
3,559✔
7253
                                          &(map->web.validation));
7254
    applyOutputFormatDefaultSubstitutions(map->outputformatlist[i], "JSONP",
3,559✔
7255
                                          &(map->web.validation));
7256
  }
7257

7258
  for (i = 0; i < map->numlayers; i++) {
12,333✔
7259
    layerObj *layer = GET_LAYER(map, i);
9,763✔
7260

7261
    for (j = 0; j < layer->numclasses;
21,356✔
7262
         j++) { /* class settings take precedence...  */
11,593✔
7263
      classObj *class = GET_CLASS(map, i, j);
11,593✔
7264
      applyClassDefaultSubstitutions(class, &(class->validation));
11,593✔
7265
    }
7266

7267
    applyLayerDefaultSubstitutions(
9,763✔
7268
        layer, &(layer->validation)); /* ...then layer settings... */
7269
    applyLayerDefaultSubstitutions(
9,763✔
7270
        layer, &(map->web.validation)); /* ...and finally web settings */
7271
  }
7272
  applyHashTableDefaultSubstitutions(&map->web.metadata,
2,570✔
7273
                                     &(map->web.validation));
7274
}
2,570✔
7275

7276
char *_get_param_value(const char *key, char **names, char **values,
444✔
7277
                       int npairs) {
7278
  if (npairs <= 0)
444✔
7279
    return NULL; // bail, no point searching
7280

7281
  if (getenv(key)) { /* environment override */
438✔
7282
    return getenv(key);
1✔
7283
  }
7284
  while (npairs) {
2,331✔
7285
    npairs--;
1,938✔
7286
    if (strcasecmp(key, names[npairs]) == 0) {
1,938✔
7287
      return values[npairs];
44✔
7288
    }
7289
  }
7290
  return NULL;
7291
}
7292

7293
void msApplySubstitutions(mapObj *map, char **names, char **values,
1,973✔
7294
                          int npairs) {
7295
  int l;
7296
  const char *key, *value, *validation;
7297
  char *tag;
7298
  for (l = 0; l < map->numlayers; l++) {
10,065✔
7299
    int c;
7300
    layerObj *lp = GET_LAYER(map, l);
8,092✔
7301
    for (c = 0; c < lp->numclasses; c++) {
17,978✔
7302
      classObj *cp = lp->class[c];
9,886✔
7303
      key = NULL;
7304
      while ((key = msNextKeyFromHashTable(&cp->validation, key))) {
9,899✔
7305
        value = _get_param_value(key, names, values, npairs);
13✔
7306
        if (!value)
13✔
7307
          continue; /*parameter was not in url*/
11✔
7308
        validation = msLookupHashTable(&cp->validation, key);
2✔
7309
        if (msEvalRegex(validation, value)) {
2✔
7310
          /* we've found a substitution and it validates correctly, now let's
7311
           * apply it */
7312
          tag = msSmallMalloc(strlen(key) + 3);
2✔
7313
          sprintf(tag, "%%%s%%", key);
7314
          classSubstituteString(cp, tag, value);
2✔
7315
          free(tag);
2✔
7316
        } else {
7317
          msSetError(MS_REGEXERR, "Parameter pattern validation failed.",
×
7318
                     "msApplySubstitutions()");
7319
          if (map->debug || lp->debug) {
×
7320
            msDebug("layer (%s), class %d: failed to validate (%s=%s) for "
×
7321
                    "regex (%s)\n",
7322
                    lp->name, c, key, value, validation);
7323
          }
7324
        }
7325
      }
7326
    }
7327
    key = NULL;
7328
    while ((key = msNextKeyFromHashTable(&lp->validation, key))) {
8,428✔
7329
      value = _get_param_value(key, names, values, npairs);
336✔
7330
      if (!value)
336✔
7331
        continue; /*parameter was not in url*/
301✔
7332
      validation = msLookupHashTable(&lp->validation, key);
35✔
7333
      if (msEvalRegex(validation, value)) {
35✔
7334
        /* we've found a substitution and it validates correctly, now let's
7335
         * apply it */
7336
        tag = msSmallMalloc(strlen(key) + 3);
34✔
7337
        sprintf(tag, "%%%s%%", key);
7338
        layerSubstituteString(lp, tag, value);
34✔
7339
        free(tag);
34✔
7340
      } else {
7341
        msSetError(MS_REGEXERR, "Parameter pattern validation failed.",
1✔
7342
                   "msApplySubstitutions()");
7343
        if (map->debug || lp->debug) {
1✔
7344
          msDebug("layer (%s): failed to validate (%s=%s) for regex (%s)\n",
×
7345
                  lp->name, key, value, validation);
7346
        }
7347
      }
7348
    }
7349
  }
7350
  key = NULL;
7351
  while ((key = msNextKeyFromHashTable(&map->web.validation, key))) {
2,068✔
7352
    value = _get_param_value(key, names, values, npairs);
95✔
7353
    if (!value)
95✔
7354
      continue; /*parameter was not in url*/
87✔
7355
    validation = msLookupHashTable(&map->web.validation, key);
8✔
7356
    if (msEvalRegex(validation, value)) {
8✔
7357
      /* we've found a substitution and it validates correctly, now let's apply
7358
       * it */
7359
      tag = msSmallMalloc(strlen(key) + 3);
6✔
7360
      sprintf(tag, "%%%s%%", key);
7361
      mapSubstituteString(map, tag, value);
6✔
7362
      free(tag);
6✔
7363
    } else {
7364
      msSetError(MS_REGEXERR, "Parameter pattern validation failed.",
2✔
7365
                 "msApplySubstitutions()");
7366
      if (map->debug) {
2✔
7367
        msDebug("failed to validate (%s=%s) for regex (%s)\n", key, value,
×
7368
                validation);
7369
      }
7370
    }
7371
  }
7372
}
1,973✔
7373

7374
/*
7375
** Returns an array with one entry per mapfile token.  Useful to manipulate
7376
** mapfiles in MapScript.
7377
**
7378
** The returned array should be freed using msFreeCharArray().
7379
*/
7380
static char **tokenizeMapInternal(char *filename, int *ret_numtokens) {
×
7381
  char **tokens = NULL;
7382
  int numtokens = 0, numtokens_allocated = 0;
7383
  size_t buffer_size = 0;
7384

7385
  *ret_numtokens = 0;
×
7386

7387
  if (!filename) {
×
7388
    msSetError(MS_MISCERR, "Filename is undefined.", "msTokenizeMap()");
×
7389
    return NULL;
×
7390
  }
7391

7392
  /*
7393
  ** Check map filename to make sure it's legal
7394
  */
7395
  const char *ms_mapfile_pattern =
7396
      CPLGetConfigOption("MS_MAPFILE_PATTERN", MS_DEFAULT_MAPFILE_PATTERN);
×
7397
  if (msEvalRegex(ms_mapfile_pattern, filename) != MS_TRUE) {
×
7398
    msSetError(MS_REGEXERR, "Filename validation failed.", "msTokenizeMap()");
×
7399
    return (NULL);
×
7400
  }
7401

7402
  if ((msyyin = fopen(filename, "r")) == NULL) {
×
7403
    msSetErrorWithStatus(MS_IOERR, MS_HTTP_500_INTERNAL_SERVER_ERROR, "(%s)",
×
7404
                         "msTokenizeMap()", filename);
7405
    return NULL;
×
7406
  }
7407

7408
  msyystate = MS_TOKENIZE_FILE; /* restore lexer state to INITIAL, and do return
×
7409
                                   comments */
7410
  msyylex();
×
7411
  msyyreturncomments = 1; /* want all tokens, including comments */
×
7412

7413
  msyyrestart(msyyin); /* start at line beginning, line 1 */
×
7414
  msyylineno = 1;
×
7415

7416
  numtokens = 0;
7417
  numtokens_allocated = 256;
7418
  tokens = (char **)malloc(numtokens_allocated * sizeof(char *));
×
7419
  if (tokens == NULL) {
×
7420
    msSetError(MS_MEMERR, NULL, "msTokenizeMap()");
×
7421
    fclose(msyyin);
×
7422
    return NULL;
×
7423
  }
7424

7425
  for (;;) {
7426

7427
    if (numtokens_allocated <= numtokens) {
×
7428
      numtokens_allocated *=
×
7429
          2; /* double size of the array every time we reach the limit */
7430
      char **tokensNew =
7431
          (char **)realloc(tokens, numtokens_allocated * sizeof(char *));
×
7432
      if (tokensNew == NULL) {
×
7433
        msSetError(MS_MEMERR, "Realloc() error.", "msTokenizeMap()");
×
7434
        fclose(msyyin);
×
7435
        for (int i = 0; i < numtokens; i++)
×
7436
          msFree(tokens[i]);
×
7437
        msFree(tokens);
×
7438
        return NULL;
×
7439
      }
7440
      tokens = tokensNew;
7441
    }
7442

7443
    switch (msyylex()) {
×
7444
    case (EOF): /* This is the normal way out... cleanup and exit */
×
7445
      fclose(msyyin);
×
7446
      *ret_numtokens = numtokens;
×
7447
      return (tokens);
×
7448
      break;
7449
    case (MS_STRING):
×
7450
      buffer_size = strlen(msyystring_buffer) + 2 + 1;
×
7451
      tokens[numtokens] = (char *)msSmallMalloc(buffer_size);
×
7452
      snprintf(tokens[numtokens], buffer_size, "\"%s\"", msyystring_buffer);
×
7453
      break;
7454
    case (MS_EXPRESSION):
×
7455
      buffer_size = strlen(msyystring_buffer) + 2 + 1;
×
7456
      tokens[numtokens] = (char *)msSmallMalloc(buffer_size);
×
7457
      snprintf(tokens[numtokens], buffer_size, "(%s)", msyystring_buffer);
×
7458
      break;
7459
    case (MS_REGEX):
×
7460
      buffer_size = strlen(msyystring_buffer) + 2 + 1;
×
7461
      tokens[numtokens] = (char *)msSmallMalloc(buffer_size);
×
7462
      snprintf(tokens[numtokens], buffer_size, "/%s/", msyystring_buffer);
×
7463
      break;
7464
    default:
×
7465
      tokens[numtokens] = msStrdup(msyystring_buffer);
×
7466
      break;
×
7467
    }
7468

7469
    if (tokens[numtokens] == NULL) {
×
7470
      int i;
7471
      msSetError(MS_MEMERR, NULL, "msTokenizeMap()");
×
7472
      fclose(msyyin);
×
7473
      for (i = 0; i < numtokens; i++)
×
7474
        msFree(tokens[i]);
×
7475
      msFree(tokens);
×
7476
      return NULL;
×
7477
    }
7478

7479
    numtokens++;
×
7480
  }
7481

7482
  return NULL; /* should never get here */
7483
}
7484

7485
/*
7486
** Wraps tokenizeMapInternal
7487
*/
7488
char **msTokenizeMap(char *filename, int *numtokens) {
×
7489
  char **tokens;
7490

7491
  msAcquireLock(TLOCK_PARSER);
×
7492
  tokens = tokenizeMapInternal(filename, numtokens);
×
7493
  msReleaseLock(TLOCK_PARSER);
×
7494

7495
  return tokens;
×
7496
}
7497

7498
void msCloseConnections(mapObj *map) {
3,146✔
7499
  int i;
7500
  layerObj *lp;
7501

7502
  for (i = 0; i < map->numlayers; i++) {
16,440✔
7503
    lp = (GET_LAYER(map, i));
13,294✔
7504

7505
    /* If the vtable is null, then the layer is never accessed or used -> skip
7506
     * it
7507
     */
7508
    if (lp->vtable) {
13,294✔
7509
      lp->vtable->LayerCloseConnection(lp);
3,367✔
7510
    }
7511
  }
7512
}
3,146✔
7513

7514
void initResultCache(resultCacheObj *resultcache) {
1,839✔
7515
  if (resultcache) {
1,839✔
7516
    resultcache->results = NULL;
1,839✔
7517
    resultcache->numresults = 0;
1,839✔
7518
    resultcache->cachesize = 0;
1,839✔
7519
    resultcache->bounds.minx = resultcache->bounds.miny =
1,839✔
7520
        resultcache->bounds.maxx = resultcache->bounds.maxy = -1;
1,839✔
7521
    resultcache->previousBounds = resultcache->bounds;
1,839✔
7522
  }
7523
}
1,839✔
7524

7525
void cleanupResultCache(resultCacheObj *resultcache) {
947✔
7526
  if (resultcache) {
947✔
7527
    if (resultcache->results) {
947✔
7528
      int i;
7529
      for (i = 0; i < resultcache->numresults; i++) {
4,965✔
7530
        if (resultcache->results[i].shape) {
4,246✔
7531
          msFreeShape(resultcache->results[i].shape);
12✔
7532
          msFree(resultcache->results[i].shape);
12✔
7533
        }
7534
      }
7535
      free(resultcache->results);
719✔
7536
    }
7537
    resultcache->results = NULL;
947✔
7538
    initResultCache(resultcache);
947✔
7539
  }
7540
}
947✔
7541

7542
static int resolveSymbolNames(mapObj *map) {
3,059✔
7543
  int i, j;
7544

7545
  /* step through layers and classes to resolve symbol names */
7546
  for (i = 0; i < map->numlayers; i++) {
15,981✔
7547
    for (j = 0; j < GET_LAYER(map, i)->numclasses; j++) {
25,847✔
7548
      if (classResolveSymbolNames(GET_LAYER(map, i)->class[j]) != MS_SUCCESS)
12,925✔
7549
        return MS_FAILURE;
7550
    }
7551
  }
7552

7553
  return MS_SUCCESS;
7554
}
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