blob: d210a725010a9d4710feba73e480948a4870d230 [file] [log] [blame]
/*
* include/proto/protocol_buffers.h
* This file contains functions and macros declarations for protocol buffers decoding.
*
* Copyright 2012 Willy Tarreau <w@1wt.eu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _PROTO_PROTOCOL_BUFFERS_H
#define _PROTO_PROTOCOL_BUFFERS_H
#include <types/protocol_buffers.h>
#define PBUF_TYPE_VARINT 0
#define PBUF_TYPE_64BIT 1
#define PBUF_TYPE_LENGTH_DELIMITED 2
#define PBUF_TYPE_START_GROUP 3
#define PBUF_TYPE_STOP_GROUP 4
#define PBUF_TYPE_32BIT 5
#define PBUF_VARINT_DONT_STOP_BIT 7
#define PBUF_VARINT_DONT_STOP_BITMASK (1 << PBUF_VARINT_DONT_STOP_BIT)
#define PBUF_VARINT_DATA_BITMASK ~PBUF_VARINT_DONT_STOP_BITMASK
/*
* Decode a protocol buffers varint located in a buffer at <pos> address with
* <len> as length. The decoded value is stored at <val>.
* Returns 1 if succeeded, 0 if not.
*/
static inline int
protobuf_varint(uint64_t *val, unsigned char *pos, size_t len)
{
unsigned int shift;
*val = 0;
shift = 0;
while (len > 0) {
int stop = !(*pos & PBUF_VARINT_DONT_STOP_BITMASK);
*val |= ((uint64_t)(*pos & PBUF_VARINT_DATA_BITMASK)) << shift;
++pos;
--len;
if (stop)
break;
else if (!len)
return 0;
shift += 7;
/* The maximum length in bytes of a 64-bit encoded value is 10. */
if (shift > 70)
return 0;
}
return 1;
}
/*
* Decode a protocol buffers varint located in a buffer at <pos> offset address with
* <len> as length address. Update <pos> and <len> consequently. Decrease <*len>
* by the number of decoded bytes. The decoded value is stored at <val>.
* Returns 1 if succeeded, 0 if not.
*/
static inline int
protobuf_decode_varint(uint64_t *val, unsigned char **pos, size_t *len)
{
unsigned int shift;
*val = 0;
shift = 0;
while (*len > 0) {
int stop = !(**pos & PBUF_VARINT_DONT_STOP_BITMASK);
*val |= ((uint64_t)**pos & PBUF_VARINT_DATA_BITMASK) << shift;
++*pos;
--*len;
if (stop)
break;
else if (!*len)
return 0;
shift += 7;
/* The maximum length in bytes of a 64-bit encoded value is 10. */
if (shift > 70)
return 0;
}
return 1;
}
/*
* Skip a protocol buffer varint found at <pos> as position address with <len>
* as available length address. Update <*pos> to make it point to the next
* available byte. Decrease <*len> by the number of skipped bytes.
* Returns 1 if succeeded, 0 if not.
*/
static inline int
protobuf_skip_varint(unsigned char **pos, size_t *len)
{
unsigned int shift;
shift = 0;
while (*len > 0) {
int stop = !(**pos & PBUF_VARINT_DONT_STOP_BITMASK);
++*pos;
--*len;
if (stop)
break;
else if (!*len)
return 0;
shift += 7;
/* The maximum length in bytes of a 64-bit encoded value is 10. */
if (shift > 70)
return 0;
}
return 1;
}
/*
* If succeeded, return the length of a prococol buffers varint found at <pos> as
* position address, with <len> as address of the available bytes at <*pos>.
* Update <*pos> to make it point to the next available byte. Decrease <*len>
* by the number of bytes used to encode this varint.
* Return -1 if failed.
*/
static inline int
protobuf_varint_getlen(unsigned char **pos, size_t *len)
{
unsigned char *spos;
unsigned int shift;
shift = 0;
spos = *pos;
while (*len > 0) {
int stop = !(**pos & PBUF_VARINT_DONT_STOP_BITMASK);
++*pos;
--*len;
if (stop)
break;
else if (!*len)
return -1;
shift += 7;
/* The maximum length in bytes of a 64-bit encoded value is 10. */
if (shift > 70)
return -1;
}
return *pos - spos;
}
#endif /* _PROTO_PROTOCOL_BUFFERS_H */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*/