Skip to content

Commit

Permalink
Fixed issue #9 when reads from unsigned 64bit varInt for TWKB inputs.
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel García Aubert committed Nov 6, 2015
1 parent 9d40bb2 commit 74536e8
Showing 1 changed file with 81 additions and 85 deletions.
166 changes: 81 additions & 85 deletions plugins/input/postgis/postgis_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ struct twkb_reader : mapnik::noncopyable
unsigned int pos_;

/* Metadata on the geometry we are parsing */
uint32_t twkb_type_;
uint32_t twkb_type_;
uint8_t has_bbox_;
uint8_t has_size_;
uint8_t has_idlist_;
Expand All @@ -74,10 +74,10 @@ struct twkb_reader : mapnik::noncopyable
double factor_m_;

/* An array to keep delta values from 4 dimensions */
int64_t coord_x_;
int64_t coord_y_;
int64_t coord_z_;
int64_t coord_m_;
int64_t coord_x_;
int64_t coord_y_;
int64_t coord_z_;
int64_t coord_m_;


public:
Expand All @@ -91,51 +91,51 @@ struct twkb_reader : mapnik::noncopyable
twkbMultiPolygon=6,
twkbGeometryCollection=7
};


twkb_reader(const char* twkb, size_t size)
: twkb_(twkb),
size_(size),
pos_(0),
twkb_type_(0), // Geometry type
has_bbox_(0), // Bounding box?
has_size_(0), // Size attribute?
has_idlist_(0), // Presence of X/Y
has_z_(0), // Presence of Z
has_m_(0), // Presence of M
is_empty_(0), // Empty?
factor_xy_(0.0), // Expansion factor for X/Y
factor_z_(0.0), // Expansion factor for Z
factor_m_(0.0) // Expansion factor for M
twkb_type_(0), // Geometry type
has_bbox_(0), // Bounding box?
has_size_(0), // Size attribute?
has_idlist_(0), // Presence of X/Y
has_z_(0), // Presence of Z
has_m_(0), // Presence of M
is_empty_(0), // Empty?
factor_xy_(0.0), // Expansion factor for X/Y
factor_z_(0.0), // Expansion factor for Z
factor_m_(0.0) // Expansion factor for M
{

}
}

void read(boost::ptr_vector<geometry_type> & paths)
{
// Read the metadata bytes, populating all the
// Read the metadata bytes, populating all the
// information about optional fields, extended (z/m) dimensions
// expansion factors and so on
read_header();

// Each new read call has to reset the coordinate accumulators
coord_x_ = 0; // Accumulation register (x)
coord_y_ = 0; // Accumulation register (y)
coord_z_ = 0; // Accumulation register (z)
coord_m_ = 0; // Accumulation register (m)
coord_m_ = 0; // Accumulation register (m)

// If the geometry is empty, add nothing to the paths array
if ( is_empty_ )
return;

// Read the [optional] size information
if ( has_size_ )
size_ = read_unsigned_integer();

// Read the [optional] bounding box information
if ( has_bbox_ )
read_bbox();

switch (twkb_type_)
{
case twkbPoint:
Expand All @@ -162,85 +162,81 @@ struct twkb_reader : mapnik::noncopyable
return;
}
}

private:

int64_t unzigzag64(uint64_t val)
{
if ( val & 0x01 )
if ( val & 0x01 )
return -1 * (int64_t)((val+1) >> 1);
else
return (int64_t)(val >> 1);
}

int32_t unzigzag32(uint32_t val)
{
if ( val & 0x01 )
if ( val & 0x01 )
return -1 * (int32_t)((val+1) >> 1);
else
return (int32_t)(val >> 1);
}

int8_t unzigzag8(uint8_t val)
{
if ( val & 0x01 )
if ( val & 0x01 )
return -1 * (int8_t)((val+1) >> 1);
else
return (int8_t)(val >> 1);
}

