Coverage Report

Created: 2026-04-16 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgis/liblwgeom/lwutil.c
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * PostGIS - Spatial Types for PostgreSQL
4
 * http://postgis.net
5
 *
6
 * PostGIS is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * PostGIS is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with PostGIS.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 **********************************************************************
20
 *
21
 * Copyright (C) 2004-2015 Sandro Santilli <strk@kbt.io>
22
 * Copyright (C) 2006 Mark Leslie <mark.leslie@lisasoft.com>
23
 * Copyright (C) 2008-2009 Mark Cave-Ayland <mark.cave-ayland@siriusit.co.uk>
24
 * Copyright (C) 2009-2015 Paul Ramsey <pramsey@cleverelephant.ca>
25
 * Copyright (C) 2010 Olivier Courtin <olivier.courtin@camptocamp.com>
26
 *
27
 **********************************************************************/
28
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <stdarg.h>
32
#include <string.h>
33
#include <ctype.h> /* for tolower */
34
35
/* Global variables */
36
#include "../postgis_config.h"
37
#include "liblwgeom_internal.h"
38
#include "stringbuffer.h"
39
#include "lwgeom_log.h"
40
41
/* Default allocators */
42
static void * default_allocator(size_t size);
43
static void default_freeor(void *mem);
44
static void * default_reallocator(void *mem, size_t size);
45
lwallocator lwalloc_var = default_allocator;
46
lwreallocator lwrealloc_var = default_reallocator;
47
lwfreeor lwfree_var = default_freeor;
48
49
/* Default reporters */
50
static void default_noticereporter(const char *fmt, va_list ap) __attribute__ ((format (printf, 1, 0)));
51
static void default_errorreporter(const char *fmt, va_list ap) __attribute__ ((format (printf, 1, 0)));
52
lwreporter lwnotice_var = default_noticereporter;
53
lwreporter lwerror_var = default_errorreporter;
54
55
/* Default logger */
56
static void default_debuglogger(int level, const char *fmt, va_list ap) __attribute__ ((format (printf, 2, 0)));
57
lwdebuglogger lwdebug_var = default_debuglogger;
58
59
0
#define LW_MSG_MAXLEN 256
60
61
static char *lwgeomTypeName[] =
62
{
63
  "Unknown",
64
  "Point",
65
  "LineString",
66
  "Polygon",
67
  "MultiPoint",
68
  "MultiLineString",
69
  "MultiPolygon",
70
  "GeometryCollection",
71
  "CircularString",
72
  "CompoundCurve",
73
  "CurvePolygon",
74
  "MultiCurve",
75
  "MultiSurface",
76
  "PolyhedralSurface",
77
  "Triangle",
78
  "Tin"
79
};
80
81
/*
82
 * Default allocators
83
 *
84
 * We include some default allocators that use malloc/free/realloc
85
 * along with stdout/stderr since this is the most common use case
86
 *
87
 */
88
89
static void *
90
default_allocator(size_t size)
91
0
{
92
0
  void *mem = malloc(size);
93
0
  return mem;
94
0
}
95
96
static void
97
default_freeor(void *mem)
98
0
{
99
0
  free(mem);
100
0
}
101
102
static void *
103
default_reallocator(void *mem, size_t size)
104
0
{
105
0
  void *ret = realloc(mem, size);
106
0
  return ret;
107
0
}
108
109
/*
110
 * Default lwnotice/lwerror handlers
111
 *
112
 * Since variadic functions cannot pass their parameters directly, we need
113
 * wrappers for these functions to convert the arguments into a va_list
114
 * structure.
115
 */
