Compare commits

...

3 Commits

Author SHA1 Message Date
Petteri Aimonen
17c10119dd Remove the PB_ENCODERS array. 2013-11-14 19:36:53 +02:00
Petteri Aimonen
97210c91a9 Remove the PB_DECODERS array.
Reduces code size by 2% and is overall cleaner.
2013-11-14 19:26:47 +02:00
Petteri Aimonen
cace53dfbd Change the API for pb_make_string_substream() to use less stack.
If your own application uses this function, you have to change
the old style:

    pb_istream_t substream;
    if (!pb_make_string_substream(stream, &substream))
        return false;
    .. do stuff with substream ..
    pb_close_string_substream(stream, &substream);

to the new style:

    size_t remaining;
    if (!pb_make_string_substream(stream, &remaining))
        return false;
    .. do stuff with stream ..
    pb_close_string_substream(stream, remaining);
2013-11-14 19:16:49 +02:00
3 changed files with 82 additions and 86 deletions

View File

@@ -32,7 +32,6 @@ typedef struct {
void *pSize; /* Pointer where to store the size of current array field */
} pb_field_iterator_t;
typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn;
static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count);
static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest);
@@ -40,6 +39,7 @@ static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire
static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct);
static bool pb_field_next(pb_field_iterator_t *iter);
static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag);
static bool checkreturn decode_ltype(pb_istream_t *stream, const pb_field_t *field, void *dest, pb_type_t type);
static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter);
static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter);
static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter);
@@ -57,21 +57,6 @@ static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t
static bool checkreturn pb_skip_varint(pb_istream_t *stream);
static bool checkreturn pb_skip_string(pb_istream_t *stream);
/* --- Function pointers to field decoders ---
* Order in the array must match pb_action_t LTYPE numbering.
*/
static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
&pb_dec_varint,
&pb_dec_svarint,
&pb_dec_fixed32,
&pb_dec_fixed64,
&pb_dec_bytes,
&pb_dec_string,
&pb_dec_submessage,
NULL /* extensions */
};
/*******************************
* pb_istream_t implementation *
*******************************/
@@ -313,28 +298,23 @@ static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire
/* Decode string length from stream and return a substream with limited length.
* Remember to close the substream using pb_close_string_substream().
*/
bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream)
bool checkreturn pb_make_string_substream(pb_istream_t *stream, size_t *remaining_length)
{
uint32_t size;
if (!pb_decode_varint32(stream, &size))
return false;
*substream = *stream;
if (substream->bytes_left < size)
if (stream->bytes_left < size)
PB_RETURN_ERROR(stream, "parent stream too short");
substream->bytes_left = size;
stream->bytes_left -= size;
*remaining_length = stream->bytes_left - size;
stream->bytes_left = size;
return true;
}
void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream)
void pb_close_string_substream(pb_istream_t *stream, size_t remaining_length)
{
stream->state = substream->state;
#ifndef PB_NO_ERRMSG
stream->errmsg = substream->errmsg;
#endif
stream->bytes_left += remaining_length;
}
static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct)
@@ -401,22 +381,37 @@ static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag)
* Decode a single field *
*************************/
/* Invoke a decoder function based on the ltype of a field. */
static bool checkreturn decode_ltype(pb_istream_t *stream,
const pb_field_t *field, void *dest, pb_type_t type)
{
switch (PB_LTYPE(type))
{
case PB_LTYPE_VARINT: return pb_dec_varint(stream, field, dest);
case PB_LTYPE_SVARINT: return pb_dec_svarint(stream, field, dest);
case PB_LTYPE_FIXED32: return pb_dec_fixed32(stream, field, dest);
case PB_LTYPE_FIXED64: return pb_dec_fixed64(stream, field, dest);
case PB_LTYPE_BYTES: return pb_dec_bytes(stream, field, dest);
case PB_LTYPE_STRING: return pb_dec_string(stream, field, dest);
case PB_LTYPE_SUBMESSAGE: return pb_dec_submessage(stream, field, dest);
default: PB_RETURN_ERROR(stream, "invalid field type");
}
}
static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter)
{
pb_type_t type;
pb_decoder_t func;
type = iter->pos->type;
func = PB_DECODERS[PB_LTYPE(type)];
switch (PB_HTYPE(type))
{
case PB_HTYPE_REQUIRED:
return func(stream, iter->pos, iter->pData);
return decode_ltype(stream, iter->pos, iter->pData, type);
case PB_HTYPE_OPTIONAL:
*(bool*)iter->pSize = true;
return func(stream, iter->pos, iter->pData);
return decode_ltype(stream, iter->pos, iter->pData, type);
case PB_HTYPE_REPEATED:
if (wire_type == PB_WT_STRING
@@ -425,24 +420,25 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
/* Packed array */
bool status = true;
size_t *size = (size_t*)iter->pSize;
pb_istream_t substream;
if (!pb_make_string_substream(stream, &substream))
size_t remaining_length;
if (!pb_make_string_substream(stream, &remaining_length))
return false;
while (substream.bytes_left && *size < iter->pos->array_size)
while (stream->bytes_left)
{
void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size);
if (!func(&substream, iter->pos, pItem))
if (*size >= iter->pos->array_size)
PB_RETURN_ERROR(stream, "array overflow");
if (!decode_ltype(stream, iter->pos, pItem, type))
{
status = false;
break;
}
(*size)++;
}
pb_close_string_substream(stream, &substream);
if (substream.bytes_left != 0)
PB_RETURN_ERROR(stream, "array overflow");
pb_close_string_substream(stream, remaining_length);
return status;
}
@@ -455,7 +451,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t
PB_RETURN_ERROR(stream, "array overflow");
(*size)++;
return func(stream, iter->pos, pItem);
return decode_ltype(stream, iter->pos, pItem, type);
}
default:
@@ -478,18 +474,18 @@ static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type
if (wire_type == PB_WT_STRING)
{
pb_istream_t substream;
size_t remaining_length;
if (!pb_make_string_substream(stream, &substream))
if (!pb_make_string_substream(stream, &remaining_length))
return false;
do
{
if (!pCallback->funcs.decode(&substream, iter->pos, arg))
if (!pCallback->funcs.decode(stream, iter->pos, arg))
PB_RETURN_ERROR(stream, "callback failed");
} while (substream.bytes_left);
} while (stream->bytes_left);
pb_close_string_substream(stream, &substream);
pb_close_string_substream(stream, remaining_length);
return true;
}
else
@@ -746,14 +742,14 @@ bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void
bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
{
pb_istream_t substream;
size_t remaining_length;
bool status;
if (!pb_make_string_substream(stream, &substream))
if (!pb_make_string_substream(stream, &remaining_length))
return false;
status = pb_decode(&substream, fields, dest_struct);
pb_close_string_substream(stream, &substream);
status = pb_decode(stream, fields, dest_struct);
pb_close_string_substream(stream, remaining_length);
return status;
}
@@ -896,10 +892,10 @@ bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, vo
bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest)
{
bool status;
pb_istream_t substream;
size_t remaining_length;
const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr;
if (!pb_make_string_substream(stream, &substream))
if (!pb_make_string_substream(stream, &remaining_length))
return false;
if (field->ptr == NULL)
@@ -908,10 +904,10 @@ bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field
/* New array entries need to be initialized, while required and optional
* submessages have already been initialized in the top-level pb_decode. */
if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
status = pb_decode(&substream, submsg_fields, dest);
status = pb_decode(stream, submsg_fields, dest);
else
status = pb_decode_noinit(&substream, submsg_fields, dest);
status = pb_decode_noinit(stream, submsg_fields, dest);
pb_close_string_substream(stream, &substream);
pb_close_string_substream(stream, remaining_length);
return status;
}

