[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 6/9] asn1_output-visitor.diff
From: |
Joel Schopp |
Subject: |
[Qemu-devel] [PATCH 6/9] asn1_output-visitor.diff |
Date: |
Tue, 12 Mar 2013 22:09:39 -0500 |
Implement an output visitor for ASN.1 BER encoding.
Cc: Michael Tsirkin <address@hidden>
Signed-off-by: Stefan Berger <address@hidden>
Signed-off-by: Joel Schopp <address@hidden>
---
configure | 2 +-
include/qapi/ber-output-visitor.h | 28 ++
include/qapi/ber.h | 107 +++++++
qapi/Makefile.objs | 1 +
qapi/ber-common.c | 86 ++++++
qapi/ber-common.h | 29 ++
qapi/ber-output-visitor.c | 617 +++++++++++++++++++++++++++++++++++++
7 files changed, 869 insertions(+), 1 deletion(-)
create mode 100644 include/qapi/ber-output-visitor.h
create mode 100644 include/qapi/ber.h
create mode 100644 qapi/ber-common.c
create mode 100644 qapi/ber-common.h
create mode 100644 qapi/ber-output-visitor.c
diff --git a/configure b/configure
index 84317c6..6dcf00e 100755
--- a/configure
+++ b/configure
@@ -2826,7 +2826,7 @@ fi
# Do we need libm
cat > $TMPC << EOF
#include <math.h>
-int main(void) { return isnan(sin(0.0)); }
+int main(void) { return isnan(nan("NAN")); }
EOF
if compile_prog "" "" ; then
:
diff --git a/include/qapi/ber-output-visitor.h
b/include/qapi/ber-output-visitor.h
new file mode 100644
index 0000000..bd7e198
--- /dev/null
+++ b/include/qapi/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 "qapi/visitor.h"
+#include "qapi/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
diff --git a/include/qapi/ber.h b/include/qapi/ber.h
new file mode 100644
index 0000000..9314b28
--- /dev/null
+++ b/include/qapi/ber.h
@@ -0,0 +1,107 @@
+/*
+ * ASN.1 Basic Encoding Rules Common functions
+ *
+ * Copyright IBM, Corp. 2011, 2013
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Authors:
+ * Stefan Berger <address@hidden>
+ * Michael Tsirkin <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 QAPI_BER_H
+#define QAPI_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.
+ */
+
+
+#define BER_TYPE_CLASS_SHIFT 6
+#define BER_TYPE_PC_SHIFT 5
+
+typedef enum ber_type_class {
+ BER_TYPE_CLASS_UNIVERSAL = 0x0 << BER_TYPE_CLASS_SHIFT,
+ BER_TYPE_CLASS_APPLICATION = 0x1 << BER_TYPE_CLASS_SHIFT,
+ BER_TYPE_CLASS_CONTENT_SPECIFIC = 0x2 << BER_TYPE_CLASS_SHIFT,
+ BER_TYPE_CLASS_PRIVATE = 0x3 << BER_TYPE_CLASS_SHIFT,
+ BER_TYPE_CLASS_MASK = 0x3 << BER_TYPE_CLASS_SHIFT /* Mask to get class */
+} BERTypeClass;
+
+/* P/C bit */
+typedef enum ber_type_p_c {
+ BER_TYPE_PRIMITIVE = 0x0 << BER_TYPE_PC_SHIFT,
+ BER_TYPE_CONSTRUCTED = 0x1 << BER_TYPE_PC_SHIFT,
+ BER_TYPE_P_C_MASK = 0x1 << BER_TYPE_PC_SHIFT /* 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);
+const char *ber_type_pc_to_str(enum ber_type_class ber_type_flags);
+const char *ber_type_class_to_str(enum ber_type_class ber_type_flags);
+
+#endif /* QAPI_BER_H */
+
diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs
index 1f9c973..519e3ee 100644
--- a/qapi/Makefile.objs
+++ b/qapi/Makefile.objs
@@ -3,3 +3,4 @@ util-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o
util-obj-y += string-input-visitor.o string-output-visitor.o
util-obj-y += opts-visitor.o
+util-obj-y += ber-common.o ber-output-visitor.o
diff --git a/qapi/ber-common.c b/qapi/ber-common.c
new file mode 100644
index 0000000..1053c41
--- /dev/null
+++ b/qapi/ber-common.c
@@ -0,0 +1,86 @@
+/*
+ * ASN.1 Basic Encoding Rules Common functions
+ *
+ * Copyright IBM, Corp. 2011, 2013
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Authors:
+ * Stefan Berger <address@hidden>
+ * Michael Tsirkin <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 "qapi/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];
+}
+
+static const char *ber_pc_names[] = {
+ "BER_PRIMITIVE",
+ "BER_CONSTRUCTED"
+};
+
+const char *ber_type_pc_to_str(enum ber_type_class ber_type_flags)
+{
+ int idx = (ber_type_flags & BER_TYPE_P_C_MASK) >>
+ BER_TYPE_PC_SHIFT;
+
+ return ber_pc_names[idx];
+}
+
+static const char *ber_class_names[] = {
+ "BER_CLASS_UNIVERSAL",
+ "BER_CLASS_APPLICATION",
+ "BER_CLASS_CONTEXT",
+ "BER_CLASS_PRIVATE"
+};
+
+const char *ber_type_class_to_str(enum ber_type_class ber_type_flags)
+{
+ int idx = (ber_type_flags & BER_TYPE_CLASS_MASK) >>
+ BER_TYPE_CLASS_SHIFT;
+
+ return ber_class_names[idx];
+}
diff --git a/qapi/ber-common.h b/qapi/ber-common.h
new file mode 100644
index 0000000..c9fd2dd
--- /dev/null
+++ b/qapi/ber-common.h
@@ -0,0 +1,29 @@
+/*
+ * BER Visitor -- common code
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * 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.
+ *
+ */
+#ifndef __QAPI_BER_COMMON_H__
+#define __QAPI_BER_COMMON_H__
+
+#include <stdint.h>
+
+#include "qemu/compiler.h"
+
+struct ieee754_buffer {
+ uint8_t type;
+ uint8_t length;
+ uint8_t first;
+ uint16_t exponent;
+ uint32_t mant_hi;
+ uint32_t mant_lo;
+} QEMU_PACKED;
+
+#endif /* __QAPI_BER_COMMON_H__ */
diff --git a/qapi/ber-output-visitor.c b/qapi/ber-output-visitor.c
new file mode 100644
index 0000000..f32469d
--- /dev/null
+++ b/qapi/ber-output-visitor.c
@@ -0,0 +1,617 @@
+/*
+ * BER Output Visitor
+ *
+ * Copyright IBM, Corp. 2011, 2013
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Authors:
+ * Anthony Liguori <address@hidden>
+ * Stefan Berger <address@hidden>
+ * Michael Tsirkin <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 <math.h>
+#include <glib.h>
+
+#include "qemu-common.h"
+#include "qapi/ber-common.h"
+#include "qapi/ber-output-visitor.h"
+#include "qemu/queue.h"
+#include "qemu-common.h"
+#include "include/qapi/qmp/qerror.h"
+#include "hw/hw.h"
+#include "qapi/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_setg(errp, "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_setg(errp, "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_setg(errp, "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_carray(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_carray(Visitor *v, Error **errp)
+{
+ /* nothing to do here */
+}
+
+static void ber_output_end_carray(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_setg(errp, "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
+
+ /*
+ * We encode ints with fixed-witdh so that they will use
+ * the same number of bytes indepent of their value.
+ * The 'universal' encoding would not encode a 32bit '0'
+ * with 4 bytes, so this is an application-specific encoding.
+ */
+ buf[0] = BER_TYPE_CLASS_APPLICATION | BER_TYPE_PRIMITIVE |
+ 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_setg(errp, "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(Visitor *v, uint8_t *obj,
+ const char *name, Error **errp)
+{
+ ber_output_int(v, *obj, sizeof(*obj), errp);
+}
+
+static void ber_output_type_uint16(Visitor *v, uint16_t *obj,
+ const char *name, Error **errp)
+{
+ ber_output_int(v, *obj, sizeof(*obj), errp);
+}
+
+static void ber_output_type_uint32(Visitor *v, uint32_t *obj,
+ const char *name, Error **errp)
+{
+ ber_output_int(v, *obj, sizeof(*obj), errp);
+}
+
+static void ber_output_type_uint64(Visitor *v, uint64_t *obj,
+ const char *name, Error **errp)
+{
+ ber_output_int(v, *obj, sizeof(*obj), errp);
+}
+
+static void ber_output_type_int8(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(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(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(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);
+}
+
+static void ber_output_type_number(Visitor *v, double *obj, const char *name,
+ Error **errp)
+{
+ BEROutputVisitor *aov = to_aov(v);
+ GDoubleIEEE754 num;
+ uint8_t first;
+ struct ieee754_buffer number;
+
+ /* encode it as fixed-width double */
+ number.type = BER_TYPE_CLASS_APPLICATION | BER_TYPE_PRIMITIVE |
+ BER_TYPE_REAL;
+ number.length = sizeof(number) - offsetof(struct ieee754_buffer, first);
+
+ num.v_double = *obj;
+
+ if (isnan(*obj)) {
+ /* special encoding supported here; not found in spec. */
+ first = 0x42;
+ } else if (isinf(*obj)) {
+ /* spec. 8.5.8 */
+ if (num.mpn.sign) {
+ first = 0x41; /* -oo */
+ } else {
+ first = 0x40; /* +oo */
+ }
+ } else {
+ first = 0x80;
+ if (num.mpn.sign) {
+ first |= 0x40;
+ }
+ /* Base 2; 0 for scaling factor; 2nd and 3rd octet encode exp. */
+ first |= 0x1;
+ }
+
+ number.first = first;
+ number.exponent = cpu_to_be16(num.mpn.biased_exponent);
+ number.mant_hi = cpu_to_be32(num.mpn.mantissa_high);
+ number.mant_lo = cpu_to_be32(num.mpn.mantissa_low);
+
+ if (qemu_write_bytes(aov->qfile, (uint8_t *)&number, sizeof(number)) !=
+ sizeof(number)) {
+ error_setg(errp, "QEMUFile error: Error while writing double.");
+ }
+}
+
+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_carray = ber_output_start_carray;
+ v->visitor.next_carray = ber_output_next_carray;
+ v->visitor.end_carray = ber_output_end_carray;
+ 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 = ber_output_type_uint8;
+ v->visitor.type_uint16 = ber_output_type_uint16;
+ v->visitor.type_uint32 = ber_output_type_uint32;
+ v->visitor.type_uint64 = ber_output_type_uint64;
+ v->visitor.type_int8 = ber_output_type_int8;
+ v->visitor.type_int16 = ber_output_type_int16;
+ v->visitor.type_int32 = ber_output_type_int32;
+ v->visitor.type_int64 = ber_output_type_int64;
+ 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;
+ v->visitor.type_number = ber_output_type_number;
+
+ QTAILQ_INIT(&v->stack);
+ v->qfile = qfile;
+ v->mode = mode;
+
+ return v;
+}
--
1.7.10.4
- [Qemu-devel] [PATCH 0/9 v2] Implement and test asn1 ber visitors, Joel Schopp, 2013/03/12
- [Qemu-devel] [PATCH 5/9] qapi_sized_buffer, Joel Schopp, 2013/03/12
- [Qemu-devel] [PATCH 3/9] two new file wrappers, Joel Schopp, 2013/03/12
- [Qemu-devel] [PATCH 2/9] qapi_c_arrays.diff, Joel Schopp, 2013/03/12
- [Qemu-devel] [PATCH 9/9] update_maintainers.diff, Joel Schopp, 2013/03/12
- [Qemu-devel] [PATCH 4/9] qemu_qsb.diff, Joel Schopp, 2013/03/12
- [Qemu-devel] [PATCH 1/9] qemu-file, Joel Schopp, 2013/03/12
- [Qemu-devel] [PATCH 6/9] asn1_output-visitor.diff,
Joel Schopp <=
- [Qemu-devel] [PATCH 8/9] asn1_test_visitor_serialization.diff, Joel Schopp, 2013/03/12
- [Qemu-devel] [PATCH 7/9] asn1_input-visitor.diff, Joel Schopp, 2013/03/12