116
117
static void
118
default_noticereporter(const char *fmt, va_list ap)
119
0
{
120
0
  char msg[LW_MSG_MAXLEN+1];
121
0
  vsnprintf (msg, LW_MSG_MAXLEN, fmt, ap);
122
0
  msg[LW_MSG_MAXLEN]='\0';
123
0
  fprintf(stderr, "%s\n", msg);
124
0
}
125
126
static void
127
default_debuglogger(int level, const char *fmt, va_list ap)
128
0
{
129
0
  char msg[LW_MSG_MAXLEN+1];
130
0
  if ( POSTGIS_DEBUG_LEVEL >= level )
131
0
  {
132
    /* Space pad the debug output */
133
0
    int i;
134
0
    for ( i = 0; i < level; i++ )
135
0
      msg[i] = ' ';
136
0
    vsnprintf(msg+i, LW_MSG_MAXLEN-i, fmt, ap);
137
0
    msg[LW_MSG_MAXLEN]='\0';
138
0
    fprintf(stderr, "%s\n", msg);
139
0
  }
140
0
}
141
142
static void
143
default_errorreporter(const char *fmt, va_list ap)
144
0
{
145
0
  char msg[LW_MSG_MAXLEN+1];
146
0
  vsnprintf (msg, LW_MSG_MAXLEN, fmt, ap);
147
0
  msg[LW_MSG_MAXLEN]='\0';
148
0
  fprintf(stderr, "%s\n", msg);
149
0
  exit(1);
150
0
}
151
152
/**
153
 * This function is called by programs which want to set up custom handling
154
 * for memory management and error reporting
155
 *
156
 * Only non-NULL values change their respective handler
157
 */
158
void
159
lwgeom_set_handlers(lwallocator allocator, lwreallocator reallocator,
160
          lwfreeor freeor, lwreporter errorreporter,
161
6
          lwreporter noticereporter) {
162
163
6
  if ( allocator ) lwalloc_var = allocator;
164
6
  if ( reallocator ) lwrealloc_var = reallocator;
165
6
  if ( freeor ) lwfree_var = freeor;
166
167
6
  if ( errorreporter ) lwerror_var = errorreporter;
168
6
  if ( noticereporter ) lwnotice_var = noticereporter;
169
6
}
170
171
void
172
6
lwgeom_set_debuglogger(lwdebuglogger debuglogger) {
173
174
6
  if ( debuglogger ) lwdebug_var = debuglogger;
175
6
}
176
177
void
178
lwnotice(const char *fmt, ...)
179
3.63k
{
180
3.63k
  va_list ap;
181
182
3.63k
  va_start(ap, fmt);
183
184
  /* Call the supplied function */
185
3.63k
  (*lwnotice_var)(fmt, ap);
186
187
3.63k
  va_end(ap);
188
3.63k
}
189
190
void
191
lwerror(const char *fmt, ...)
192
159k
{
193
159k
  va_list ap;
194
195
159k
  va_start(ap, fmt);
196
197
  /* Call the supplied function */
198
159k
  (*lwerror_var)(fmt, ap);
199
200
159k
  va_end(ap);
201
159k
}
202
203
void
204
lwdebug(int level, const char *fmt, ...)
205
0
{
206
0
  va_list ap;
207
208
0
  va_start(ap, fmt);
209
210
  /* Call the supplied function */
211
0
  (*lwdebug_var)(level, fmt, ap);
212
213
0
  va_end(ap);
214
0
}
215
216
const char*
217
lwtype_name(uint8_t type)
218
480
{
219
480
  if ( type > 15 )
220
0
  {
221
    /* assert(0); */
222
0
    return "Invalid type";
223
0
  }
224
480
  return lwgeomTypeName[(int ) type];
225
480
}
226
227
void *
228
lwalloc(size_t size)
229
3.32M
{
230
3.32M
  void *mem = lwalloc_var(size);
231
3.32M
  return mem;
232
3.32M
}
233
234
void *
235
lwalloc0(size_t size)
236
0
{
237
0
  void *mem = lwalloc_var(size);
238
0
  memset(mem, 0, size);
239
0
  return mem;
240
0
}
241
242
void *
243
lwrealloc(void *mem, size_t size)
244
18.0k
{
245
18.0k
  return lwrealloc_var(mem, size);
246
18.0k
}
247
248
void
249
lwfree(void *mem)
250
3.32M
{
251
3.32M
  lwfree_var(mem);
252
3.32M
}
253
254
char *
255
lwstrdup(const char* a)
256
0
{
257
0
  size_t l = strlen(a)+1;
258
0
  char *b = lwalloc(l);
259
0
  strncpy(b, a, l);
260
0
  return b;
261
0
}
262
263
/*
264
 * Returns the characters to the left of the error position
265
 * to a maximum of maxlength.
266
 */