View File

@@ -128,8 +128,8 @@ bool pb_decode_fixed32(pb_istream_t *stream, void *dest);
bool pb_decode_fixed64(pb_istream_t *stream, void *dest);
/* Make a limited-length substream for reading a PB_WT_STRING field. */
bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream);
void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream);
bool pb_make_string_substream(pb_istream_t *stream, size_t *remaining_length);
void pb_close_string_substream(pb_istream_t *stream, size_t remaining_length);
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -20,10 +20,9 @@
/**************************************
* Declarations internal to this file *
**************************************/
typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn;
static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count);
static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func);
static bool checkreturn encode_ltype(pb_ostream_t *stream, const pb_field_t *field, const void *src, pb_type_t type);
static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count);
static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
@@ -35,21 +34,6 @@ static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *fie
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src);
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
/* --- Function pointers to field encoders ---
* Order in the array must match pb_action_t LTYPE numbering.
*/
static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
&pb_enc_varint,
&pb_enc_svarint,
&pb_enc_fixed32,
&pb_enc_fixed64,
&pb_enc_bytes,
&pb_enc_string,
&pb_enc_submessage,
NULL /* extensions */
};
/*******************************
* pb_ostream_t implementation *
*******************************/
@@ -106,9 +90,28 @@ bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count
* Encode a single field *
*************************/
/* Invoke an encoder function based on the ltype of a field. */
static bool checkreturn encode_ltype(pb_ostream_t *stream,
const pb_field_t *field, const void *src, pb_type_t type)
{
switch (PB_LTYPE(type))
{
case PB_LTYPE_VARINT: return pb_enc_varint(stream, field, src);
case PB_LTYPE_SVARINT: return pb_enc_svarint(stream, field, src);
case PB_LTYPE_FIXED32: return pb_enc_fixed32(stream, field, src);
case PB_LTYPE_FIXED64: return pb_enc_fixed64(stream, field, src);
case PB_LTYPE_BYTES: return pb_enc_bytes(stream, field, src);
case PB_LTYPE_STRING: return pb_enc_string(stream, field, src);
case PB_LTYPE_SUBMESSAGE: return pb_enc_submessage(stream, field, src);
default: PB_RETURN_ERROR(stream, "invalid field type");
}
}
/* Encode a static array. Handles the size calculations and possible packing. */
static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field,
const void *pData, size_t count, pb_encoder_t func)
const void *pData, size_t count)
{
size_t i;
const void *p;
@@ -141,7 +144,7 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie
p = pData;
for (i = 0; i < count; i++)
{
if (!func(&sizestream, field, p))
if (!encode_ltype(&sizestream, field, p, field->type))
return false;
p = (const char*)p + field->data_size;
}
@@ -158,7 +161,7 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie
p = pData;
for (i = 0; i < count; i++)
{
if (!func(stream, field, p))
if (!encode_ltype(stream, field, p, field->type))
return false;
p = (const char*)p + field->data_size;
}
@@ -170,7 +173,7 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie
{
if (!pb_encode_tag_for_field(stream, field))
return false;
if (!func(stream, field, p))
if (!encode_ltype(stream, field, p, field->type))
return false;
p = (const char*)p + field->data_size;
}
@@ -184,12 +187,9 @@ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *fie
static bool checkreturn encode_static_field(pb_ostream_t *stream,
const pb_field_t *field, const void *pData)
{
pb_encoder_t func;
const void *pSize;
bool dummy = true;
func = PB_ENCODERS[PB_LTYPE(field->type)];
if (field->size_offset)
pSize = (const char*)pData + field->size_offset;
else
@@ -200,7 +200,7 @@ static bool checkreturn encode_static_field(pb_ostream_t *stream,
case PB_HTYPE_REQUIRED:
if (!pb_encode_tag_for_field(stream, field))
return false;
if (!func(stream, field, pData))
if (!encode_ltype(stream, field, pData, field->type))
return false;
break;
@@ -210,13 +210,13 @@ static bool checkreturn encode_static_field(pb_ostream_t *stream,
if (!pb_encode_tag_for_field(stream, field))
return false;
if (!func(stream, field, pData))
if (!encode_ltype(stream, field, pData, field->type))
return false;
}
break;
case PB_HTYPE_REPEATED:
if (!encode_array(stream, field, pData, *(const size_t*)pSize, func))
if (!encode_array(stream, field, pData, *(const size_t*)pSize))
return false;
break;