qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 2/3] asn1 ber visitors


From: mdroth
Subject: Re: [Qemu-devel] [PATCH 2/3] asn1 ber visitors
Date: Wed, 27 Feb 2013 16:57:48 -0600
User-agent: Mutt/1.5.21 (2010-09-15)

On Tue, Feb 26, 2013 at 05:03:56PM -0600, address@hidden wrote:
> These patches implement asn1 ber visitors for encoding and decoding data.
> References: <address@hidden>
> Content-Disposition: inline; filename=asn1_all.diff
> 
> Signed-off-by: Stefan Berger <address@hidden>
> Signed-off-by: Joel Schopp <address@hidden>
> ---
>  Makefile.objs               |   10 
>  ber/Makefile.objs           |    2 
>  ber/ber-common.c            |   56 ++
>  ber/ber-input-visitor.c     |  969 
> ++++++++++++++++++++++++++++++++++++++++++++
>  ber/ber-input-visitor.h     |   30 +
>  ber/ber-output-visitor.c    |  563 +++++++++++++++++++++++++
>  ber/ber-output-visitor.h    |   28 +

Please break the input/output implementations out into separate patches,
and follow those up with test cases. See:

tests/test-{string,qmp}-{input,output}-visitor.c
tests/test-visitor-serialization.c