267
char *
268
lwmessage_truncate(const char *str, int errpos, int maxlength)
269
0
{
270
0
  int str_sz;
271
0
  int startpos;
272
273
0
  assert(str != NULL);
274
0
  assert(errpos >= 0);
275
0
  assert(maxlength > 0);
276
277
0
  str_sz = strlen(str);
278
279
0
  stringbuffer_t sb;
280
0
  stringbuffer_init(&sb);
281
282
  /* Error cannot be past end of WKT */
283
0
  if (errpos > str_sz)
284
0
    errpos = str_sz;
285
286
  /* Go back maxlength from errpos but not past zero */
287
0
  startpos = errpos - maxlength;
288
0
  if (startpos < 0)
289
0
    startpos = 0;
290
291
0
  if (str_sz < maxlength)
292
0
  {
293
0
    stringbuffer_append(&sb, str);
294
0
  }
295
0
  else
296
0
  {
297
    /* Add "..." prefix */
298
0
    stringbuffer_append(&sb, "...");
299
0
    stringbuffer_append_len(&sb, str + startpos, errpos-startpos);
300
0
  }
301
302
0
  return stringbuffer_getstringcopy(&sb);
303
0
}
304
305
306
int32_t
307
clamp_srid(int32_t srid)
308
1.49k
{
309
1.49k
  int newsrid = srid;
310
311
1.49k
  if ( newsrid <= 0 ) {
312
819
    if ( newsrid != SRID_UNKNOWN ) {
313
537
      newsrid = SRID_UNKNOWN;
314
537
      lwnotice("SRID value %d converted to the officially unknown SRID value %d", srid, newsrid);
315
537
    }
316
819
  } else if ( srid > SRID_MAXIMUM ) {
317
309
    newsrid = SRID_USER_MAXIMUM + 1 +
318
      /* -1 is to reduce likelihood of clashes */
319
      /* NOTE: must match implementation in postgis_restore.pl */
320
309
      ( srid % ( SRID_MAXIMUM - SRID_USER_MAXIMUM - 1 ) );
321
309
    lwnotice("SRID value %d > SRID_MAXIMUM converted to %d", srid, newsrid);
322
309
  }
323
324
1.49k
  return newsrid;
325
1.49k
}
326
327
328
329
330
/* Structure for the type array */
331
struct geomtype_struct
332
{
333
  char *typename;
334
  int type;
335
  int z;
336
  int m;
337
};
338
339
/* Type array. Note that the order of this array is important in
340
   that any typename in the list must *NOT* occur within an entry
341
   before it. Otherwise if we search for "POINT" at the top of the
342
   list we would also match MULTIPOINT, for example. */
