postgis/liblwgeom/varint.c

158 lines
4.3 KiB
C
Raw Normal View History

/**********************************************************************
*
* PostGIS - Spatial Types for PostgreSQL
* http://postgis.net
*
* Copyright (C) 2014 Sandro Santilli <strk@keybit.net>
* Copyright (C) 2013 Nicklas Avén
*
* This is free software; you can redistribute and/or modify it under
* the terms of the GNU General Public Licence. See the COPYING file.
*
**********************************************************************
*
* Handle varInt values, as described here:
* http://developers.google.com/protocol-buffers/docs/encoding#varints
*
**********************************************************************/
#include "varint.h"
#include "lwgeom_log.h"
#include "liblwgeom.h"
/**
* Constants to find the range of Varint.
* Since Varint only uses 7 bits instead of 8 in each byte a 8 byte varint
* only uses 56 bits for the number and 8 for telling if next byte is used
*/
const int64_t varint_u64_max = ((int64_t) 1<<56) - 1;
const int64_t varint_s64_min = (int64_t) -1<<55;
const int64_t varint_s64_max = ((int64_t)1<<55) - 1;
const int32_t varint_u32_max = ((int32_t) 1<<28) - 1;
const int32_t varint_s32_min = (int32_t) -1<<27;
const int32_t varint_s32_max = ((int32_t)1<<27) - 1;
static unsigned
_varint_u64_encoded_size(uint64_t q)
{
int n=0;
while ((q>>(7*(n+1))) >0) ++n;
return ++n;
}
static int
_varint_u64_encode_buf(uint64_t val, uint8_t **buf)
{
uint8_t grp;
uint64_t q=val;
while (1)
{
grp=127&q; //We put the 7 least significant bits in grp
q=q>>7; //We rightshift our input value 7 bits which means that the 7 next least significant bits becomes the 7 least significant
if(q>0) // Check if, after our rightshifting, we still have anything to read in our input value.
{
/*In the next line quite a lot is happening.
Since there is more to read in our input value we signalize that by setting the most siginicant bit in our byte to 1.
Then we put that byte in our buffer (**buf) and move the cursor to our buffer (*buf) one step*/
*((*buf)++)=128^grp;
}
else
{
/*The same as above, but since there is nothing more to read in our input value we leave the most significant bit unset*/
*((*buf)++)=grp;
// printf("grp1:%d\n",(int) grp);
return 0;
}
}
return 0;
}
unsigned
varint_u32_encoded_size(uint32_t val)
{
LWDEBUGF(2, "Entered varint_u32_encoded_size, value %u", val);
if( val>varint_u32_max ) {
lwerror("Value is out of range for unsigned 32bit varint (0 to %ld)",
varint_u32_max);
}
return _varint_u64_encoded_size(val); /* implicit upcast to 64bit int */
}
int
varint_u32_encode_buf(uint32_t val, uint8_t **buf)
{
LWDEBUGF(2, "Entered varint_u32_encode_buf, value %u", val);
_varint_u64_encode_buf(val, buf); /* implicit upcast to 64bit */
return 0;
}
unsigned
varint_s32_encoded_size(int32_t val)
{
LWDEBUGF(2, "Entered varint_s32_encoded_size, value %d", val);
if(val<varint_s32_min||val>varint_s32_max) {
lwerror("Value is out of range for signed 32bit varint (%d to %d)",
varint_s32_min, varint_s32_max);
}
uint32_t q = (val << 1) ^ (val >> 31); /* zig-zag encode */
return _varint_u64_encoded_size(q); /* implicit upcast to 64bit int */
}
int
varint_s32_encode_buf(int32_t val, uint8_t **buf)
{
uint32_t q;
q = (val << 1) ^ (val >> 31);/* zig-zag encode */
_varint_u64_encode_buf(q, buf);/* implicit upcast to 64bit */
return 0;
}
unsigned
varint_s64_encoded_size(int64_t val)
{
LWDEBUGF(2, "Entered varint_s64_encoded_size, value %ld", val);
if(val<varint_s64_min||val>varint_s64_max) {
lwerror("Value is out of range for signed 64bit varint (%ld to %ld)",
varint_s64_min, varint_s64_max);
}
uint64_t q = (val << 1) ^ (val >> 63); /* zig-zag encode */
return _varint_u64_encoded_size(q);
}
int
varint_s64_encode_buf(int64_t val, uint8_t **buf)
{
uint64_t q;
q = (val << 1) ^ (val >> 63);
varint_u64_encode_buf(q, buf);
return 0;
}
unsigned
varint_u64_encoded_size(uint64_t val)
{
LWDEBUGF(2, "Entered varint_u64_encoded_size, value %lu", val);
if( val>varint_u64_max ) {
lwerror("Value is out of range for unsigned 64bit varint (0 to %ld)",
varint_u64_max);
}
return _varint_u64_encoded_size(val);
}
int
varint_u64_encode_buf(uint64_t val, uint8_t **buf)
{
LWDEBUGF(2, "Entered varint_u64_encode_buf, value %lu", val);
_varint_u64_encode_buf(val, buf);
return 0;
}