>  ber/ber.h                   |   85 +++
>  include/qapi/qmp/qerror.h   |    6 
>  include/qapi/visitor-impl.h |   23 +
>  include/qapi/visitor.h      |   10 
>  qapi/qapi-visit-core.c      |   30 +
>  12 files changed, 1811 insertions(+), 1 deletion(-)
> 
> Index: b/Makefile.objs
> ===================================================================
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -57,7 +57,12 @@ common-obj-$(CONFIG_POSIX) += os-posix.o
>  common-obj-$(CONFIG_LINUX) += fsdev/
> 
>  common-obj-y += migration.o migration-tcp.o
> -common-obj-y += qemu-char.o qemu-file.o #aio.o
> +
> +#ber has to be linked against qemu-file.o so we must add them on the same 
> line
> +ber-nested-y = ber-input-visitor.o ber-output-visitor.o ber-common.o
> +ber-obj-y = $(addprefix ber/, $(ber-nested-y))
> +
> +common-obj-y += qemu-char.o qemu-file.o $(ber-obj-y) #aio.o
>  common-obj-y += block-migration.o
>  common-obj-y += page_cache.o xbzrle.o
> 
> @@ -116,4 +121,7 @@ nested-vars += \
>       qga-obj-y \
>       block-obj-y \
>       common-obj-y
> +# \
> +#    ber-obj-y
> +
>  dummy := $(call unnest-vars)
> Index: b/ber/ber-common.c
> ===================================================================
> --- /dev/null
> +++ b/ber/ber-common.c
> @@ -0,0 +1,56 @@
> +/*
> + * ASN.1 Basic Encoding Rules Common functions
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + *  Stefan Berger     <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or 
> later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#include <stdint.h>
> +
> +#include "ber.h"
> +
> +static const char *ber_type_names[] = {
> +    "BER_TYPE_EOC",
> +    "BER_TYPE_BOOLEAN",
> +    "BER_TYPE_INTEGER",
> +    "BER_TYPE_BIT_STRING",
> +    "BER_TYPE_OCTET_STRING",
> +    "BER_TYPE_NULL",
> +    "BER_TYPE_OBJECT_ID",
> +    "BER_TYPE_OBJECT_DESC",
> +    "BER_TYPE_EXTERNAL",
> +    "BER_TYPE_REAL",
> +    "BER_TYPE_ENUMERATED",
> +    "BER_TYPE_EMBEDDED",
> +    "BER_TYPE_UTF8_STRING",
> +    "BER_TYPE_RELATIVE_OID",
> +    "BER_TYPE_UNUSED_0xE",
> +    "BER_TYPE_UNUSED_0xF",
> +    "BER_TYPE_SEQUENCE",
> +    "BER_TYPE_SET",
> +    "BER_TYPE_NUMERIC_STRING",
> +    "BER_TYPE_PRINTABLE_STRING",
> +    "BER_TYPE_T61STRING",
> +    "BER_TYPE_VIDEOTEX_STRING",
> +    "BER_TYPE_IA5_STRING",
> +    "BER_TYPE_UTCTIME",
> +    "BER_TYPE_GENERALIZED_TIME",
> +    "BER_TYPE_GRAPHIC_STRING",
> +    "BER_TYPE_VISIBLE_STRING",
> +    "BER_TYPE_GENERAL_STRING",
> +    "BER_TYPE_UNIVERSAL_STRING",
> +    "BER_TYPE_CHARACTER_STRING"
> +    "BER_TYPE_BMP_STRING",
> +    "BER_TYPE_LONG_FORM",
> +};
> +
> +const char *ber_type_to_str(uint8_t ber_type)
> +{
> +    return ber_type_names[ber_type & BER_TYPE_TAG_MASK];
> +}
> Index: b/ber/ber-input-visitor.c
> ===================================================================
> --- /dev/null
> +++ b/ber/ber-input-visitor.c
> @@ -0,0 +1,969 @@
> +/*
> + * BER Input Visitor
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + *  Anthony Liguori   <address@hidden>
> + *  Stefan Berger     <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or 
> later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#include "qemu-common.h"
> +#include "ber-input-visitor.h"
> +#include "qemu/queue.h"
> +#include "qemu-common.h"
> +#include "hw/hw.h"
> +#include "ber.h"
> +#include "include/qapi/qmp/qerror.h"
> +#include "migration/qemu-file.h"
> +#include "qapi/visitor-impl.h"
> +
> +#define AIV_STACK_SIZE 1024
> +
> +/* whether to allow the parsing of primitives that are fragmented */
> +#define BER_ALLOW_FRAGMENTED_PRIMITIVES
> +
> +/* #define BER_DEBUG */
> +
> +typedef struct StackEntry {
> +    uint64_t cur_pos;
> +} StackEntry;
> +
> +struct BERInputVisitor {
> +    Visitor visitor;
> +    QEMUFile *qfile;
> +    uint64_t cur_pos;
> +    StackEntry stack[AIV_STACK_SIZE];
> +    int nb_stack;
> +    uint64_t max_allowed_buffer_size;
> +    uint64_t largest_needed_buffer;
> +};
> +
> +static BERInputVisitor *to_biv(Visitor *v)
> +{
> +    return container_of(v, BERInputVisitor, visitor);
> +}
> +
> +static void ber_input_push(BERInputVisitor *aiv,
> +                           uint64_t cur_pos, Error **errp)
> +{
> +    aiv->stack[aiv->nb_stack].cur_pos = cur_pos;
> +    aiv->nb_stack++;
> +
> +    if (aiv->nb_stack >= AIV_STACK_SIZE) {
> +        error_set(errp, QERR_BUFFER_OVERRUN);
> +        return;
> +    }
> +}
> +
> +static uint64_t ber_input_pop(BERInputVisitor *aiv, Error **errp)
> +{
> +    aiv->nb_stack--;
> +
> +    if (aiv->nb_stack < 0) {
> +        error_set(errp, QERR_BUFFER_OVERRUN);
> +        return 0;
> +    }
> +
> +    return aiv->stack[aiv->nb_stack].cur_pos;
> +}
> +
> +/*
> + * Read a type tag from the stream. Up-to 32 bit type tags are supported
> + * for reading and otherwise an error is returned. Anything larger than that
> + * would not be reasonable and could only be abused.
> + */
> +static uint32_t ber_read_type(BERInputVisitor *aiv, uint8_t *ber_type_flags,
> +                              Error **errp)
> +{
> +    uint32_t type;
> +    uint8_t byte;
> +    uint8_t ctr = 0;
> +    char buf[128];
> +
> +    if (qemu_read_bytes(aiv->qfile, &byte, 1) != 1) {
> +        error_set(errp, QERR_QEMUFILE_ERROR,
> +                  "Error while reading type");
> +        return 0;
> +    }
> +    aiv->cur_pos++;
> +    type = byte;
> +
> +    *ber_type_flags = type & (BER_TYPE_P_C_MASK | BER_TYPE_CLASS_MASK);
> +
> +    if ((type & BER_TYPE_TAG_MASK) == BER_TYPE_LONG_FORM) {
> +        type = 0;
> +        while (true) {
> +            type <<= 7;
> +            if (qemu_read_bytes(aiv->qfile, &byte, 1) != 1) {
> +                error_set(errp, QERR_QEMUFILE_ERROR,
> +                          "Error while reading long type");
> +                return 0;
> +            }
> +            aiv->cur_pos++;
> +
> +            type |= (byte & 0x7f);
> +            if ((byte & 0x80) == 0) {
> +                break;
> +            }
> +            ctr += 7; /* read 7 bits */
> +            if (ctr >= (sizeof(type) * 8)) {
> +                /* only support 32 bit length identifiers */
> +                snprintf(buf, sizeof(buf),
> +                         "type tag is larger than 32 bit (offset %" PRIu64
> +                         ")", aiv->cur_pos);
> +                error_set(errp, QERR_INVALID_STREAM,
> +                          buf);
> +                return 0;
> +            }
> +        }
> +    } else {
> +        type &= BER_TYPE_TAG_MASK;
> +    }
> +
> +    return type;
> +}
> +
> +static uint64_t ber_read_length(BERInputVisitor *aiv, bool *is_indefinite,
> +                                Error **errp)
> +{
> +    uint8_t byte, c, int_len;
> +    uint64_t len = 0;
> +    QEMUFile *qfile = aiv->qfile;
> +    char buf[128];
> +
> +    *is_indefinite = false;
> +
> +    if (qemu_read_bytes(qfile, &byte, 1) != 1) {
> +        error_set(errp, QERR_QEMUFILE_ERROR,
> +                  "Error while reading length indicator");
> +        return ~0x0ULL;
> +    }
> +    aiv->cur_pos++;
> +
> +    if (byte == BER_LENGTH_INDEFINITE) {
> +        *is_indefinite = true;
> +        return ~0x0ULL;
> +    }
> +
> +    if (!(byte & BER_LENGTH_LONG)) {
> +        len = byte;
> +    } else {
> +        int_len = byte & BER_LENGTH_MASK;
> +        if (int_len > 8) {
> +            snprintf(buf, sizeof(buf), "ASN.1 integer length field %d > 8",
> +                     int_len);
> +            /* Length can be up to 127 byte, but it seems
> +             * safe to assume any input will be < 1TB in length. */
> +            error_set(errp, QERR_INVALID_PARAMETER, buf);
> +            return ~0x0ULL;
> +        }
> +        for (c = 0; c < int_len; c++) {
> +            len <<= 8;
> +            if (qemu_read_bytes(qfile, &byte, 1) != 1) {
> +                error_set(errp, QERR_QEMUFILE_ERROR,
> +                          "Error while reading length");
> +                return ~0x0ULL;
> +            }
> +            len |= byte;
> +        }
> +        aiv->cur_pos += int_len;
> +    }
> +
> +    if (len > aiv->max_allowed_buffer_size) {
> +        snprintf(buf, sizeof(buf),
> +                 "Length indicator (%"PRIu64") in input byte stream "
> +                 "exceeds maximum allowed length (%"PRIu64").",
> +                 len, aiv->max_allowed_buffer_size);
> +        error_set(errp,  QERR_INVALID_STREAM, buf);
> +        return ~0x0ULL;
> +    }
> +
> +    if (len > aiv->largest_needed_buffer) {
> +        aiv->largest_needed_buffer = len;
> +    }
> +
> +    return len;
> +}
> +
> +static uint64_t ber_peek_is_eoc(BERInputVisitor *biv, Error **errp)
> +{
> +    uint8_t buf[2];
> +    QEMUFile *qfile = biv->qfile;
> +
> +    if (qemu_peek_bytes(qfile, buf, 2, 0) != 2) {
> +        error_set(errp, QERR_QEMUFILE_ERROR,
> +                  "Error while peeking for EOC");
> +        return ~0x0ULL;
> +    }
> +
> +    if (buf[0] == BER_TYPE_EOC && buf[1] == 0) {
> +        return 1;
> +    }
> +
> +    return 0;
> +}
> +
> +static void ber_skip_bytes(BERInputVisitor *aiv, uint64_t to_skip,
> +                           Error **errp)
> +{
> +    uint8_t buf[1024];
> +    uint32_t skip;
> +
> +    /* skip length bytes */
> +    while (to_skip > 0) {
> +        skip = MIN(to_skip, sizeof(buf));
> +        if (qemu_read_bytes(aiv->qfile, buf, skip) != skip) {
> +            error_set(errp, QERR_QEMUFILE_ERROR,
> +                      "Error while skipping over bytes");
> +            return;
> +        }
> +        aiv->cur_pos += skip;
> +        to_skip -= skip;
> +    }
> +}
> +
> +static void ber_skip_until_eoc(BERInputVisitor *aiv, Error **errp)
> +{
> +    uint32_t ber_type_tag;
> +    uint64_t length;
> +    bool is_indefinite;
> +    uint8_t ber_type_flags;
> +    uint64_t indefinite_nesting = 1;
> +    char buf[128];
> +
> +    while (!error_is_set(errp)) {
> +        ber_type_tag = ber_read_type(aiv, &ber_type_flags, errp);
> +        if (error_is_set(errp)) {
> +            return;
> +        }
> +
> +        length = ber_read_length(aiv, &is_indefinite, errp);
> +        if (error_is_set(errp)) {
> +            return;
> +        }
> +        if (ber_type_tag == BER_TYPE_EOC) {
> +            if (length) {
> +                snprintf(buf, sizeof(buf),
> +                         "ASN.1 EOC length field at offset %" PRIu64
> +                         " is invalid", aiv->cur_pos);
> +                error_set(errp, QERR_INVALID_PARAMETER, buf);
> +                return;
> +            }
> +            if (!indefinite_nesting) {
> +                snprintf(buf, sizeof(buf),
> +                         "ASN.1 EOC at offset %" PRIu64
> +                         "not within an indefinite length",
> +                         aiv->cur_pos);
> +                error_set(errp, QERR_INVALID_PARAMETER, buf);
> +                return;
> +            }
> +#ifdef BER_DEBUG
> +            fprintf(stderr, "found end! nesting=%" PRIdMAX
> +                    ", pos=%" PRIu64 "\n",
> +                    indefinite_nesting, aiv->cur_pos);
> +#endif
> +            if (!--indefinite_nesting) {
> +                return;
> +            }
> +        }
> +        if (is_indefinite) {
> +            if ((ber_type_flags & BER_TYPE_P_C_MASK) == BER_TYPE_PRIMITIVE) {
> +                snprintf(buf, sizeof(buf),
> +                         "ASN.1 indefinite length in a primitive type "
> +                         "at offset %" PRIu64,
> +                         aiv->cur_pos);
> +                error_set(errp, QERR_INVALID_PARAMETER, buf);
> +                return;
> +            }
> +            if (indefinite_nesting == ~0x0ULL) {
> +                snprintf(buf, sizeof(buf),
> +                         "ASN.1 indefinite nesting level is too large "
> +                         "(offset %" PRIu64 ")",
> +                         aiv->cur_pos);
> +                error_set(errp, QERR_INVALID_PARAMETER, buf);
> +                return;
> +            }
> +            ++indefinite_nesting;
> +        } else {
> +#ifdef BER_DEBUG
> +            fprintf(stderr, "skipping type '%s' of length "
> +                    "%" PRIu64 " at %" PRIu64 ".\n",
> +                    ber_type_to_str(ber_type_tag), length, aiv->cur_pos);
> +#endif
> +            ber_skip_bytes(aiv, length, errp);
> +        }
> +    }
> +}
> +
> +static void ber_input_start_constructed(Visitor *v, uint32_t exp_ber_type,
> +                                        uint8_t exp_ber_flags, void **obj,
> +                                        const char *kind, const char *name,
> +                                        size_t size, Error **errp)
> +{
> +    BERInputVisitor *aiv = to_biv(v);
> +    uint32_t ber_type_tag;
> +    uint8_t ber_type_flags;
> +    int64_t len;
> +    bool is_indefinite;
> +    char buf[128];
> +
> +    ber_type_tag = ber_read_type(aiv, &ber_type_flags, errp);
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    if (ber_type_tag != exp_ber_type || ber_type_flags != exp_ber_flags) {
> +        sprintf(buf, "%s at offset %" PRIu64 "\n",
> +                ber_type_to_str(exp_ber_type), aiv->cur_pos);
> +
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE,
> +                  ber_type_to_str(ber_type_tag),
> +                  buf);
> +        return;
> +    }
> +
> +    if ((ber_type_flags & BER_TYPE_P_C_MASK) == BER_TYPE_PRIMITIVE) {
> +        snprintf(buf, sizeof(buf), "primitive type (%s)",
> +                 ber_type_to_str(ber_type_tag));
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE,
> +                  buf, "constructed type");
> +        return;
> +    }
> +
> +    len = ber_read_length(aiv, &is_indefinite, errp);
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    if (!is_indefinite) {
> +#ifdef BER_DEBUG
> +        fprintf(stderr, "structure/set len: %" PRIi64 "\n", len);
> +#endif
> +        ber_input_push(aiv, aiv->cur_pos + len, errp);
> +    } else {
> +#ifdef BER_DEBUG
> +        fprintf(stderr, "indefinite length encoding!\n");
> +#endif
> +        ber_input_push(aiv, 0, errp);
> +    }
> +
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    if (size > 0 && *obj == NULL) {
> +        *obj = g_malloc0(size);
> +#ifdef BER_DEBUG
> +        fprintf(stderr, "for type '%s' allocated buffer at %p, size = %zu\n",
> +                ber_type_to_str(ber_type_tag), *obj, size);
> +#endif
> +    }
> +}
> +
> +static void ber_input_end_constructed(Visitor *v, Error **errp)
> +{
> +    uint64_t new_pos;
> +    BERInputVisitor *aiv = to_biv(v);
> +
> +    new_pos = ber_input_pop(aiv, errp);
> +
> +    if (new_pos != 0) {
> +#ifdef BER_DEBUG
> +        fprintf(stderr, "new_pos = %" PRIu64 "\n", new_pos);
> +#endif
> +        aiv->cur_pos = new_pos;
> +    } else {
> +#ifdef BER_DEBUG
> +        fprintf(stderr, "searching for end...\n");
> +        fprintf(stderr, "cur_pos = %" PRIu64 "\n", aiv->cur_pos);
> +#endif
> +        ber_skip_until_eoc(aiv, errp);
> +    }
> +}
> +
> +static void ber_input_start_struct(Visitor *v, void **obj, const char *kind,
> +                                   const char *name, size_t size, Error 
> **errp)
> +{
> +    ber_input_start_constructed(v, BER_TYPE_SEQUENCE, BER_TYPE_CONSTRUCTED,
> +                                obj, kind, name, size, errp);
> +}
> +
> +static void ber_input_end_struct(Visitor *v, Error **errp)
> +{
> +    ber_input_end_constructed(v, errp);
> +}
> +
> +static void ber_input_start_array(Visitor *v, void **obj,
> +                                  const char *name, size_t elem_count,
> +                                  size_t elem_size, Error **errp)
> +{
> +    ber_input_start_constructed(v, BER_TYPE_SET, BER_TYPE_CONSTRUCTED,
> +                                obj, NULL, name,
> +                                elem_count * elem_size, errp);
> +}
> +
> +static void ber_input_next_array(Visitor *v, Error **errp)
> +{
> +    /* nothing to do here */
> +}
> +
> +static void ber_input_end_array(Visitor *v, Error **errp)
> +{
> +    ber_input_end_constructed(v, errp);
> +}
> +
> +static void ber_input_start_list(Visitor *v, const char *name,
> +                                 Error **errp)
> +{
> +    void *obj = NULL;
> +    ber_input_start_constructed(v, BER_TYPE_CUSTOM_LIST, 
> BER_TYPE_CONSTRUCTED,
> +                                obj, NULL, name, 0, errp);
> +    g_free(obj);
> +}
> +
> +static GenericList *ber_input_next_list(Visitor *v, GenericList **list,
> +                                        Error **errp)
> +{
> +    BERInputVisitor *biv = to_biv(v);
> +    GenericList *entry;
> +    StackEntry *se = &biv->stack[biv->nb_stack - 1];
> +
> +    if (se->cur_pos == 0) {
> +        /* indefinite lenght encoding is used */
> +        se = &biv->stack[biv->nb_stack];
> +        if (ber_peek_is_eoc(biv, errp) != 0) {
> +            return NULL;
> +        }
> +    } else if (se->cur_pos <= biv->cur_pos) {
> +        return NULL;
> +    }
> +
> +    entry = g_malloc0(sizeof(*entry));
> +    if (*list) {
> +        (*list)->next = entry;
> +    }
> +
> +    return entry;
> +}
> +
> +static void ber_input_end_list(Visitor *v, Error **errp)
> +{
> +    ber_input_end_constructed(v, errp);
> +}
> +
> +static void ber_input_integer(Visitor *v, uint8_t *obj, uint8_t maxbytes,
> +                              Error **errp)
> +{
> +    BERInputVisitor *aiv = to_biv(v);
> +    uint32_t ber_type_tag;
> +    uint8_t ber_type_flags, byte;
> +    bool is_indefinite;
> +    uint64_t len;
> +    uint64_t val = 0;
> +    int c;
> +    char buf[128];
> +
> +#ifdef BER_DEBUG
> +    fprintf(stderr, "reading int to %p\n", obj);
> +#endif
> +
> +    ber_type_tag = ber_read_type(aiv, &ber_type_flags, errp);
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +#ifdef BER_DEBUG
> +    fprintf(stderr, "%s: got type: 0x%02x, expected 0x%02x\n",
> +            __func__, ber_type_tag, BER_TYPE_INTEGER);
> +#endif
> +
> +    if (ber_type_tag != BER_TYPE_INTEGER || ber_type_flags != 0) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE,
> +                  ber_type_to_str(ber_type_tag),
> +                  ber_type_to_str(BER_TYPE_INTEGER));
> +        return;
> +    }
> +    len = ber_read_length(aiv, &is_indefinite, errp);
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +#ifdef BER_DEBUG
> +    fprintf(stderr, "pos: %" PRIu64 " int len: %" PRIi64 "\n",
> +            aiv->cur_pos, len);
> +#endif
> +
> +    if (is_indefinite) {
> +        error_set(errp, QERR_INVALID_PARAMETER_VALUE,
> +                  "ASN.1 int indicator is indefinite",
> +                  "[1..8]");
> +        return;
> +    }
> +    if (len > maxbytes) {
> +        snprintf(buf, sizeof(buf), "ASN.1 integer length indicator %" PRIi64
> +                 " is larger than expected (%u bytes)\n",
> +                 len, maxbytes);
> +        error_set(errp, QERR_INVALID_PARAMETER_VALUE,
> +                  buf, "[1..8]");
> +        return;
> +    }
> +
> +    for (c = 0; c < len ; c++) {
> +        val <<= 8;
> +        if (qemu_read_bytes(aiv->qfile, &byte, 1) != 1) {
> +            error_set(errp, QERR_QEMUFILE_ERROR,
> +                      "Error while reading integer");
> +            return;
> +        }
> +        val |= byte;
> +        if (c == 0 && (val & 0x80) == 0x80) {
> +            /* sign extend */
> +            val |= 0xFFFFFFFFFFFFFF00ULL;
> +        }
> +    }
> +    aiv->cur_pos += len;
> +#ifdef BER_DEBUG
> +    fprintf(stderr, "pos: %" PRIu64 " int: %" PRIu64 "\n", aiv->cur_pos, 
> val);
> +#endif
> +
> +    memcpy(obj, &val, maxbytes);
> +}
> +
> +static void ber_input_type_int(Visitor *v, int64_t *obj, const char *name,
> +                               Error **errp)
> +{
> +    ber_input_integer(v, (uint8_t *)obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_input_type_uint8_t(Visitor *v, uint8_t *obj,
> +                                   const char *name, Error **errp)
> +{
> +    ber_input_integer(v, (uint8_t *)obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_input_type_uint16_t(Visitor *v, uint16_t *obj,
> +                                    const char *name, Error **errp)
> +{
> +    ber_input_integer(v, (uint8_t *)obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_input_type_uint32_t(Visitor *v, uint32_t *obj,
> +                                    const char *name, Error **errp)
> +{
> +    ber_input_integer(v, (uint8_t *)obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_input_type_uint64_t(Visitor *v, uint64_t *obj,
> +                                    const char *name, Error **errp)
> +{
> +    ber_input_integer(v, (uint8_t *)obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_input_type_int8_t(Visitor *v, int8_t *obj,
> +                                  const char *name, Error **errp)
> +{
> +    ber_input_integer(v, (uint8_t *)obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_input_type_int16_t(Visitor *v, int16_t *obj,
> +                                   const char *name, Error **errp)
> +{
> +    ber_input_integer(v, (uint8_t *)obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_input_type_int32_t(Visitor *v, int32_t *obj,
> +                                   const char *name, Error **errp)
> +{
> +    ber_input_integer(v, (uint8_t *)obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_input_type_int64_t(Visitor *v, int64_t *obj,
> +                                   const char *name, Error **errp)
> +{
> +    ber_input_integer(v, (uint8_t *)obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_input_type_bool(Visitor *v, bool *obj, const char *name,
> +                                Error **errp)
> +{
> +    BERInputVisitor *aiv = to_biv(v);
> +    uint32_t ber_type_tag;
> +    uint8_t ber_type_flags, byte;
> +    bool is_indefinite;
> +    uint64_t len;
> +    char buf[128];
> +
> +    ber_type_tag = ber_read_type(aiv, &ber_type_flags, errp);
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    if (ber_type_tag != BER_TYPE_BOOLEAN || ber_type_flags != 0) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE,
> +                  ber_type_to_str(ber_type_tag),
> +                  ber_type_to_str(BER_TYPE_BOOLEAN));
> +        return;
> +    }
> +    len = ber_read_length(aiv, &is_indefinite, errp);
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +#ifdef BER_DEBUG
> +    fprintf(stderr, "pos: %" PRIu64 " bool len: %" PRIi64 "\n",
> +            aiv->cur_pos, len);
> +#endif
> +
> +    if (is_indefinite || len != 1) {
> +        snprintf(buf, sizeof(buf),
> +                 "ASN.1 bool length indicator at offset %" PRIu64
> +                 " is indefinite or != 1",
> +                 aiv->cur_pos);
> +        error_set(errp, QERR_INVALID_PARAMETER_VALUE,
> +                  buf, "1");
> +        return;
> +    }
> +    if (qemu_read_bytes(aiv->qfile, &byte, 1) != 1) {
> +        error_set(errp, QERR_QEMUFILE_ERROR,
> +                  "Error while reading boolean");
> +        return;
> +    }
> +    aiv->cur_pos++;
> +    *obj = byte;
> +
> +#ifdef BER_DEBUG
> +    fprintf(stderr, "pos: %" PRIu64 " bool: %d\n", aiv->cur_pos, *obj);
> +#endif
> +}
> +
> +/* Function for recursive reading of fragmented primitives */
> +static uint32_t ber_input_fragment(BERInputVisitor *aiv,
> +                                   uint32_t exp_type_tag,
> +                                   uint8_t exp_type_flags,
> +                                   uint8_t **buffer, size_t *buffer_len,
> +                                   bool may_realloc,
> +                                   uint32_t offset, uint32_t nesting,
> +                                   bool indefinite, uint64_t max_pos,
> +                                   const char *name, Error **errp)
> +{
> +    uint32_t ber_type_tag;
> +    uint8_t ber_type_flags;
> +    uint32_t bytes_read = 0;
> +    bool is_indefinite;
> +    uint64_t len;
> +    char buf[128];
> +
> +    assert((exp_type_flags & BER_TYPE_CONSTRUCTED) == BER_TYPE_PRIMITIVE);
> +
> +    ber_type_tag = ber_read_type(aiv, &ber_type_flags, errp);
> +    if (error_is_set(errp)) {
> +        return 0;
> +    }
> +
> +    if (ber_type_tag != exp_type_tag) {
> +        error_set(errp, QERR_INVALID_PARAMETER_TYPE,
> +                  ber_type_to_str(ber_type_tag & BER_TYPE_TAG_MASK),
> +                  ber_type_to_str(exp_type_tag));
> +        return 0;
> +    }
> +
> +    if ((ber_type_flags & BER_TYPE_CONSTRUCTED)) {
> +#ifndef BER_ALLOW_FRAGMENTED_PRIMITIVES
> +        error_set(errp, QERR_INVALID_STREAM,
> +                  "constructed encoding of primitive types is not 
> supported");
> +        goto err_exit;
> +#else
> +        if (nesting == 1) {
> +            /* don't allow further nesting */
> +            error_set(errp, QERR_INVALID_STREAM, "invalid nesting");
> +            goto err_exit;
> +        }
> +        len = ber_read_length(aiv, &is_indefinite, errp);
> +        if (error_is_set(errp)) {
> +            goto err_exit;
> +        }
> +#ifdef BER_DEBUG
> +        fprintf(stderr, "pos: %" PRIu64 " string len: %" PRIi64 "\n",
> +                aiv->cur_pos, len);
> +#endif
> +
> +        if (!is_indefinite) {
> +            if ((*buffer) == NULL) {
> +                /* allocate buffer once; due to the ASN.1 overhead it
> +                 * will be bigger than what we need */
> +                *buffer = g_malloc0(len);
> +                *buffer_len = len;
> +                may_realloc = false;
> +            }
> +        }
> +#ifdef BER_DEBUG
> +        fprintf(stderr, "recursing now to read constructed type.\n");
> +        fprintf(stderr, "  is_indefinite: %d\n", is_indefinite);
> +#endif
> +        bytes_read += ber_input_fragment(aiv, exp_type_tag, exp_type_flags,
> +                                         buffer, buffer_len, may_realloc,
> +                                         offset, nesting + 1, is_indefinite,
> +                                         aiv->cur_pos + len, name, errp);
> +        return bytes_read;
> +#endif
> +    }
> +
> +    while (true) {
> +        /* Would reading the length carry us beyond what we are allowed to
> +         * read?
> +         */
> +        if (!indefinite &&
> +            max_pos != 0 &&
> +            aiv->cur_pos + 1 > max_pos) {
> +            snprintf(buf, sizeof(buf),
> +                     "data stream would cause parsing beyond "
> +                     "allowed offset at %" PRIu64,
> +                     max_pos);
> +            /* input stream is malformed */
> +            error_set(errp, QERR_INVALID_STREAM, buf);
> +            goto err_exit;
> +        }
> +
> +        /* not-constructed case */
> +        len = ber_read_length(aiv, &is_indefinite, errp);
> +        if (error_is_set(errp)) {
> +            goto err_exit;
> +        }
> +#ifdef BER_DEBUG
> +        fprintf(stderr, "pos: %" PRIu64 " string len: %" PRIi64 "\n",
> +                    aiv->cur_pos, len);
> +#endif
> +        if (is_indefinite) {
> +            snprintf(buf, sizeof(buf),
> +                     "Got indefinite type length in primitive type (%s) at"
> +                     "offset %" PRIu64,
> +                     ber_type_to_str(ber_type_tag), aiv->cur_pos);
> +            error_set(errp, QERR_INVALID_PARAMETER, buf);
> +            goto err_exit;
> +        }
> +        /* if max_pos is not set, set it here */
> +        if (!indefinite && max_pos == 0) {
> +            max_pos = aiv->cur_pos + len;
> +        }
> +
> +        /* Would reading the data carry us beyond what we are allowed to
> +         * read ?
> +         */
> +        if (!indefinite && aiv->cur_pos + len > max_pos) {
> +            /* input stream is malformed */
> +            snprintf(buf, sizeof(buf),
> +                     "data stream would cause parsing beyond "
> +                     "allowed offset at %" PRIu64,
> +                     max_pos);
> +            error_set(errp, QERR_INVALID_STREAM, buf);
> +            goto err_exit;
> +        }
> +
> +        if (offset + len > *buffer_len) {
> +            if (!may_realloc) {
> +                snprintf(buf, sizeof(buf),
> +                         "given buffer is too small (%lu < %"PRIu64")",
> +                         (unsigned long)*buffer_len, offset + len);
> +                error_set(errp, QERR_INVALID_STREAM, buf);
> +            }
> +            /* allocate one more byte for strings, set to 0 */
> +            *buffer = g_realloc(*buffer, offset + len + 1);
> +            *buffer_len = offset + len;
> +            (*buffer)[offset+len] = 0;
> +        }
> +
> +        if (qemu_read_bytes(aiv->qfile,
> +                            &((uint8_t *)*buffer)[offset], len) != len) {
> +            error_set(errp, QERR_QEMUFILE_ERROR,
> +                      "Error while reading data");
> +            goto err_exit;
> +        }
> +
> +        offset += len;
> +        bytes_read += len;
> +
> +        aiv->cur_pos += len;
> +#ifdef BER_DEBUG
> +        if (exp_type_tag == BER_TYPE_IA5_STRING) {
> +            fprintf(stderr, "pos: %" PRIu64 " string: %.*s\n", aiv->cur_pos,
> +                    offset, *buffer);
> +        }
> +#endif
> +
> +        if (nesting == 0) {
> +            break;
> +        }
> +
> +        /* indefinite length case: loop until we encounter EOC */
> +        if (indefinite) {
> +            ber_type_tag = ber_read_type(aiv, &ber_type_flags, errp);
> +            if (error_is_set(errp)) {
> +                goto err_exit;
> +            }
> +
> +            if (ber_type_tag == BER_TYPE_EOC) {
> +                uint8_t byte;
> +                if (qemu_read_bytes(aiv->qfile, &byte, 1) != 1) {
> +                    error_set(errp, QERR_QEMUFILE_ERROR,
> +                              "Error while reading BER_TYPE_EOC length");
> +                    goto err_exit;
> +                }
> +                aiv->cur_pos++;
> +
> +                if (byte != 0) {
> +                    snprintf(buf, sizeof(buf),
> +                             "ASN.1 EOC length field is invalid at offset "
> +                             "%" PRIu64,
> +                             aiv->cur_pos);
> +                    error_set(errp, QERR_INVALID_PARAMETER, buf);
> +                    goto err_exit;
> +                }
> +                return bytes_read;
> +            }
> +
> +            if (ber_type_tag != exp_type_tag ||
> +                ber_type_flags != exp_type_flags) {
> +                snprintf(buf, sizeof(buf),
> +                         "ASN.1 type field or flags are wrong. Found "
> +                         "0x%x/%u, expected "
> +                         "0x%x/%u at offset %" PRIu64,
> +                         ber_type_tag, ber_type_flags,
> +                         exp_type_tag, exp_type_flags,
> +                         aiv->cur_pos);
> +                error_set(errp, QERR_INVALID_PARAMETER, buf);
> +                goto err_exit;
> +            }
> +            continue;
> +        }
> +
> +        /* in definite length coding case; caller told us how far to read */
> +        if (aiv->cur_pos == max_pos) {
> +            return bytes_read;
> +        }
> +
> +        ber_type_tag = ber_read_type(aiv, &ber_type_flags, errp);
> +        if (error_is_set(errp)) {
> +            goto err_exit;
> +        }
> +
> +        if ((ber_type_flags & BER_TYPE_P_C_MASK) == BER_TYPE_CONSTRUCTED) {
> +            error_set(errp, QERR_INVALID_PARAMETER_TYPE,
> +                      "constructed BER type",
> +                      ber_type_to_str(exp_type_tag));
> +            goto err_exit;
> +        }
> +
> +        if (ber_type_tag != exp_type_tag) {
> +            error_set(errp, QERR_INVALID_PARAMETER_TYPE,
> +                      ber_type_to_str(ber_type_tag & BER_TYPE_TAG_MASK),
> +                      ber_type_to_str(exp_type_tag));
> +            goto err_exit;
> +        }
> +    }
> +    return bytes_read;
> +
> +err_exit:
> +    if (may_realloc) {
> +        g_free(*buffer);
> +        *buffer = NULL;
> +    }
> +    return 0;
> +}
> +
> +static void ber_input_type_str(Visitor *v, char **obj, const char *name,
> +                               Error **errp)
> +{
> +    BERInputVisitor *aiv = to_biv(v);
> +    size_t buffer_len = 0;
> +
> +    ber_input_fragment(aiv, BER_TYPE_IA5_STRING, 0,
> +                       (uint8_t **)obj, &buffer_len, (*obj == NULL),
> +                       0, 0, false, 0, name, errp);
> +
> +    if (!error_is_set(errp) && *obj == NULL) {
> +        /* adjust NULL string to "" */
> +        *obj = g_strdup("");
> +    }
> +}
> +
> +static void ber_input_sized_buffer(Visitor *v, uint8_t **obj, size_t len,
> +                                   const char *name, Error **errp)
> +{
> +    BERInputVisitor *aiv = to_biv(v);
> +
> +    ber_input_fragment(aiv, BER_TYPE_OCTET_STRING, 0,
> +                       (uint8_t **)obj, &len, (*obj == NULL),
> +                       0, 0, false, 0, name, errp);
> +
> +#ifdef BER_DEBUG
> +    fprintf(stderr, "pos: %" PRIu64 " data at: %p data:\n",
> +            aiv->cur_pos, *obj);
> +    int i;
> +    for (i = 0; i < len; i++) {
> +        fprintf(stderr, "%02x ", (*obj)[i]);
> +        if ((i & 0xf) == 0xf) {
> +            fprintf(stderr, "\n");
> +        }
> +    }
> +    fprintf(stderr, "\n");
> +#endif
> +}
> +
> +Visitor *ber_input_get_visitor(BERInputVisitor *v)
> +{
> +    return &v->visitor;
> +}
> +
> +uint64_t ber_input_get_parser_position(BERInputVisitor *v)
> +{
> +    return v->cur_pos;
> +}
> +
> +uint64_t ber_input_get_largest_needed_buffer(BERInputVisitor *v)
> +{
> +    return v->largest_needed_buffer;
> +}
> +
> +void ber_input_visitor_cleanup(BERInputVisitor *v)
> +{
> +    g_free(v);
> +}
> +
> +BERInputVisitor *ber_input_visitor_new(QEMUFile *qfile,
> +                                       uint64_t max_allowed_buffer_size)
> +{
> +    BERInputVisitor *v;
> +
> +    v = g_malloc0(sizeof(*v));
> +
> +    v->visitor.start_struct = ber_input_start_struct;
> +    v->visitor.end_struct = ber_input_end_struct;
> +    v->visitor.start_array = ber_input_start_array;
> +    v->visitor.next_array = ber_input_next_array;
> +    v->visitor.end_array = ber_input_end_array;
> +    v->visitor.start_list = ber_input_start_list;
> +    v->visitor.next_list = ber_input_next_list;
> +    v->visitor.end_list = ber_input_end_list;
> +    v->visitor.type_int = ber_input_type_int;
> +    v->visitor.type_uint8_t = ber_input_type_uint8_t;
> +    v->visitor.type_uint16_t = ber_input_type_uint16_t;
> +    v->visitor.type_uint32_t = ber_input_type_uint32_t;
> +    v->visitor.type_uint64_t = ber_input_type_uint64_t;
> +    v->visitor.type_int8_t = ber_input_type_int8_t;
> +    v->visitor.type_int16_t = ber_input_type_int16_t;
> +    v->visitor.type_int32_t = ber_input_type_int32_t;
> +    v->visitor.type_int64_t = ber_input_type_int64_t;
> +    v->visitor.type_bool = ber_input_type_bool;
> +    v->visitor.type_str = ber_input_type_str;
> +    v->visitor.type_sized_buffer = ber_input_sized_buffer;
> +
> +    v->qfile = qfile;
> +    v->cur_pos = 0;
> +    v->max_allowed_buffer_size = max_allowed_buffer_size;
> +    v->largest_needed_buffer = 0;
> +
> +    return v;
> +}
> Index: b/ber/ber-input-visitor.h
> ===================================================================
> --- /dev/null
> +++ b/ber/ber-input-visitor.h
> @@ -0,0 +1,30 @@
> +/*
> + * BER Input Visitor header
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + *  Anthony Liguori   <address@hidden>
> + *  Stefan Berger     <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or 
> later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#ifndef BER_INPUT_VISITOR_H
> +#define BER_INPUT_VISITOR_H
> +
> +#include "include/qapi/visitor.h"
> +
> +typedef struct BERInputVisitor BERInputVisitor;
> +
> +BERInputVisitor *ber_input_visitor_new(QEMUFile *,
> +                                       uint64_t max_allowd_buffer_size);
> +void ber_input_visitor_cleanup(BERInputVisitor *v);
> +uint64_t ber_input_get_parser_position(BERInputVisitor *v);
> +uint64_t ber_input_get_largest_needed_buffer(BERInputVisitor *v);
> +
> +Visitor *ber_input_get_visitor(BERInputVisitor *v);
> +
> +#endif
> Index: b/ber/ber-output-visitor.c
> ===================================================================
> --- /dev/null
> +++ b/ber/ber-output-visitor.c
> @@ -0,0 +1,563 @@
> +/*
> + * BER Output Visitor
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + *  Anthony Liguori   <address@hidden>
> + *  Stefan Berger     <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or 
> later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#include "qemu-common.h"
> +#include "ber-output-visitor.h"
> +#include "qemu/queue.h"
> +#include "qemu-common.h"
> +#include "include/qapi/qmp/qerror.h"
> +#include "hw/hw.h"
> +#include "ber.h"
> +#include "qapi/visitor-impl.h"
> +
> +
> +#define CER_FRAGMENT_CHUNK_SIZE  1000
> +
> +/*#define BER_DEBUG*/
> +
> +typedef struct QStackEntry {
> +    QEMUFile *qfile;
> +    bool is_list_head;
> +    QTAILQ_ENTRY(QStackEntry) node;
> +} QStackEntry;
> +
> +typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
> +
> +struct BEROutputVisitor {
> +    Visitor visitor;
> +    QStack stack;
> +    QEMUFile *qfile;
> +
> +    BERTypePC mode;
> +};
> +
> +static BEROutputVisitor *to_aov(Visitor *v)
> +{
> +    return container_of(v, BEROutputVisitor, visitor);
> +}
> +
> +static void ber_output_push(BEROutputVisitor *qov, QEMUFile *qfile,
> +                            Error **errp)
> +{
> +    QStackEntry *e = g_malloc0(sizeof(*e));
> +
> +    e->qfile = qfile;
> +    e->is_list_head = true;
> +    QTAILQ_INSERT_HEAD(&qov->stack, e, node);
> +}
> +
> +static QEMUFile *ber_output_pop(BEROutputVisitor *qov)
> +{
> +    QStackEntry *e = QTAILQ_FIRST(&qov->stack);
> +    QEMUFile *qfile;
> +
> +    QTAILQ_REMOVE(&qov->stack, e, node);
> +    qfile = e->qfile;
> +    g_free(e);
> +
> +    return qfile;
> +}
> +
> +static unsigned int ber_encode_type(uint8_t *buffer, uint32_t buflen,
> +                                    enum ber_type_tag ber_type,
> +                                    uint8_t ber_type_flags,
> +                                    Error **errp)
> +{
> +    unsigned int idx = 0;
> +
> +    if (buflen < 1) {
> +        error_set(errp, QERR_BUFFER_OVERRUN);
> +        return 0;
> +    }
> +
> +    if (ber_type > BER_TYPE_LONG_FORM) {
> +        int byte = 4;
> +        uint32_t mask = (0x7f << (7 * byte));
> +        bool do_write = false;
> +
> +        buffer[0] = ber_type_flags | BER_TYPE_LONG_FORM;
> +
> +        while (byte >= 0) {
> +            if (!do_write) {
> +                if ((mask & ber_type)) {
> +                    do_write = true;
> +                    if (1 + byte + 1 > buflen) {
> +                        error_set(errp, QERR_BUFFER_OVERRUN);
> +                        return 0;
> +                    }
> +                }
> +            }
> +            if (do_write) {
> +                buffer[1 + idx] = (ber_type >> (7 * byte)) & 0x7f;
> +                if (byte > 0) {
> +                    buffer[1 + idx] |= 0x80;
> +                }
> +                idx++;
> +            }
> +            byte--;
> +            mask =  (0x7f << (7 * byte));
> +        }
> +    } else {
> +        buffer[0] = ber_type | ber_type_flags;
> +    }
> +    return 1 + idx;
> +}
> +
> +static unsigned int ber_encode_len(uint8_t *buffer, uint32_t buflen,
> +                                   uint64_t len, Error **errp)
> +{
> +    uint64_t mask = 0xFF00000000000000ULL;
> +    int shift =  64 - 8;
> +    int c = 0;
> +
> +    if (len <= 0x7f && buflen >= 1) {
> +        buffer[0] = len;
> +        return 1;
> +    }
> +
> +    while (mask && (mask & len) == 0) {
> +        mask >>= 8;
> +        shift -= 8;
> +    }
> +
> +    while (shift >= 0) {
> +        if (1 + c + 1 > buflen) {
> +            error_set(errp, QERR_BUFFER_OVERRUN);
> +            return 0;
> +        }
> +        buffer[1+c] = (len >> shift);
> +        c++;
> +        shift -= 8;
> +    }
> +
> +    buffer[0] = BER_LENGTH_LONG | c;
> +
> +    return 1 + c;
> +}
> +
> +static void ber_output_start_constructed(Visitor *v, uint32_t ber_type,
> +                                         Error **errp)
> +{
> +    BEROutputVisitor *aov = to_aov(v);
> +    uint8_t buf[20];
> +    unsigned int tag_bytes_written;
> +
> +    switch (aov->mode) {
> +    case BER_TYPE_PRIMITIVE:
> +        ber_output_push(aov, aov->qfile, errp);
> +        if (error_is_set(errp)) {
> +            return;
> +        }
> +        aov->qfile = qemu_bufopen("w", NULL);
> +        break;
> +    case BER_TYPE_CONSTRUCTED:
> +        ber_output_push(aov, aov->qfile, errp); /* needed for list support */
> +        if (error_is_set(errp)) {
> +            return;
> +        }
> +        tag_bytes_written = ber_encode_type(buf, sizeof(buf),
> +                                            ber_type, BER_TYPE_CONSTRUCTED,
> +                                            errp);
> +        if (error_is_set(errp)) {
> +            return;
> +        }
> +        buf[tag_bytes_written] = BER_LENGTH_INDEFINITE;
> +        if (qemu_write_bytes(aov->qfile, buf, 1 + tag_bytes_written) !=
> +            1 + tag_bytes_written) {
> +            error_set(errp, QERR_QEMUFILE_ERROR,
> +                      "Error while writing constructed type");
> +            return;
> +        }
> +    }
> +}
> +
> +static void ber_output_constructed_ber_close(BEROutputVisitor *aov,
> +                                             uint32_t ber_type,
> +                                             Error **errp)
> +{
> +    uint8_t buf[20];
> +    const QEMUSizedBuffer *qsb;
> +    uint64_t len;
> +    unsigned int num_bytes, tag_bytes_written;
> +    QEMUFile *qfile = ber_output_pop(aov);
> +
> +    tag_bytes_written = ber_encode_type(buf, sizeof(buf),
> +                                        ber_type, BER_TYPE_CONSTRUCTED,
> +                                        errp);
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +
> +    qsb = qemu_buf_get(aov->qfile);
> +    len = qsb_get_length(qsb);
> +#ifdef BER_DEBUG
> +    fprintf(stderr, "constructed type (0x%02x, %p) has length %ld bytes\n",
> +            ber_type, aov->qfile, len);
> +#endif
> +
> +    num_bytes = ber_encode_len(&buf[tag_bytes_written],
> +                               sizeof(buf) - tag_bytes_written,
> +                               len, errp);
> +    if (error_is_set(errp)) {
> +        return;
> +    }
> +    if (qemu_write_bytes(qfile, buf, tag_bytes_written + num_bytes) !=
> +        tag_bytes_written + num_bytes ||
> +        qemu_write_bytes(qfile, qsb_get_buffer(qsb, 0),
> +                         qsb_get_length(qsb)) != qsb_get_length(qsb)) {
> +        error_set(errp, QERR_QEMUFILE_ERROR,
> +                  "Error while writing buffer");
> +        return;
> +    }
> +
> +    qemu_fclose(aov->qfile);
> +    aov->qfile = qfile;
> +    qemu_fflush(qfile);
> +}
> +
> +static void ber_output_end_constructed(Visitor *v, uint32_t ber_type,
> +                                       Error **errp)
> +{
> +    BEROutputVisitor *aov = to_aov(v);
> +    uint8_t buf[20];
> +
> +#ifdef BER_DEBUG
> +    fprintf(stderr, "end set/struct:\n");
> +#endif
> +
> +    switch (aov->mode) {
> +    case BER_TYPE_PRIMITIVE:
> +        ber_output_constructed_ber_close(aov, ber_type, errp);
> +        break;
> +
> +    case BER_TYPE_CONSTRUCTED:
> +        ber_output_pop(aov);
> +        buf[0] = BER_TYPE_EOC;
> +        buf[1] = 0;
> +        if (qemu_write_bytes(aov->qfile, buf, 2) != 2) {
> +            error_set(errp, QERR_QEMUFILE_ERROR,
> +                      "Error while writing buffer with BER_TYPE_EOC");
> +            return;
> +        }
> +        break;
> +    }
> +}
> +
> +static void ber_output_start_struct(Visitor *v, void **obj, const char *kind,
> +                                    const char *name, size_t unused,
> +                                    Error **errp)
> +{
> +    ber_output_start_constructed(v, BER_TYPE_SEQUENCE, errp);
> +}
> +
> +static void ber_output_end_struct(Visitor *v, Error **errp)
> +{
> +    ber_output_end_constructed(v, BER_TYPE_SEQUENCE, errp);
> +}
> +
> +static void ber_output_start_array(Visitor *v, void **obj,
> +                                   const char *name, size_t elem_count,
> +                                   size_t elem_size, Error **errp)
> +{
> +    ber_output_start_constructed(v, BER_TYPE_SET, errp);
> +}
> +
> +static void ber_output_next_array(Visitor *v, Error **errp)
> +{
> +    /* nothing to do here */
> +}
> +
> +static void ber_output_end_array(Visitor *v, Error **errp)
> +{
> +    ber_output_end_constructed(v, BER_TYPE_SET, errp);
> +}
> +
> +static void ber_output_start_list(Visitor *v, const char *name,
> +                                  Error **errp)
> +{
> +    ber_output_start_constructed(v, BER_TYPE_CUSTOM_LIST, errp);
> +}
> +
> +static GenericList *ber_output_next_list(Visitor *v, GenericList **listp,
> +                                         Error **errp)
> +{
> +    GenericList *list = *listp;
> +    BEROutputVisitor *bov = to_aov(v);
> +    QStackEntry *e = QTAILQ_FIRST(&bov->stack);
> +
> +    assert(e);
> +    if (e->is_list_head) {
> +        e->is_list_head = false;
> +        return list;
> +    }
> +
> +    return list ? list->next : NULL;
> +}
> +
> +static void ber_output_end_list(Visitor *v, Error **errp)
> +{
> +    ber_output_end_constructed(v, BER_TYPE_CUSTOM_LIST, errp);
> +}
> +
> +static void ber_output_fragment(Visitor *v, uint32_t ber_type,
> +                                uint8_t *buffer,
> +                                size_t buflen, Error **errp)
> +{
> +    uint32_t offset = 0;
> +    bool fragmented = false;
> +    uint32_t chunk;
> +    unsigned int num_bytes, type_bytes;
> +    uint8_t buf[20];
> +    uint32_t chunk_size;
> +    BEROutputVisitor *aov = to_aov(v);
> +
> +    switch (aov->mode) {
> +    case BER_TYPE_CONSTRUCTED:
> +        /* X.690 9.2 */
> +        fragmented = (buflen > CER_FRAGMENT_CHUNK_SIZE);
> +        chunk_size = 1000;
> +        break;
> +    case BER_TYPE_PRIMITIVE:
> +        chunk_size = 0xffffffff;
> +        break;
> +    }
> +
> +    if (fragmented) {
> +        ber_output_start_constructed(&aov->visitor, ber_type, errp);
> +        if (error_is_set(errp)) {
> +            return;
> +        }
> +    }
> +
> +    do {
> +        chunk = (buflen - offset > chunk_size) ? chunk_size : buflen - 
> offset;
> +
> +        type_bytes = ber_encode_type(buf, sizeof(buf), ber_type, 0,
> +                                     errp);
> +        if (error_is_set(errp)) {
> +            return;
> +        }
> +        num_bytes = ber_encode_len(&buf[type_bytes], sizeof(buf) - 
> type_bytes,
> +                                   chunk, errp);
> +        if (error_is_set(errp)) {
> +            return;
> +        }
> +        if (qemu_write_bytes(aov->qfile, buf, type_bytes + num_bytes) !=
> +            type_bytes + num_bytes ||
> +            qemu_write_bytes(aov->qfile, &buffer[offset], chunk) != chunk) {
> +            error_set(errp, QERR_QEMUFILE_ERROR,
> +                      "Error while writing buffer");
> +            return;
> +        }
> +        offset += chunk;
> +    } while (offset < buflen);
> +
> +    if (fragmented) {
> +        ber_output_end_constructed(&aov->visitor, ber_type, errp);
> +    }
> +}
> +
> +static void ber_output_int(Visitor *v, int64_t val, uint8_t maxnumbytes,
> +                           Error **errp)
> +{
> +    uint8_t buf[20];
> +    int shift =  (maxnumbytes - 1) * 8;
> +    uint64_t mask = 0xFF80ULL << (shift - 8);
> +    bool exp_zeros;
> +    int c = 0;
> +    BEROutputVisitor *aov = to_aov(v);
> +
> +#ifdef BER_DEBUG
> +    fprintf(stderr, "Writing int 0x%lx (signed=%d, len=%d)\n",
> +            val, is_signed, maxnumbytes);
> +#endif
> +
> +    buf[0] = BER_TYPE_INTEGER;
> +
> +    if (maxnumbytes > 1) {
> +        exp_zeros = ((mask & val) == 0) ? true : false;
> +        while (mask != 0xFF) {
> +            if (exp_zeros) {
> +                if ((mask & val) != 0) {
> +                    break;
> +                }
> +            } else {
> +                if ((mask & val) != mask) {
> +                    break;
> +                }
> +            }
> +            shift -= 8;
> +            mask >>= 8;
> +        }
> +    }
> +
> +    while (shift >= 0) {
> +        buf[2+c] = (val >> shift);
> +        c++;
> +        shift -= 8;
> +    }
> +    buf[1] = c;
> +
> +    if (qemu_write_bytes(aov->qfile, buf, 1 + 1 + c) != 1 + 1 + c) {
> +        error_set(errp, QERR_QEMUFILE_ERROR, "Error while writing integer");
> +        return;
> +    }
> +}
> +
> +static void ber_output_type_int(Visitor *v, int64_t *obj, const char *name,
> +                                Error **errp)
> +{
> +    ber_output_int(v, *obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_output_type_uint8_t(Visitor *v, uint8_t *obj,
> +                                    const char *name, Error **errp)
> +{
> +    ber_output_int(v, *obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_output_type_uint16_t(Visitor *v, uint16_t *obj,
> +                                     const char *name, Error **errp)
> +{
> +    ber_output_int(v, *obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_output_type_uint32_t(Visitor *v, uint32_t *obj,
> +                                     const char *name, Error **errp)
> +{
> +    ber_output_int(v, *obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_output_type_uint64_t(Visitor *v, uint64_t *obj,
> +                                     const char *name, Error **errp)
> +{
> +    ber_output_int(v, *obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_output_type_int8_t(Visitor *v, int8_t *obj,
> +                                   const char *name, Error **errp)
> +{
> +    ber_output_int(v, (int64_t)*obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_output_type_int16_t(Visitor *v, int16_t *obj,
> +                                    const char *name, Error **errp)
> +{
> +    ber_output_int(v, (int64_t)*obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_output_type_int32_t(Visitor *v, int32_t *obj,
> +                                    const char *name, Error **errp)
> +{
> +    ber_output_int(v, (int64_t)*obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_output_type_int64_t(Visitor *v, int64_t *obj,
> +                                    const char *name, Error **errp)
> +{
> +    ber_output_int(v, (int64_t)*obj, sizeof(*obj), errp);
> +}
> +
> +static void ber_output_type_bool(Visitor *v, bool *obj, const char *name,
> +                                 Error **errp)
> +{
> +    BEROutputVisitor *aov = to_aov(v);
> +    bool b = 0;
> +
> +    switch (aov->mode) {
> +    case BER_TYPE_PRIMITIVE:
> +        b = *obj;
> +        break;
> +    case BER_TYPE_CONSTRUCTED:
> +        b = (*obj) ? 0xff : 0;
> +        break;
> +    }
> +    ber_output_fragment(v, BER_TYPE_BOOLEAN, (uint8_t *)&b, sizeof(b), errp);
> +}
> +
> +static void ber_output_type_str(Visitor *v, char **obj, const char *name,
> +                                Error **errp)
> +{
> +#ifdef BER_DEBUG
> +    fprintf(stderr, "Writing string %s, len = 0x%02x\n", *obj,
> +            (int)strlen(*obj));
> +#endif
> +    ber_output_fragment(v, BER_TYPE_IA5_STRING,
> +                        (uint8_t *)*obj,
> +                        *obj == NULL ? 0 : strlen(*obj), errp);
> +}
> +
> +static void ber_output_sized_buffer(Visitor *v, uint8_t **obj,
> +                                    size_t size, const char *name,
> +                                    Error **errp)
> +{
> +    ber_output_fragment(v, BER_TYPE_OCTET_STRING,
> +                        *obj, size, errp);
> +}
> +
> +void ber_output_visitor_cleanup(BEROutputVisitor *v)
> +{
> +    QStackEntry *e, *tmp;
> +
> +    QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
> +        QTAILQ_REMOVE(&v->stack, e, node);
> +        if (e->qfile) {
> +            qemu_fclose(e->qfile);
> +        }
> +        g_free(e);
> +    }
> +
> +    g_free(v);
> +}
> +
> +
> +Visitor *ber_output_get_visitor(BEROutputVisitor *v)
> +{
> +    return &v->visitor;
> +}
> +
> +BEROutputVisitor *ber_output_visitor_new(QEMUFile *qfile,
> +                                         BERTypePC mode)
> +{
> +    BEROutputVisitor *v;
> +
> +    v = g_malloc0(sizeof(*v));
> +
> +    v->visitor.start_struct = ber_output_start_struct;
> +    v->visitor.end_struct = ber_output_end_struct;
> +    v->visitor.start_array = ber_output_start_array;
> +    v->visitor.next_array = ber_output_next_array;
> +    v->visitor.end_array = ber_output_end_array;
> +    v->visitor.start_list = ber_output_start_list;
> +    v->visitor.next_list = ber_output_next_list;
> +    v->visitor.end_list = ber_output_end_list;
> +    v->visitor.type_int = ber_output_type_int;
> +    v->visitor.type_uint8_t = ber_output_type_uint8_t;
> +    v->visitor.type_uint16_t = ber_output_type_uint16_t;
> +    v->visitor.type_uint32_t = ber_output_type_uint32_t;
> +    v->visitor.type_uint64_t = ber_output_type_uint64_t;
> +    v->visitor.type_int8_t = ber_output_type_int8_t;
> +    v->visitor.type_int16_t = ber_output_type_int16_t;
> +    v->visitor.type_int32_t = ber_output_type_int32_t;
> +    v->visitor.type_int64_t = ber_output_type_int64_t;
> +    v->visitor.type_bool = ber_output_type_bool;
> +    v->visitor.type_str = ber_output_type_str;
> +    v->visitor.type_sized_buffer = ber_output_sized_buffer;
> +
> +    QTAILQ_INIT(&v->stack);
> +    v->qfile = qfile;
> +    v->mode = mode;
> +
> +    return v;
> +}
> Index: b/ber/ber-output-visitor.h
> ===================================================================
> --- /dev/null
> +++ b/ber/ber-output-visitor.h
> @@ -0,0 +1,28 @@
> +/*
> + * BER Output Visitor header
> + *
> + * Copyright IBM, Corp. 2011
> + *
> + * Authors:
> + *  Anthony Liguori   <address@hidden>
> + *  Stefan Berger     <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or 
> later.
> + * See the COPYING.LIB file in the top-level directory.
> + *
> + */
> +
> +#ifndef BER_OUTPUT_VISITOR_H
> +#define BER_OUTPUT_VISITOR_H
> +
> +#include "include/qapi/visitor.h"
> +#include "ber.h"
> +
> +typedef struct BEROutputVisitor BEROutputVisitor;
> +
> +BEROutputVisitor *ber_output_visitor_new(QEMUFile *, BERTypePC mode);
> +void ber_output_visitor_cleanup(BEROutputVisitor *v);
> +
> +Visitor *ber_output_get_visitor(BEROutputVisitor *v);
> +
> +#endif
> Index: b/ber/ber.h
> ===================================================================
> --- /dev/null
> +++ b/ber/ber.h
> @@ -0,0 +1,85 @@
> +#ifndef BER_BER_H
> +#define BER_BER_H
> +
> +/* This is a subset of BER for QEMU use. */
> +/* QEMU will use the DER encoding always with one extension from
> + * CER: SET and SEQUENCE types can have indefinite-length encoding
> + * if the encoding is not all immediately available.
> + *
> + * We assume that SET encodings can be available or not available,
> + * and that SEQUENCE encodings are available unless a SEQUENCE includes
> + * a non-available SET.
> + *
> + * The last is an extension to allow an arbitrarily large SET
> + * to be produced online without knowing the length in advance.
> + *
> + * All types used shall be universal, with explicit tagging, to simplify
> + * use by external tools.
> + */
> +
> +typedef enum ber_type_class {
> +    BER_TYPE_CLASS_UNIVERSAL = 0x0 << 7,
> +    BER_TYPE_CLASS_APPLICATION = 0x1 << 6,
> +    BER_TYPE_CLASS_CONTENT_SPECIFIC = 0x2 << 6,
> +    BER_TYPE_CLASS_PRIVATE = 0x3 << 6,
> +    BER_TYPE_CLASS_MASK = 0x3 << 6 /* Mask to get class */
> +} BERTypeClass;
> +
> +/* P/C bit */
> +typedef enum ber_type_p_c {
> +    BER_TYPE_PRIMITIVE = (0x0 << 5),
> +    BER_TYPE_CONSTRUCTED = (0x1 << 5),
> +    BER_TYPE_P_C_MASK = (0x1 << 5) /* Mask to get P/C bit */
> +} BERTypePC;
> +
> +typedef enum ber_type_tag {
> +    BER_TYPE_EOC              /*  P        0       0*/,
> +    BER_TYPE_BOOLEAN          /*  P        1       1*/,
> +    BER_TYPE_INTEGER          /*  P        2       2*/,
> +    BER_TYPE_BIT_STRING       /*  P/C      3       3*/,
> +    BER_TYPE_OCTET_STRING     /*  P/C      4       4*/,
> +    BER_TYPE_NULL             /*  P        5       5*/,
> +    BER_TYPE_OBJECT_ID        /*  P        6       6*/,
> +    BER_TYPE_OBJECT_DESC      /*  P        7       7*/,
> +    BER_TYPE_EXTERNAL         /*  C        8       8*/,
> +    BER_TYPE_REAL             /*  P        9       9*/,
> +    BER_TYPE_ENUMERATED       /*  P        10      A*/,
> +    BER_TYPE_EMBEDDED         /*  C        11      B*/,
> +    BER_TYPE_UTF8_STRING      /*  P/C      12      C*/,
> +    BER_TYPE_RELATIVE_OID     /*  P        13      D*/,
> +    BER_TYPE_UNUSED_0xE       /*                    */,
> +    BER_TYPE_UNUSED_0xF       /*                    */,
> +    BER_TYPE_SEQUENCE         /*  C        16      10*/,
> +    BER_TYPE_SET              /*  C        17      11*/,
> +    BER_TYPE_NUMERIC_STRING   /*  P/C      18      12*/,
> +    BER_TYPE_PRINTABLE_STRING /*  P/C      19      13*/,
> +    BER_TYPE_T61STRING        /*  P/C      20      14*/,
> +    BER_TYPE_VIDEOTEX_STRING  /*  P/C      21      15*/,
> +    BER_TYPE_IA5_STRING       /*  P/C      22      16*/,
> +    BER_TYPE_UTCTIME          /*  P/C      23      17*/,
> +    BER_TYPE_GENERALIZED_TIME /*  P/C      24      18*/,
> +    BER_TYPE_GRAPHIC_STRING   /*  P/C      25      19*/,
> +    BER_TYPE_VISIBLE_STRING   /*  P/C      26      1A*/,
> +    BER_TYPE_GENERAL_STRING   /*  P/C      27      1B*/,
> +    BER_TYPE_UNIVERSAL_STRING /*  P/C      28      1C*/,
> +    BER_TYPE_CHARACTER_STRING /*  P/C      29      1D*/,
> +    BER_TYPE_BMP_STRING       /*  P/C      30      1E*/,
> +    BER_TYPE_LONG_FORM        /*  -        31      1F*/,
> +    BER_TYPE_TAG_MASK = 0x1f /* Mask to get tag */,
> +    BER_TYPE_CUSTOM_LIST = 0x20,
> +} BERTypeTag;
> +
> +typedef enum ber_length {
> +    /* Special length values */
> +    BER_LENGTH_INDEFINITE = (0x1 << 7),
> +    BER_LENGTH_RESERVED = 0xFF,
> +    /* Anything else is either short or long */
> +    BER_LENGTH_SHORT = (0x0 << 7),
> +    BER_LENGTH_LONG = (0x1 << 7),
> +    BER_LENGTH_SHORT_LONG_MASK = (0x1 << 7),
> +    BER_LENGTH_MASK = 0x7F,
> +} BERLength;
> +
> +const char *ber_type_to_str(uint8_t ber_type);
> +
> +#endif /* BER_BER_H */
> Index: b/qapi/qapi-visit-core.c
> ===================================================================
> --- a/qapi/qapi-visit-core.c
> +++ b/qapi/qapi-visit-core.c
> @@ -67,6 +67,28 @@ void visit_end_list(Visitor *v, Error **
>      v->end_list(v, errp);
>  }
> 
> +void visit_start_array(Visitor *v, void **obj, const char *name,
> +                       size_t elem_count, size_t elem_size, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->start_array(v, obj, name, elem_count, elem_size, errp);
> +    }
> +}
> +
> +void visit_next_array(Visitor *v, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->next_array(v, errp);
> +    }
> +}
> +
> +void visit_end_array(Visitor *v, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->end_array(v, errp);
> +    }
> +}
> +
>  void visit_start_optional(Visitor *v, bool *present, const char *name,
>                            Error **errp)
>  {
> @@ -313,3 +335,11 @@ void input_type_enum(Visitor *v, int *ob
>      g_free(enum_str);
>      *obj = value;
>  }
> +
> +void visit_type_sized_buffer(Visitor *v, uint8_t **obj, size_t len,
> +                             const char *name, Error **errp)
> +{
> +    if (!error_is_set(errp)) {
> +        v->type_sized_buffer(v, obj, len, name, errp);
> +    }
> +}
> Index: b/include/qapi/visitor.h
> ===================================================================
> --- a/include/qapi/visitor.h
> +++ b/include/qapi/visitor.h
> @@ -22,6 +22,10 @@ typedef struct GenericList
>      struct GenericList *next;
>  } GenericList;
> 
> +typedef struct GenericItem {
> +    void *value;
> +} GenericItem;
> +
>  typedef struct Visitor Visitor;
> 
>  void visit_start_handle(Visitor *v, void **obj, const char *kind,
> @@ -33,6 +37,10 @@ void visit_end_struct(Visitor *v, Error
>  void visit_start_list(Visitor *v, const char *name, Error **errp);
>  GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
>  void visit_end_list(Visitor *v, Error **errp);
> +void visit_start_array(Visitor *v, void **obj, const char *name,
> +                       size_t elem_count, size_t elem_size, Error **errp);
> +void visit_next_array(Visitor *v, Error **errp);
> +void visit_end_array(Visitor *v, Error **errp);
>  void visit_start_optional(Visitor *v, bool *present, const char *name,
>                            Error **errp);
>  void visit_end_optional(Visitor *v, Error **errp);
> @@ -51,5 +59,7 @@ void visit_type_size(Visitor *v, uint64_
>  void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
>  void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
>  void visit_type_number(Visitor *v, double *obj, const char *name, Error 
> **errp);
> +void visit_type_sized_buffer(Visitor *v, uint8_t **obj, size_t len,
> +                             const char *name, Error **errp);
> 
>  #endif
> Index: b/include/qapi/visitor-impl.h
> ===================================================================
> --- a/include/qapi/visitor-impl.h
> +++ b/include/qapi/visitor-impl.h
> @@ -26,14 +26,37 @@ struct Visitor
>      GenericList *(*next_list)(Visitor *v, GenericList **list, Error **errp);
>      void (*end_list)(Visitor *v, Error **errp);
> 
> +    void (*start_array)(Visitor *v, void **obj, const char *name,
> +                        size_t elem_count, size_t elem_size, Error **errp);
> +    void (*next_array)(Visitor *v, Error **errp);
> +    void (*end_array)(Visitor *v, Error **errp);

There's a more recent patch to add these interfaces, they were
renamed in response to review comments from Anthony, so we should name
those accordingly. Adding Visitor interfaces for arrays also deserves
it's own patch and careful attention, so please include this patch in your
series:

http://lists.gnu.org/archive/html/qemu-devel/2012-10/msg05782.html

> +
>      void (*type_enum)(Visitor *v, int *obj, const char *strings[],
>                        const char *kind, const char *name, Error **errp);
> 
>      void (*type_int)(Visitor *v, int64_t *obj, const char *name, Error 
> **errp);
> +    void (*type_uint8_t)(Visitor *v, uint8_t *obj, const char *name,
> +          Error **errp);
> +    void (*type_uint16_t)(Visitor *v, uint16_t *obj, const char *name,
> +          Error **errp);
> +    void (*type_uint32_t)(Visitor *v, uint32_t *obj, const char *name,
> +          Error **errp);
> +    void (*type_uint64_t)(Visitor *v, uint64_t *obj, const char *name,
> +          Error **errp);
> +    void (*type_int8_t)(Visitor *v, int8_t *obj, const char *name,
> +                        Error **errp);
> +    void (*type_int16_t)(Visitor *v, int16_t *obj, const char *name,
> +                         Error **errp);
> +    void (*type_int32_t)(Visitor *v, int32_t *obj, const char *name,
> +          Error **errp);
> +    void (*type_int64_t)(Visitor *v, int64_t *obj, const char *name,
> +          Error **errp);

These interfaces already exist under a slightly different name:

    void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error 
**errp);
    void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error 
**errp);                                                                        
                         
    void (*type_uint32)(Visitor *v, uint32_t *obj, const char *name, Error 
**errp);
    void (*type_uint64)(Visitor *v, uint64_t *obj, const char *name, Error 
**errp);
    void (*type_int8)(Visitor *v, int8_t *obj, const char *name, Error **errp);
    void (*type_int16)(Visitor *v, int16_t *obj, const char *name, Error 
**errp);
    void (*type_int32)(Visitor *v, int32_t *obj, const char *name, Error 
**errp);
    void (*type_int64)(Visitor *v, int64_t *obj, const char *name, Error 
**errp);


>      void (*type_bool)(Visitor *v, bool *obj, const char *name, Error **errp);
>      void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
>      void (*type_number)(Visitor *v, double *obj, const char *name,
>                          Error **errp);
> +    void (*type_sized_buffer)(Visitor *v, uint8_t **obj, size_t size,
> +                              const char *name, Error **errp);

Can't {start,next,end}_array handle this already?

> 
>      /* May be NULL */
>      void (*start_optional)(Visitor *v, bool *present, const char *name,
> Index: b/include/qapi/qmp/qerror.h
> ===================================================================
> --- a/include/qapi/qmp/qerror.h
> +++ b/include/qapi/qmp/qerror.h
> @@ -249,4 +249,10 @@ void assert_no_error(Error *err);
>  #define QERR_SOCKET_CREATE_FAILED \
>      ERROR_CLASS_GENERIC_ERROR, "Failed to create socket"
> 
> +#define QERR_INVALID_STREAM \
> +    ERROR_CLASS_GENERIC_ERROR, "Data stream is invalid, error was '%s'"
> +
> +#define QERR_QEMUFILE_ERROR \
> +    ERROR_CLASS_GENERIC_ERROR, "QEMUFile has an error, error was '%s'"
> +

new policy on error classes is to avoid adding new ones and stick with
ERROR_CLASS_GENERIC_ERROR/error_setg() unless there's some special reason
not to.

>  #endif /* QERROR_H */
> Index: b/ber/Makefile.objs
> ===================================================================
> --- /dev/null
> +++ b/ber/Makefile.objs
> @@ -0,0 +1,2 @@
> +common-obj-y += ber-common.o ber-input-visitor.o ber-output-visitor.o
> +
> 
> 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]