343
344
struct geomtype_struct geomtype_struct_array[] =
345
{
346
  { "GEOMETRYCOLLECTIONZM", COLLECTIONTYPE, 1, 1 },
347
  { "GEOMETRYCOLLECTIONZ", COLLECTIONTYPE, 1, 0 },
348
  { "GEOMETRYCOLLECTIONM", COLLECTIONTYPE, 0, 1 },
349
  { "GEOMETRYCOLLECTION", COLLECTIONTYPE, 0, 0 },
350
351
  { "GEOMETRYZM", 0, 1, 1 },
352
  { "GEOMETRYZ", 0, 1, 0 },
353
  { "GEOMETRYM", 0, 0, 1 },
354
  { "GEOMETRY", 0, 0, 0 },
355
356
  { "POLYHEDRALSURFACEZM", POLYHEDRALSURFACETYPE, 1, 1 },
357
  { "POLYHEDRALSURFACEZ", POLYHEDRALSURFACETYPE, 1, 0 },
358
  { "POLYHEDRALSURFACEM", POLYHEDRALSURFACETYPE, 0, 1 },
359
  { "POLYHEDRALSURFACE", POLYHEDRALSURFACETYPE, 0, 0 },
360
361
  { "TINZM", TINTYPE, 1, 1 },
362
  { "TINZ", TINTYPE, 1, 0 },
363
  { "TINM", TINTYPE, 0, 1 },
364
  { "TIN", TINTYPE, 0, 0 },
365
366
  { "CIRCULARSTRINGZM", CIRCSTRINGTYPE, 1, 1 },
367
  { "CIRCULARSTRINGZ", CIRCSTRINGTYPE, 1, 0 },
368
  { "CIRCULARSTRINGM", CIRCSTRINGTYPE, 0, 1 },
369
  { "CIRCULARSTRING", CIRCSTRINGTYPE, 0, 0 },
370
371
  { "COMPOUNDCURVEZM", COMPOUNDTYPE, 1, 1 },
372
  { "COMPOUNDCURVEZ", COMPOUNDTYPE, 1, 0 },
373
  { "COMPOUNDCURVEM", COMPOUNDTYPE, 0, 1 },
374
  { "COMPOUNDCURVE", COMPOUNDTYPE, 0, 0 },
375
376
  { "CURVEPOLYGONZM", CURVEPOLYTYPE, 1, 1 },
377
  { "CURVEPOLYGONZ", CURVEPOLYTYPE, 1, 0 },
378
  { "CURVEPOLYGONM", CURVEPOLYTYPE, 0, 1 },
379
  { "CURVEPOLYGON", CURVEPOLYTYPE, 0, 0 },
380
381
  { "MULTICURVEZM", MULTICURVETYPE, 1, 1 },
382
  { "MULTICURVEZ", MULTICURVETYPE, 1, 0 },
383
  { "MULTICURVEM", MULTICURVETYPE, 0, 1 },
384
  { "MULTICURVE", MULTICURVETYPE, 0, 0 },
385
386
  { "MULTISURFACEZM", MULTISURFACETYPE, 1, 1 },
387
  { "MULTISURFACEZ", MULTISURFACETYPE, 1, 0 },
388
  { "MULTISURFACEM", MULTISURFACETYPE, 0, 1 },
389
  { "MULTISURFACE", MULTISURFACETYPE, 0, 0 },
390
391
  { "MULTILINESTRINGZM", MULTILINETYPE, 1, 1 },
392
  { "MULTILINESTRINGZ", MULTILINETYPE, 1, 0 },
393
  { "MULTILINESTRINGM", MULTILINETYPE, 0, 1 },
394
  { "MULTILINESTRING", MULTILINETYPE, 0, 0 },
395
396
  { "MULTIPOLYGONZM", MULTIPOLYGONTYPE, 1, 1 },
397
  { "MULTIPOLYGONZ", MULTIPOLYGONTYPE, 1, 0 },
398
  { "MULTIPOLYGONM", MULTIPOLYGONTYPE, 0, 1 },
399
  { "MULTIPOLYGON", MULTIPOLYGONTYPE, 0, 0 },
400
401
  { "MULTIPOINTZM", MULTIPOINTTYPE, 1, 1 },
402
  { "MULTIPOINTZ", MULTIPOINTTYPE, 1, 0 },
403
  { "MULTIPOINTM", MULTIPOINTTYPE, 0, 1 },
404
  { "MULTIPOINT", MULTIPOINTTYPE, 0, 0 },
405
406
  { "LINESTRINGZM", LINETYPE, 1, 1 },
407
  { "LINESTRINGZ", LINETYPE, 1, 0 },
408
  { "LINESTRINGM", LINETYPE, 0, 1 },
409
  { "LINESTRING", LINETYPE, 0, 0 },
410
411
  { "TRIANGLEZM", TRIANGLETYPE, 1, 1 },
412
  { "TRIANGLEZ", TRIANGLETYPE, 1, 0 },
413
  { "TRIANGLEM", TRIANGLETYPE, 0, 1 },
414
  { "TRIANGLE", TRIANGLETYPE, 0, 0 },
415
416
  { "POLYGONZM", POLYGONTYPE, 1, 1 },
417
  { "POLYGONZ", POLYGONTYPE, 1, 0 },
418
  { "POLYGONM", POLYGONTYPE, 0, 1 },
419
  { "POLYGON", POLYGONTYPE, 0, 0 },
420
421
  { "POINTZM", POINTTYPE, 1, 1 },
422
  { "POINTZ", POINTTYPE, 1, 0 },
423
  { "POINTM", POINTTYPE, 0, 1 },
424
  { "POINT", POINTTYPE, 0, 0 }
425
426
};
427
0
#define GEOMTYPE_STRUCT_ARRAY_LEN (sizeof geomtype_struct_array/sizeof(struct geomtype_struct))
428
429
/*
430
* We use a very simple upper case mapper here, because the system toupper() function
431
* is locale dependent and may have trouble mapping lower case strings to the upper
432
* case ones we expect (see, the "Turkisk I", http://www.i18nguy.com/unicode/turkish-i18n.html)
433
* We could also count on PgSQL sending us *lower* case inputs, as it seems to do that
434
* regardless of the case the user provides for the type arguments.
435
*/
436
const char dumb_upper_map[128] = "................................................0123456789.......ABCDEFGHIJKLMNOPQRSTUVWXYZ......ABCDEFGHIJKLMNOPQRSTUVWXYZ.....";
437
438
static char dumb_toupper(int in)
439
0
{
440
0
  if ( in < 0 || in > 127 )
441
0
    return '.';
442
0
  return dumb_upper_map[in];
443
0
}
444
445
lwflags_t lwflags(int hasz, int hasm, int geodetic)
446
1.66M
{
447
1.66M
  lwflags_t flags = 0;
448
1.66M
  if (hasz)
449
516k
    FLAGS_SET_Z(flags, 1);
450
1.66M
  if (hasm)
451
26.7k
    FLAGS_SET_M(flags, 1);
452
1.66M
  if (geodetic)
453
0
    FLAGS_SET_GEODETIC(flags, 1);
454
1.66M
  return flags;
455
1.66M
}
456
457
/**
458
* Calculate type integer and dimensional flags from string input.
459
* Case insensitive, and insensitive to spaces at front and back.
460
* Type == 0 in the case of the string "GEOMETRY" or "GEOGRAPHY".
461
* Return LW_SUCCESS for success.
462
*/
463
int geometry_type_from_string(const char *str, uint8_t *type, int *z, int *m)
464
0
{
465
0
  char *tmpstr;
466
0
  size_t tmpstartpos, tmpendpos;
467
0
  size_t i;
468
469
0
  assert(str);
470
0
  assert(type);
471
0
  assert(z);
472
0
  assert(m);
473
474
  /* Initialize. */
475
0
  *type = 0;
476
0
  *z = 0;
477
0
  *m = 0;
478
479
  /* Locate any leading/trailing spaces */
480
0
  tmpstartpos = 0;
481
0
  for (i = 0; i < strlen(str); i++)
482
0
  {
483
0
    if (str[i] != ' ')
484
0
    {
485
0
      tmpstartpos = i;
486
0
      break;
487
0
    }
488
0
  }
489
490
0
  tmpendpos = strlen(str) - 1;
491
0
  for (i = strlen(str) - 1; i != 0; i--)
492
0
  {
493
0
    if (str[i] != ' ')
494
0
    {
495
0
      tmpendpos = i;
496
0
      break;
497
0
    }
498
0
  }
499
500
  /* Copy and convert to upper case for comparison */
501
0
  tmpstr = lwalloc(tmpendpos - tmpstartpos + 2);
502
0
  for (i = tmpstartpos; i <= tmpendpos; i++)
503
0
    tmpstr[i - tmpstartpos] = dumb_toupper(str[i]);
504
505
  /* Add NULL to terminate */
506
0
  tmpstr[i - tmpstartpos] = '\0';
507
508
  /* Now check for the type */
509
0
  for (i = 0; i < GEOMTYPE_STRUCT_ARRAY_LEN; i++)
510
0
  {
511
0
    if (!strcmp(tmpstr, geomtype_struct_array[i].typename))
512
0
    {
513
0
      *type = geomtype_struct_array[i].type;
514
0
      *z = geomtype_struct_array[i].z;
515
0
      *m = geomtype_struct_array[i].m;
516
517
0
      lwfree(tmpstr);
518
519
0
      return LW_SUCCESS;
520
0
    }
521
522
0
  }
523
524
0
  lwfree(tmpstr);
525
526
0
  return LW_FAILURE;
527
0
}
528
529
530
531
532
533