/* Read from signed 64bit varint */
int64_t read_signed_integer()
{
{
return unzigzag64(read_unsigned_integer());
}

/* Read from unsigned 64bit varint */
uint64_t read_unsigned_integer()
{
uint64_t nVal = 0;
int nShift = 0;
uint8_t nByte;
uint64_t nVal = 0;
int nShift = 0;
uint8_t nByte;

/* Check so we don't read beyond the twkb */
while ( pos_ < size_ )
{
nByte = twkb_[pos_];

/* We get here when there is more to read in the input varInt */
/* Here we take the least significant 7 bits of the read */
/* byte and put it in the most significant place in the result variable. */
nVal |= ((uint64_t)(nByte & 0x7f)) << nShift;

/* move the "cursor" of the input buffer step (8 bits) */
pos_++;

/* move the cursor in the resulting variable (7 bits) */
nShift += 7;

/* Hibit isn't set, so this is the last byte */
if ( !(nByte & 0x80) )
{
return nVal;
}
}

/* Check so we don't read beyond the twkb */
while( pos_ < size_ )
{
nByte = twkb_[pos_];
/* Hibit is set, so this isn't the last byte */
if (nByte & 0x80)
{
/* We get here when there is more to read in the input varInt */
/* Here we take the least significant 7 bits of the read */
/* byte and put it in the most significant place in the result variable. */
nVal |= ((uint64_t)(nByte & 0x7f)) << nShift;
/* move the "cursor" of the input buffer step (8 bits) */
pos_++;
/* move the cursor in the resulting variable (7 bits) */
nShift += 7;
}
else
{
/* move the "cursor" one step */
pos_++;
/* Move the last read byte to the most significant */
/* place in the result and return the whole result */
//*size = ptr - the_start;
return nVal | (uint64_t)(nByte << nShift);
}
}

// lwerror("%s: varint extends past end of buffer", __func__);
return 0;
return 0;
}

// Every TWKB geometry starts with a metadata header
//
//
// type_and_dims byte
// metadata_header byte
// [extended_dims] byte
// [size] uvarint
// [bounds] bbox
//
//
void read_header()
{
uint8_t type_precision = twkb_[pos_++];
Expand All @@ -253,8 +249,8 @@ struct twkb_reader : mapnik::noncopyable
has_idlist_ = (metadata & 0x04) >> 2;
uint8_t zm = (metadata & 0x08) >> 3;
is_empty_ = (metadata & 0x10) >> 4;
// Flag for higher dimensions means read a third byte

// Flag for higher dimensions means read a third byte
// of extended dimension information
if ( zm )
{
Expand All @@ -270,7 +266,7 @@ struct twkb_reader : mapnik::noncopyable
factor_z_ = pow(10, (double)precision_z);
factor_m_ = pow(10, (double)precision_m);
}

}

void read_bbox()
Expand All @@ -296,8 +292,8 @@ struct twkb_reader : mapnik::noncopyable
}
}
}
void read_idlist(unsigned int num_ids)

void read_idlist(unsigned int num_ids)
{
// we have nowhere to store this id information
// for now, so we'll just move the read head
Expand All @@ -310,7 +306,7 @@ struct twkb_reader : mapnik::noncopyable
}
}
}

void read_coords(CoordinateArray& ar)
{
for ( unsigned int i = 0; i < ar.size(); i++ )
Expand All @@ -323,15 +319,15 @@ struct twkb_reader : mapnik::noncopyable
coord_y_ += read_signed_integer();
ar[i].y = coord_y_ / factor_xy_;

// No Mapnik slot to hold Z, so just move read head forward
// No Mapnik slot to hold Z, so just move read head forward
if ( has_z_ )
coord_z_ += read_signed_integer();

// No Mapnik slot to hold M, so just move read head forward
// No Mapnik slot to hold M, so just move read head forward
if ( has_m_ )
coord_m_ += read_signed_integer();
}

}

void read_point(boost::ptr_vector<geometry_type> & paths)
Expand All @@ -346,10 +342,10 @@ struct twkb_reader : mapnik::noncopyable
void read_multipoint(boost::ptr_vector<geometry_type> & paths)
{
unsigned int num_points = read_unsigned_integer();

if ( has_idlist_ )
read_idlist(num_points);

if (num_points > 0)
{
CoordinateArray ar(num_points);
Expand Down Expand Up @@ -379,14 +375,14 @@ struct twkb_reader : mapnik::noncopyable
paths.push_back(line);
}
}

void read_multilinestring(boost::ptr_vector<geometry_type> & paths)
{
unsigned int num_lines = read_unsigned_integer();

if ( has_idlist_ )
read_idlist(num_lines);

for ( unsigned int i = 0; i < num_lines; ++i )
{
read_linestring(paths);
Expand Down Expand Up @@ -425,7 +421,7 @@ struct twkb_reader : mapnik::noncopyable

if ( has_idlist_ )
read_idlist(num_polys);

for ( unsigned int i = 0; i < num_polys; ++i )
{
read_polygon(paths);
Expand All @@ -435,10 +431,10 @@ struct twkb_reader : mapnik::noncopyable
void read_collection(boost::ptr_vector<geometry_type> & paths)
{
unsigned int num_geometries = read_unsigned_integer();

if ( has_idlist_ )
read_idlist(num_geometries);

for ( unsigned int i = 0; i < num_geometries; ++i )
{
read(paths);
Expand Down

0 comments on commit 74536e8

Please sign in to comment.