Coverage Report

Created: 2026-08-13 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgis/liblwgeom/lwin_encoded_polyline.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 2014 Kashif Rasul <kashif.rasul@gmail.com> and
22
 *
23
 **********************************************************************/
24
25
26
#include <assert.h>
27
#include <string.h>
28
#include <math.h>
29
#include <stdint.h>
30
31
#include "liblwgeom.h"
32
#include "lwgeom_log.h"
33
#include "../postgis_config.h"
34
35
static int
36
encoded_polyline_read_varint(const char *encodedpolyline, int length, int *idx, uint32_t *value)
37
37.0k
{
38
37.0k
  uint32_t res = 0;
39
37.0k
  unsigned int shift = 0;
40
41
38.1k
  while (1)
42
38.1k
  {
43
38.1k
    int byte;
44
38.1k
    if (*idx >= length)
45
60
    {
46
60
      lwerror("lwgeom_from_encoded_polyline: input is truncated");
47
60
      return LW_FALSE;
48
60
    }
49
50
38.1k
    byte = (unsigned char)encodedpolyline[(*idx)++] - 63;
51
38.1k
    if (byte < 0)
52
16
    {
53
16
      lwerror("lwgeom_from_encoded_polyline: input contains an invalid byte");
54
16
      return LW_FALSE;
55
16
    }
56
38.0k
    if (shift > 30 || (shift == 30 && ((byte & 0x1C) || (byte >= 0x20))))
57
23
    {
58
23
      lwerror("lwgeom_from_encoded_polyline: coordinate value is too large");
59
23
      return LW_FALSE;
60
23
    }
61
62
38.0k
    res |= (uint32_t)(byte & 0x1F) << shift;
63
38.0k
    if (byte < 0x20)
64
36.9k
      break;
65
66
1.12k
    shift += 5;
67
1.12k
  }
68
69
36.9k
  *value = res;
70
36.9k
  return LW_TRUE;
71
37.0k
}
72
73
static int32_t
74
encoded_polyline_zigzag_decode(uint32_t value)
75
36.9k
{
76
36.9k
  return (int32_t)((value >> 1) ^ (uint32_t)(-(int32_t)(value & 1)));
77
36.9k
}
78
79
static int
80
encoded_polyline_add_delta(int32_t *coordinate, int32_t delta)
81
36.9k
{
82
36.9k
  int64_t next = (int64_t)*coordinate + delta;
83
36.9k
  if (next < INT32_MIN || next > INT32_MAX)
84
15
  {
85
15
    lwerror("lwgeom_from_encoded_polyline: coordinate value is too large");
86
15
    return LW_FALSE;
87
15
  }
88
89
36.9k
  *coordinate = next;
90
36.9k
  return LW_TRUE;
91
36.9k
}
92
93
LWGEOM*
94
lwgeom_from_encoded_polyline(const char *encodedpolyline, int precision)
95
211
{
96
211
  LWGEOM *geom = NULL;
97
211
  POINTARRAY *pa = NULL;
98
211
  int length = strlen(encodedpolyline);
99
211
  int idx = 0;
100
211
  double scale = pow(10,precision);
101
102
211
  int32_t latitude = 0;
103
211
  int32_t longitude = 0;
104
105
211
  pa = ptarray_construct_empty(LW_FALSE, LW_FALSE, 1);
106
107
18.7k
  while (idx < length) {
108
18.5k
    POINT4D pt;
109
18.5k
    uint32_t res = 0;
110
111
18.5k
    if (!encoded_polyline_read_varint(encodedpolyline, length, &idx, &res))
112
0
    {
113
0
      ptarray_free(pa);
114
0
      return NULL;
115
0
    }
116
18.5k
    int32_t deltaLat = encoded_polyline_zigzag_decode(res);
117
18.5k
    if (!encoded_polyline_add_delta(&latitude, deltaLat))
118
0
    {
119
0
      ptarray_free(pa);
120
0
      return NULL;
121
0
    }
122
123
18.5k
    if (!encoded_polyline_read_varint(encodedpolyline, length, &idx, &res))
124
0
    {
125
0
      ptarray_free(pa);
126
0
      return NULL;
127
0
    }
128
18.5k
    int32_t deltaLon = encoded_polyline_zigzag_decode(res);
129
18.5k
    if (!encoded_polyline_add_delta(&longitude, deltaLon))
130
0
    {
131
0
      ptarray_free(pa);
132
0
      return NULL;
133
0
    }
134
135
18.5k
    pt.x = longitude/scale;
136
18.5k
    pt.y = latitude/scale;
137
18.5k
  pt.m = pt.z = 0.0;
138
18.5k
    ptarray_append_point(pa, &pt, LW_FALSE);
139
18.5k
  }
140
141
211
  geom = (LWGEOM *)lwline_construct(4326, NULL, pa);
142
211
  lwgeom_add_bbox(geom);
143
144
211
  return geom;
145
211
}