static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter)
{
    pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
    
#ifdef PB_OLD_CALLBACK_STYLE
    void *arg = pCallback->arg;
#else
    void **arg = &(pCallback->arg);
#endif
    
    if (pCallback->funcs.decode == NULL)
        return pb_skip_field(stream, wire_type);
    
    if (wire_type == PB_WT_STRING)
    {
        pb_istream_t substream;
        
        if (!pb_make_string_substream(stream, &substream))
            return false;
        
        do
        {
            if (!pCallback->funcs.decode(&substream, iter->pos, arg))
                PB_RETURN_ERROR(stream, "callback failed");
        } while (substream.bytes_left);
        
        pb_close_string_substream(stream, &substream);
        return true;
    }
    else
    {
        /* Copy the single scalar value to stack.
         * This is required so that we can limit the stream length,
         * which in turn allows to use same callback for packed and
         * not-packed fields. */
        pb_istream_t substream;
        uint8_t buffer[10];
        size_t size = sizeof(buffer);
        
        if (!read_raw_value(stream, wire_type, buffer, &size))
            return false;
        substream = pb_istream_from_buffer(buffer, size);
        
        return pCallback->funcs.decode(&substream, iter->pos, arg);
    }
}
Example #2
0
static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter)
{
    pb_decoder_t func = PB_DECODERS[PB_LTYPE(iter->current->type)];

    switch (PB_HTYPE(iter->current->type))
    {
    case PB_HTYPE_REQUIRED:
        return func(stream, iter->current, iter->pData);

    case PB_HTYPE_OPTIONAL:
        *(bool*)iter->pSize = true;
        return func(stream, iter->current, iter->pData);

    case PB_HTYPE_ARRAY:
        if (wire_type == PB_WT_STRING
                && PB_LTYPE(iter->current->type) <= PB_LTYPE_LAST_PACKABLE)
        {
            /* Packed array */
            bool status;
            size_t *size = (size_t*)iter->pSize;
            pb_istream_t substream;
            if (!pb_make_string_substream(stream, &substream))
                return false;

            while (substream.bytes_left && *size < iter->current->array_size)
            {
                void *pItem = (uint8_t*)iter->pData + iter->current->data_size * (*size);
                if (!func(&substream, iter->current, pItem))
                    return false;
                (*size)++;
            }
            status = (substream.bytes_left == 0);
            pb_close_string_substream(stream, &substream);
            return status;
        }
        else
        {
            /* Repeated field */
            size_t *size = (size_t*)iter->pSize;
            void *pItem = (uint8_t*)iter->pData + iter->current->data_size * (*size);
            if (*size >= iter->current->array_size)
                PB_RETURN_ERROR(stream, "array overflow");

            (*size)++;
            return func(stream, iter->current, pItem);
        }

    case PB_HTYPE_CALLBACK:
    {
        pb_callback_t *pCallback = (pb_callback_t*)iter->pData;

        if (pCallback->funcs.decode == NULL)
            return pb_skip_field(stream, wire_type);

        if (wire_type == PB_WT_STRING)
        {
            pb_istream_t substream;

            if (!pb_make_string_substream(stream, &substream))
                return false;

            while (substream.bytes_left)
            {
                if (!pCallback->funcs.decode(&substream, iter->current, pCallback->arg))
                    PB_RETURN_ERROR(stream, "callback failed");
            }

            pb_close_string_substream(stream, &substream);
            return true;
        }
        else
        {
            /* Copy the single scalar value to stack.
             * This is required so that we can limit the stream length,
             * which in turn allows to use same callback for packed and
             * not-packed fields. */
            pb_istream_t substream;
            uint8_t buffer[10];
            size_t size = sizeof(buffer);

            if (!read_raw_value(stream, wire_type, buffer, &size))
                return false;
            substream = pb_istream_from_buffer(buffer, size);

            return pCallback->funcs.decode(&substream, iter->current, pCallback->arg);
        }
    }

    default:
        PB_RETURN_ERROR(stream, "invalid field type");
    }
}