summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2010-01-12 11:29:32 -0800
committerJoshua Haberman <joshua@reverberate.org>2010-01-12 11:29:32 -0800
commitd7d1b2a14120e0194aadcfcb327a542f81213058 (patch)
treee4736491eee14639e9ae3242f8236380d43f0b69
parent02d2f8afb81eebbb7aab6f9a07f7e5cfcebbba2c (diff)
Move many serializing functions to .cc file, since they do not need to be exposed.
-rw-r--r--Makefile2
-rw-r--r--src/upb_serialize.c184
-rw-r--r--src/upb_serialize.h196
-rw-r--r--src/upb_sink.h2
4 files changed, 195 insertions, 189 deletions
diff --git a/Makefile b/Makefile
index 0fd7f65..65ba41e 100644
--- a/Makefile
+++ b/Makefile
@@ -47,7 +47,7 @@ clean:
# The core library (src/libupb.a)
SRC=src/upb.c src/upb_parse.c src/upb_table.c src/upb_def.c src/upb_data.c \
- descriptor/descriptor.c src/upb_text.c
+ src/upb_serialize.c descriptor/descriptor.c src/upb_text.c
# Override the optimization level for upb_def.o, because it is not in the
# critical path but gets very large when -O3 is used.
src/upb_def.o: src/upb_def.c
diff --git a/src/upb_serialize.c b/src/upb_serialize.c
index a1d4718..8527f1e 100644
--- a/src/upb_serialize.c
+++ b/src/upb_serialize.c
@@ -7,12 +7,188 @@
#include "upb_serialize.h"
#include "descriptor.h"
-upb_status_t upb_serialize_value(uint8_t *buf, uint8_t *end, upb_field_type_t ft,
- union upb_value_ptr v, uint8_t **outbuf)
+/* Functions for calculating sizes. *******************************************/
+
+INLINE size_t upb_v_uint64_t_size(uint64_t val) {
+#ifdef __GNUC__
+ int high_bit = 63 - __builtin_clzll(val); /* 0-based, undef if val == 0. */
+#else
+ int high_bit = 0;
+ uint64_t tmp = val;
+ while(tmp >>= 1) high_bit++;
+#endif
+ return val == 0 ? 1 : high_bit / 7 + 1;
+}
+
+INLINE size_t upb_v_int32_t_size(int32_t val) {
+ /* v_uint32's are sign-extended to maintain wire compatibility with int64s. */
+ return upb_v_uint64_t_size((int64_t)val);
+}
+INLINE size_t upb_v_uint32_t_size(uint32_t val) {
+ return upb_v_uint64_t_size(val);
+}
+INLINE size_t upb_f_uint64_t_size(uint64_t val) {
+ (void)val; /* Length is independent of value. */
+ return sizeof(uint64_t);
+}
+INLINE size_t upb_f_uint32_t_size(uint32_t val) {
+ (void)val; /* Length is independent of value. */
+ return sizeof(uint32_t);
+}
+
+
+/* Functions to write wire values. ********************************************/
+
+/* Puts a varint (wire type: UPB_WIRE_TYPE_VARINT). */
+uint8_t *upb_put_v_uint64_t(uint8_t *buf, uint8_t *end, uint64_t val,
+ struct upb_status *status)
+{
+ do {
+ uint8_t byte = val & 0x7f;
+ val >>= 7;
+ if(val) byte |= 0x80;
+ if(buf >= end) {
+ status->code = UPB_STATUS_NEED_MORE_DATA;
+ return end;
+ }
+ *buf++ = byte;
+ } while(val);
+ return buf;
+}
+
+/* Puts an unsigned 32-bit varint, verbatim. Never uses the high 64 bits. */
+uint8_t *upb_put_v_uint32_t(uint8_t *buf, uint8_t *end, uint32_t val,
+ struct upb_status *status)
+{
+ return upb_put_v_uint64_t(buf, end, val, status);
+}
+
+/* Puts a signed 32-bit varint, first sign-extending to 64-bits. We do this to
+ * maintain wire-compatibility with 64-bit signed integers. */
+uint8_t *upb_put_v_int32_t(uint8_t *buf, uint8_t *end, int32_t val,
+ struct upb_status *status)
+{
+ return upb_put_v_uint64_t(buf, end, (int64_t)val, status);
+}
+
+void upb_put32(uint8_t *buf, uint32_t val) {
+ buf[0] = val & 0xff;
+ buf[1] = (val >> 8) & 0xff;
+ buf[2] = (val >> 16) & 0xff;
+ buf[3] = (val >> 24);
+}
+
+/* Puts a fixed-length 32-bit integer (wire type: UPB_WIRE_TYPE_32BIT). */
+uint8_t *upb_put_f_uint32_t(uint8_t *buf, uint8_t *end, uint32_t val,
+ struct upb_status *status)
+{
+ uint8_t *uint32_end = buf + sizeof(uint32_t);
+ if(uint32_end > end) {
+ status->code = UPB_STATUS_NEED_MORE_DATA;
+ return end;
+ }
+#if UPB_UNALIGNED_READS_OK
+ *(uint32_t*)buf = val;
+#else
+ upb_put32(buf, val);
+#endif
+ return uint32_end;
+}
+
+/* Puts a fixed-length 64-bit integer (wire type: UPB_WIRE_TYPE_64BIT). */
+uint8_t *upb_put_f_uint64_t(uint8_t *buf, uint8_t *end, uint64_t val,
+ struct upb_status *status)
+{
+ uint8_t *uint64_end = buf + sizeof(uint64_t);
+ if(uint64_end > end) {
+ status->code = UPB_STATUS_NEED_MORE_DATA;
+ return end;
+ }
+#if UPB_UNALIGNED_READS_OK
+ *(uint64_t*)buf = val;
+#else
+ upb_put32(buf, (uint32_t)val);
+ upb_put32(buf, (uint32_t)(val >> 32));
+#endif
+ return uint64_end;
+}
+
+/* Functions to write .proto values. ******************************************/
+
+/* Performs zig-zag encoding, which is used by sint32 and sint64. */
+INLINE uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); }
+INLINE uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); }
+
+/* Use macros to define a set of two functions for each .proto type:
+ *
+ * // Converts and writes a .proto value into buf. "end" indicates the end
+ * // of the current available buffer (if the buffer does not contain enough
+ * // space UPB_STATUS_NEED_MORE_DATA is returned). On success, *outbuf will
+ * // point one past the data that was written.
+ * uint8_t *upb_put_INT32(uint8_t *buf, uint8_t *end, int32_t val,
+ * struct upb_status *status);
+ *
+ * // Returns the number of bytes required to serialize val.
+ * size_t upb_get_INT32_size(int32_t val);
+ *
+ * // Given a .proto value s (source) convert it to a wire value.
+ * uint32_t upb_vtowv_INT32(int32_t s);
+ */
+
+#define VTOWV(type, wire_t, val_t) \
+ INLINE wire_t upb_vtowv_ ## type(val_t s)
+
+#define PUT(type, v_or_f, wire_t, val_t, member_name) \
+ INLINE uint8_t *upb_put_ ## type(uint8_t *buf, uint8_t *end, val_t val, \
+ struct upb_status *status) { \
+ wire_t tmp = upb_vtowv_ ## type(val); \
+ return upb_put_ ## v_or_f ## _ ## wire_t(buf, end, tmp, status); \
+ }
+
+#define T(type, v_or_f, wire_t, val_t, member_name) \
+ INLINE size_t upb_get_ ## type ## _size(val_t val) { \
+ return upb_ ## v_or_f ## _ ## wire_t ## _size(val); \
+ } \
+ VTOWV(type, wire_t, val_t); /* prototype for PUT below */ \
+ PUT(type, v_or_f, wire_t, val_t, member_name) \
+ VTOWV(type, wire_t, val_t)
+
+T(INT32, v, uint32_t, int32_t, int32) { return (uint32_t)s; }
+T(INT64, v, uint64_t, int64_t, int64) { return (uint64_t)s; }
+T(UINT32, v, uint32_t, uint32_t, uint32) { return s; }
+T(UINT64, v, uint64_t, uint64_t, uint64) { return s; }
+T(SINT32, v, uint32_t, int32_t, int32) { return upb_zzenc_32(s); }
+T(SINT64, v, uint64_t, int64_t, int64) { return upb_zzenc_64(s); }
+T(FIXED32, f, uint32_t, uint32_t, uint32) { return s; }
+T(FIXED64, f, uint64_t, uint64_t, uint64) { return s; }
+T(SFIXED32, f, uint32_t, int32_t, int32) { return (uint32_t)s; }
+T(SFIXED64, f, uint64_t, int64_t, int64) { return (uint64_t)s; }
+T(BOOL, v, uint32_t, bool, _bool) { return (uint32_t)s; }
+T(ENUM, v, uint32_t, int32_t, int32) { return (uint32_t)s; }
+T(DOUBLE, f, uint64_t, double, _double) {
+ union upb_value v;
+ v._double = s;
+ return v.uint64;
+}
+T(FLOAT, f, uint32_t, float, _float) {
+ union upb_value v;
+ v._float = s;
+ return v.uint32;
+}
+#undef VTOWV
+#undef PUT
+#undef T
+
+INLINE size_t upb_get_tag_size(uint32_t fieldnum) {
+ return upb_v_uint64_t_size((uint64_t)fieldnum << 3);
+}
+
+uint8_t *upb_serialize_value(uint8_t *buf, uint8_t *end, upb_field_type_t ft,
+ union upb_value_ptr v, struct upb_status *status)
{
#define CASE(t, member_name) \
case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_ ## t: \
- return upb_put_ ## t(buf, end, *v.member_name, outbuf);
+ return upb_put_ ## t(buf, end, *v.member_name, status);
switch(ft) {
CASE(DOUBLE, _double)
CASE(FLOAT, _float)
@@ -28,7 +204,7 @@ upb_status_t upb_serialize_value(uint8_t *buf, uint8_t *end, upb_field_type_t ft
CASE(SFIXED64, int64)
CASE(BOOL, _bool)
CASE(ENUM, int32)
- default: return UPB_ERROR_ILLEGAL;
+ default: return end;
}
#undef CASE
}
diff --git a/src/upb_serialize.h b/src/upb_serialize.h
index 29c411a..6ce9c81 100644
--- a/src/upb_serialize.h
+++ b/src/upb_serialize.h
@@ -1,19 +1,11 @@
/*
* upb - a minimalist implementation of protocol buffers.
*
- * Implements routines for serializing protobufs. For serializing an entire
- * upb_msg, see the serialization routines in upb_msg.h (which are layered on
- * top of this).
+ * Implements a upb_sink that writes protobuf data to the binary wire format.
*
- * By default this interface does not "check your work." It doesn't pay
- * attention to whether the lengths you give for submessages are correct, or
- * whether your groups are properly balanced, or whether you give each value a
- * tag of the appropriate type. In other words, it is quite possible (easy,
- * even) to use this interface to emit invalid protobufs. We don't want to
- * pay for the runtime checks.
- *
- * The best way to test that you're using the API correctly is to try to parse
- * your output.
+ * For messages that have any submessages, the serializer needs a buffer
+ * containing the submessage sizes, so they can be properly written at the
+ * front of each message. Note that groups do *not* have this requirement.
*
* Copyright (c) 2009 Joshua Haberman. See LICENSE for details.
*/
@@ -22,186 +14,22 @@
#define UPB_SERIALIZE_H_
#include "upb.h"
+#include "upb_sink.h"
#ifdef __cplusplus
extern "C" {
#endif
-/* Functions to write wire values. ********************************************/
-
-/* Puts a varint (wire type: UPB_WIRE_TYPE_VARINT). */
-INLINE uint8_t *upb_put_v_uint64_t(uint8_t *buf, uint8_t *end, uint64_t val,
- struct upb_status *status)
-{
- do {
- uint8_t byte = val & 0x7f;
- val >>= 7;
- if(val) byte |= 0x80;
- if(buf >= end) {
- status->code = UPB_STATUS_NEED_MORE_DATA;
- return end;
- }
- *buf++ = byte;
- } while(val);
- return buf;
-}
-
-/* Puts an unsigned 32-bit varint, verbatim. Never uses the high 64 bits. */
-INLINE uint8_t *upb_put_v_uint32_t(uint8_t *buf, uint8_t *end,
- uint32_t val, struct upb_status *status)
-{
- return upb_put_v_uint64_t(buf, end, val, status);
-}
-
-/* Puts a signed 32-bit varint, first sign-extending to 64-bits. We do this to
- * maintain wire-compatibility with 64-bit signed integers. */
-INLINE uint8_t *upb_put_v_int32_t(uint8_t *buf, uint8_t *end,
- int32_t val, struct upb_status *status)
-{
- return upb_put_v_uint64_t(buf, end, (int64_t)val, status);
-}
-
-INLINE void upb_put32(uint8_t *buf, uint32_t val) {
- buf[0] = val & 0xff;
- buf[1] = (val >> 8) & 0xff;
- buf[2] = (val >> 16) & 0xff;
- buf[3] = (val >> 24);
-}
-
-/* Puts a fixed-length 32-bit integer (wire type: UPB_WIRE_TYPE_32BIT). */
-INLINE uint8_t *upb_put_f_uint32_t(uint8_t *buf, uint8_t *end,
- uint32_t val, struct upb_status *status)
-{
- uint8_t *uint32_end = buf + sizeof(uint32_t);
- if(uint32_end > end) {
- status->code = UPB_STATUS_NEED_MORE_DATA;
- return end;
- }
-#if UPB_UNALIGNED_READS_OK
- *(uint32_t*)buf = val;
-#else
- upb_put32(buf, val);
-#endif
- return uint32_end;
-}
-
-/* Puts a fixed-length 64-bit integer (wire type: UPB_WIRE_TYPE_64BIT). */
-INLINE uint8_t *upb_put_f_uint64_t(uint8_t *buf, uint8_t *end,
- uint64_t val, struct upb_status *status)
-{
- uint8_t *uint64_end = buf + sizeof(uint64_t);
- if(uint64_end > end) {
- status->code = UPB_STATUS_NEED_MORE_DATA;
- return end;
- }
-#if UPB_UNALIGNED_READS_OK
- *(uint64_t*)buf = val;
-#else
- upb_put32(buf, (uint32_t)val);
- upb_put32(buf, (uint32_t)(val >> 32));
-#endif
- return uint64_end;
-}
-
-INLINE size_t upb_v_uint64_t_size(uint64_t val) {
-#ifdef __GNUC__
- int high_bit = 63 - __builtin_clzll(val); /* 0-based, undef if val == 0. */
-#else
- int high_bit = 0;
- uint64_t tmp = val;
- while(tmp >>= 1) high_bit++;
-#endif
- return val == 0 ? 1 : high_bit / 7 + 1;
-}
-
-INLINE size_t upb_v_int32_t_size(int32_t val) {
- /* v_uint32's are sign-extended to maintain wire compatibility with int64s. */
- return upb_v_uint64_t_size((int64_t)val);
-}
-INLINE size_t upb_v_uint32_t_size(uint32_t val) {
- return upb_v_uint64_t_size(val);
-}
-INLINE size_t upb_f_uint64_t_size(uint64_t val) {
- (void)val; /* Length is independent of value. */
- return sizeof(uint64_t);
-}
-INLINE size_t upb_f_uint32_t_size(uint32_t val) {
- (void)val; /* Length is independent of value. */
- return sizeof(uint32_t);
-}
-
-/* Functions to write .proto values. ******************************************/
-
-/* Performs zig-zag encoding, which is used by sint32 and sint64. */
-INLINE uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); }
-INLINE uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); }
-
-/* Use macros to define a set of two functions for each .proto type:
- *
- * // Converts and writes a .proto value into buf. "end" indicates the end
- * // of the current available buffer (if the buffer does not contain enough
- * // space UPB_STATUS_NEED_MORE_DATA is returned). On success, *outbuf will
- * // point one past the data that was written.
- * uint8_t *upb_put_INT32(uint8_t *buf, uint8_t *end, int32_t val,
- * struct upb_status *status);
- *
- * // Returns the number of bytes required to serialize val.
- * size_t upb_get_INT32_size(int32_t val);
- *
- * // Given a .proto value s (source) convert it to a wire value.
- * uint32_t upb_vtowv_INT32(int32_t s);
- */
-
-#define VTOWV(type, wire_t, val_t) \
- INLINE wire_t upb_vtowv_ ## type(val_t s)
-
-#define PUT(type, v_or_f, wire_t, val_t, member_name) \
- INLINE uint8_t *upb_put_ ## type(uint8_t *buf, uint8_t *end, val_t val, \
- struct upb_status *status) { \
- wire_t tmp = upb_vtowv_ ## type(val); \
- return upb_put_ ## v_or_f ## _ ## wire_t(buf, end, tmp, status); \
- }
-
-#define T(type, v_or_f, wire_t, val_t, member_name) \
- INLINE size_t upb_get_ ## type ## _size(val_t val) { \
- return upb_ ## v_or_f ## _ ## wire_t ## _size(val); \
- } \
- VTOWV(type, wire_t, val_t); /* prototype for PUT below */ \
- PUT(type, v_or_f, wire_t, val_t, member_name) \
- VTOWV(type, wire_t, val_t)
+size_t upb_get_value_size(union upb_value v, struct upb_fielddef *f);
-T(INT32, v, uint32_t, int32_t, int32) { return (uint32_t)s; }
-T(INT64, v, uint64_t, int64_t, int64) { return (uint64_t)s; }
-T(UINT32, v, uint32_t, uint32_t, uint32) { return s; }
-T(UINT64, v, uint64_t, uint64_t, uint64) { return s; }
-T(SINT32, v, uint32_t, int32_t, int32) { return upb_zzenc_32(s); }
-T(SINT64, v, uint64_t, int64_t, int64) { return upb_zzenc_64(s); }
-T(FIXED32, f, uint32_t, uint32_t, uint32) { return s; }
-T(FIXED64, f, uint64_t, uint64_t, uint64) { return s; }
-T(SFIXED32, f, uint32_t, int32_t, int32) { return (uint32_t)s; }
-T(SFIXED64, f, uint64_t, int64_t, int64) { return (uint64_t)s; }
-T(BOOL, v, uint32_t, bool, _bool) { return (uint32_t)s; }
-T(ENUM, v, uint32_t, int32_t, int32) { return (uint32_t)s; }
-T(DOUBLE, f, uint64_t, double, _double) {
- union upb_value v;
- v._double = s;
- return v.uint64;
-}
-T(FLOAT, f, uint32_t, float, _float) {
- union upb_value v;
- v._float = s;
- return v.uint32;
-}
-#undef VTOWV
-#undef PUT
-#undef T
+struct upb_serializer;
+typedef struct upb_serializer upb_serializer;
-INLINE size_t upb_get_tag_size(uint32_t fieldnum) {
- return upb_v_uint64_t_size((uint64_t)fieldnum << 3);
-}
+upb_serializer *upb_serializer_new();
+void upb_serializer_free(upb_serializer *s);
-uint8_t *upb_serialize_value(uint8_t *buf, uint8_t *end, upb_field_type_t ft,
- union upb_value_ptr v, struct upb_status *status);
+void upb_serializer_reset(upb_serializer *s, uint32_t *sizes);
+upb_sink *upb_serializer_sink(upb_serializer *s);
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/upb_sink.h b/src/upb_sink.h
index 3400092..2055688 100644
--- a/src/upb_sink.h
+++ b/src/upb_sink.h
@@ -38,6 +38,8 @@
extern "C" {
#endif
+struct upb_fielddef;
+
// Each of the upb_sink callbacks returns a status of this type.
typedef enum {
// The normal case, where the consumer wants to continue consuming.
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback