diff options
Diffstat (limited to 'stream')
-rw-r--r-- | stream/upb_decoder.c | 441 | ||||
-rw-r--r-- | stream/upb_decoder.h | 86 | ||||
-rw-r--r-- | stream/upb_encoder.c | 420 | ||||
-rw-r--r-- | stream/upb_encoder.h | 56 | ||||
-rw-r--r-- | stream/upb_stdio.c | 104 | ||||
-rw-r--r-- | stream/upb_stdio.h | 42 | ||||
-rw-r--r-- | stream/upb_strstream.c | 65 | ||||
-rw-r--r-- | stream/upb_strstream.h | 65 | ||||
-rw-r--r-- | stream/upb_textprinter.c | 143 | ||||
-rw-r--r-- | stream/upb_textprinter.h | 29 |
10 files changed, 0 insertions, 1451 deletions
diff --git a/stream/upb_decoder.c b/stream/upb_decoder.c deleted file mode 100644 index 4a43c4b..0000000 --- a/stream/upb_decoder.c +++ /dev/null @@ -1,441 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2008-2009 Joshua Haberman. See LICENSE for details. - */ - -#include "upb_decoder.h" - -#include <inttypes.h> -#include <stddef.h> -#include <stdlib.h> -#include "upb_def.h" - -/* Pure Decoding **************************************************************/ - -// The key fast-path varint-decoding routine. Here we can assume we have at -// least UPB_MAX_VARINT_ENCODED_SIZE bytes available. There are a lot of -// possibilities for optimization/experimentation here. - -#ifdef USE_SSE_VARINT_DECODING -#include <emmintrin.h> - -// This works, but is empirically slower than the branchy version below. Why? -// Most varints are very short. Next step: use branches for 1/2-byte varints, -// but use the SSE version for 3-10 byte varints. -INLINE bool upb_decode_varint_fast(const char **ptr, uint64_t *val, upb_status *s) { - const char *p = *ptr; - __m128i val128 = _mm_loadu_si128((void*)p); - unsigned int continuation_bits = _mm_movemask_epi8(val128); - unsigned int bsr_val = ~continuation_bits; - int varint_length = __builtin_ffs(bsr_val); - if (varint_length > 10) { - upb_seterr(s, UPB_ERROR, "Unterminated varint"); - return false; - } - - uint16_t twob; - memcpy(&twob, p, 2); - twob &= 0x7f7f; - twob = ((twob & 0xff00) >> 1) | (twob & 0xff); - - uint64_t eightb; - memcpy(&eightb, p + 2, 8); - eightb &= 0x7f7f7f7f7f7f7f7f; - eightb = ((eightb & 0xff00ff00ff00ff00) >> 1) | (eightb & 0x00ff00ff00ff00ff); - eightb = ((eightb & 0xffff0000ffff0000) >> 2) | (eightb & 0x0000ffff0000ffff); - eightb = ((eightb & 0xffffffff00000000) >> 4) | (eightb & 0x00000000ffffffff); - - uint64_t all_bits = twob | (eightb << 14); - int varint_bits = varint_length * 7; - uint64_t mask = varint_bits == 70 ? (uint64_t)-1 : (1ULL << (varint_bits)) - 1; - *val = all_bits & mask; - *ptr = p + varint_length; - return true; -} - -#else - -INLINE bool upb_decode_varint_fast(const char **ptr, uint64_t *val, upb_status *s) { - const char *p = *ptr; - uint32_t low, high = 0; - uint32_t b; - b = *(p++); low = (b & 0x7f) ; if(!(b & 0x80)) goto done; - b = *(p++); low |= (b & 0x7f) << 7; if(!(b & 0x80)) goto done; - b = *(p++); low |= (b & 0x7f) << 14; if(!(b & 0x80)) goto done; - b = *(p++); low |= (b & 0x7f) << 21; if(!(b & 0x80)) goto done; - b = *(p++); low |= (b & 0x7f) << 28; - high = (b & 0x7f) >> 4; if(!(b & 0x80)) goto done; - b = *(p++); high |= (b & 0x7f) << 3; if(!(b & 0x80)) goto done; - b = *(p++); high |= (b & 0x7f) << 10; if(!(b & 0x80)) goto done; - b = *(p++); high |= (b & 0x7f) << 17; if(!(b & 0x80)) goto done; - b = *(p++); high |= (b & 0x7f) << 24; if(!(b & 0x80)) goto done; - b = *(p++); high |= (b & 0x7f) << 31; if(!(b & 0x80)) goto done; - - upb_seterr(s, UPB_ERROR, "Unterminated varint"); - return false; - -done: - *val = ((uint64_t)high << 32) | low; - *ptr = p; - return true; -} - -#endif - - -/* Decoding/Buffering of individual values ************************************/ - -// Performs zig-zag decoding, which is used by sint32 and sint64. -INLINE int32_t upb_zzdec_32(uint32_t n) { return (n >> 1) ^ -(int32_t)(n & 1); } -INLINE int64_t upb_zzdec_64(uint64_t n) { return (n >> 1) ^ -(int64_t)(n & 1); } - -typedef struct { - // Our current position in the data buffer. - const char *ptr; - - // End of this submessage, relative to *ptr. - const char *submsg_end; - - // Number of bytes available at ptr. - size_t len; - - // Msgdef for the current level. - upb_msgdef *msgdef; -} upb_dstate; - -// Constant used to signal that the submessage is a group and therefore we -// don't know its end offset. This cannot be the offset of a real submessage -// end because it takes at least one byte to begin a submessage. -#define UPB_GROUP_END_OFFSET 0 -#define UPB_MAX_VARINT_ENCODED_SIZE 10 - -INLINE void upb_dstate_advance(upb_dstate *s, size_t len) { - s->ptr += len; - s->len -= len; -} - -INLINE void upb_dstate_setmsgend(upb_decoder *d, upb_dstate *s) { - s->submsg_end = (d->top->end_offset == UPB_GROUP_END_OFFSET) ? - (void*)UINTPTR_MAX : - upb_string_getrobuf(d->buf) + (d->top->end_offset - d->buf_stream_offset); -} - -static upb_flow_t upb_pop(upb_decoder *d, upb_dstate *s); - -// Called only from the slow path, this function copies the next "len" bytes -// from the stream to "data", adjusting the dstate appropriately. -static bool upb_getbuf(upb_decoder *d, void *data, size_t bytes_wanted, - upb_dstate *s) { - while (1) { - size_t to_copy = UPB_MIN(bytes_wanted, s->len); - memcpy(data, s->ptr, to_copy); - upb_dstate_advance(s, to_copy); - bytes_wanted -= to_copy; - if (bytes_wanted == 0) { - upb_dstate_setmsgend(d, s); - return true; - } - - // Get next buffer. - if (d->buf) d->buf_stream_offset += upb_string_len(d->buf); - upb_string_recycle(&d->buf); - if (!upb_bytesrc_getstr(d->bytesrc, d->buf, d->status)) return false; - s->ptr = upb_string_getrobuf(d->buf); - s->len = upb_string_len(d->buf); - } -} - -// We use this path when we don't have UPB_MAX_VARINT_ENCODED_SIZE contiguous -// bytes available in our current buffer. We don't inline this because we -// accept that it will be slow and we don't want to pay for two copies of it. -static bool upb_decode_varint_slow(upb_decoder *d, upb_dstate *s, - upb_value *val) { - char byte = 0x80; - uint64_t val64 = 0; - int bitpos; - for(bitpos = 0; - bitpos < 70 && (byte & 0x80) && upb_getbuf(d, &byte, 1, s); - bitpos += 7) - val64 |= ((uint64_t)byte & 0x7F) << bitpos; - - if(bitpos == 70) { - upb_seterr(d->status, UPB_ERROR, - "Varint was unterminated after 10 bytes.\n"); - return false; - } else if (d->status->code == UPB_EOF && bitpos == 0) { - // Regular EOF. - return false; - } else if (d->status->code == UPB_EOF && (byte & 0x80)) { - upb_seterr(d->status, UPB_ERROR, - "Provided data ended in the middle of a varint.\n"); - return false; - } else { - // Success. - upb_value_setraw(val, val64); - return true; - } -} - -typedef struct { - upb_wire_type_t wire_type; - upb_field_number_t field_number; -} upb_tag; - -INLINE bool upb_decode_tag(upb_decoder *d, upb_dstate *s, upb_tag *tag) { - const char *p = s->ptr; - uint32_t tag_int; - upb_value val; - // Nearly all tag varints will be either 1 byte (1-16) or 2 bytes (17-2048). - if (s->len < 2) goto slow; // unlikely. - tag_int = *p & 0x7f; - if ((*(p++) & 0x80) == 0) goto done; // predictable if fields are in order - tag_int |= (*p & 0x7f) << 7; - if ((*(p++) & 0x80) == 0) goto done; // likely -slow: - // Decode a full varint starting over from ptr. - if (!upb_decode_varint_slow(d, s, &val)) return false; - tag_int = upb_value_getint64(val); - p = s->ptr; // Trick the next line into not overwriting us. -done: - upb_dstate_advance(s, p - s->ptr); - tag->wire_type = (upb_wire_type_t)(tag_int & 0x07); - tag->field_number = tag_int >> 3; - return true; -} - -INLINE bool upb_decode_varint(upb_decoder *d, upb_dstate *s, upb_value *val) { - if (s->len >= 16) { - // Common (fast) case. - uint64_t val64; - const char *p = s->ptr; - if (!upb_decode_varint_fast(&p, &val64, d->status)) return false; - upb_dstate_advance(s, p - s->ptr); - upb_value_setraw(val, val64); - return true; - } else { - return upb_decode_varint_slow(d, s, val); - } -} - -INLINE bool upb_decode_fixed(upb_decoder *d, upb_wire_type_t wt, - upb_dstate *s, upb_value *val) { - static const char table[] = {0, 8, 0, 0, 0, 4}; - size_t bytes = table[wt]; - if (s->len >= bytes) { - // Common (fast) case. - memcpy(val, s->ptr, bytes); - upb_dstate_advance(s, bytes); - } else { - if (!upb_getbuf(d, val, bytes, s)) return false; - } - return true; -} - -// "val" initially holds the length of the string, this is replaced by the -// contents of the string. -INLINE bool upb_decode_string(upb_decoder *d, upb_value *val, upb_string **str, - upb_dstate *s) { - upb_string_recycle(str); - uint32_t strlen = upb_value_getint32(*val); - if (s->len >= strlen) { - // Common (fast) case. - upb_string_substr(*str, d->buf, s->ptr - upb_string_getrobuf(d->buf), strlen); - upb_dstate_advance(s, strlen); - } else { - if (!upb_getbuf(d, upb_string_getrwbuf(*str, strlen), strlen, s)) - return false; - } - upb_value_setstr(val, *str); - return true; -} - - -/* The main decoding loop *****************************************************/ - -extern upb_wire_type_t upb_expected_wire_types[]; -// Returns true if wt is the correct on-the-wire type for ft. -INLINE bool upb_check_type(upb_wire_type_t wt, upb_fieldtype_t ft) { - // This doesn't currently support packed arrays. - return upb_types[ft].native_wire_type == wt; -} - -static upb_flow_t upb_push(upb_decoder *d, upb_dstate *s, upb_fielddef *f, - upb_value submsg_len, upb_fieldtype_t type) { - d->top++; - if(d->top >= d->limit) { - upb_seterr(d->status, UPB_ERROR, "Nesting too deep."); - return UPB_ERROR; - } - d->top->end_offset = (type == UPB_TYPE(GROUP)) ? - UPB_GROUP_END_OFFSET : - d->buf_stream_offset + (s->ptr - upb_string_getrobuf(d->buf)) + - upb_value_getint32(submsg_len); - d->top->msgdef = upb_downcast_msgdef(f->def); - upb_dstate_setmsgend(d, s); - return upb_dispatch_startsubmsg(&d->dispatcher, f); -} - -static upb_flow_t upb_pop(upb_decoder *d, upb_dstate *s) { - d->top--; - upb_dstate_setmsgend(d, s); - return upb_dispatch_endsubmsg(&d->dispatcher); -} - -void upb_decoder_run(upb_src *src, upb_status *status) { - upb_decoder *d = (upb_decoder*)src; - d->status = status; - // We put our dstate on the stack so the compiler knows they can't be changed - // by external code (like when we dispatch a callback). We must be sure not - // to let its address escape this source file. - upb_dstate state = {NULL, (void*)0x1, 0, d->top->msgdef}; - -// TODO: handle UPB_SKIPSUBMSG -#define CHECK_FLOW(expr) if ((expr) == UPB_BREAK) { assert(!upb_ok(status)); goto err; } -#define CHECK(expr) if (!expr) { assert(!upb_ok(status)); goto err; } - - CHECK_FLOW(upb_dispatch_startmsg(&d->dispatcher)); - - // Main loop: executed once per tag/field pair. - while(1) { - // Check for end-of-submessage. - while (state.ptr >= state.submsg_end) { - if (state.ptr > state.submsg_end) { - upb_seterr(d->status, UPB_ERROR, "Bad submessage end."); - goto err; - } - CHECK_FLOW(upb_pop(d, &state)); - } - - // Parse/handle tag. - upb_tag tag; - if (!upb_decode_tag(d, &state, &tag)) { - if (status->code == UPB_EOF && d->top == d->stack) { - // Normal end-of-file. - upb_clearerr(status); - CHECK_FLOW(upb_dispatch_endmsg(&d->dispatcher)); - return; - } else { - if (status->code == UPB_EOF) { - upb_seterr(status, UPB_ERROR, - "Input ended in the middle of a submessage."); - } - goto err; - } - } - - // Decode wire data. Hopefully this branch will predict pretty well - // since most types will read a varint here. - upb_value val; - switch (tag.wire_type) { - case UPB_WIRE_TYPE_START_GROUP: - break; // Nothing to do now, below we will push appropriately. - case UPB_WIRE_TYPE_END_GROUP: - if(d->top->end_offset != UPB_GROUP_END_OFFSET) { - upb_seterr(status, UPB_ERROR, "Unexpected END_GROUP tag."); - goto err; - } - CHECK_FLOW(upb_pop(d, &state)); - continue; // We have no value to dispatch. - case UPB_WIRE_TYPE_VARINT: - case UPB_WIRE_TYPE_DELIMITED: - // For the delimited case we are parsing the length. - CHECK(upb_decode_varint(d, &state, &val)); - break; - case UPB_WIRE_TYPE_32BIT: - case UPB_WIRE_TYPE_64BIT: - CHECK(upb_decode_fixed(d, tag.wire_type, &state, &val)); - break; - } - - // Look up field by tag number. - upb_fielddef *f = upb_msgdef_itof(d->top->msgdef, tag.field_number); - - if (!f) { - if (tag.wire_type == UPB_WIRE_TYPE_DELIMITED) - CHECK(upb_decode_string(d, &val, &d->tmp, &state)); - CHECK_FLOW(upb_dispatch_unknownval(&d->dispatcher, tag.field_number, val)); - } else if (!upb_check_type(tag.wire_type, f->type)) { - // TODO: put more details in this error msg. - upb_seterr(status, UPB_ERROR, "Field had incorrect type, name: " UPB_STRFMT, UPB_STRARG(f->name)); - upb_printerr(status); - *(int*)0 = 0; - goto err; - } - - // Perform any further massaging of the data now that we have the fielddef. - // Now we can distinguish strings from submessages, and we know about - // zig-zag-encoded types. - // TODO: handle packed encoding. - // TODO: if we were being paranoid, we could check for 32-bit-varint types - // that the top 32 bits all match the highest bit of the low 32 bits. - // If this is not true we are losing data. But the main protobuf library - // doesn't check this, and it would slow us down, so pass for now. - switch (f->type) { - case UPB_TYPE(MESSAGE): - case UPB_TYPE(GROUP): - CHECK_FLOW(upb_push(d, &state, f, val, f->type)); - continue; // We have no value to dispatch. - case UPB_TYPE(STRING): - case UPB_TYPE(BYTES): - CHECK(upb_decode_string(d, &val, &d->tmp, &state)); - break; - case UPB_TYPE(SINT32): - upb_value_setint32(&val, upb_zzdec_32(upb_value_getint32(val))); - break; - case UPB_TYPE(SINT64): - upb_value_setint64(&val, upb_zzdec_64(upb_value_getint64(val))); - break; - default: -#ifndef NDEBUG - val.type = upb_types[f->type].inmemory_type; -#endif - break; // Other types need no further processing at this point. - } - CHECK_FLOW(upb_dispatch_value(&d->dispatcher, f, val)); - } - -err: - if (upb_ok(status)) { - upb_seterr(status, UPB_ERROR, "Callback returned UPB_BREAK"); - } -} - -void upb_decoder_sethandlers(upb_src *src, upb_handlers *handlers) { - upb_decoder *d = (upb_decoder*)src; - upb_dispatcher_reset(&d->dispatcher, handlers, false); - d->top = d->stack; - d->buf_stream_offset = 0; - d->top->msgdef = d->toplevel_msgdef; - // The top-level message is not delimited (we can keep receiving data for it - // indefinitely), so we treat it like a group. - d->top->end_offset = 0; -} - -void upb_decoder_init(upb_decoder *d, upb_msgdef *msgdef) { - static upb_src_vtbl vtbl = { - &upb_decoder_sethandlers, - &upb_decoder_run, - }; - upb_src_init(&d->src, &vtbl); - upb_dispatcher_init(&d->dispatcher); - d->toplevel_msgdef = msgdef; - d->limit = &d->stack[UPB_MAX_NESTING]; - d->buf = NULL; - d->tmp = NULL; -} - -void upb_decoder_reset(upb_decoder *d, upb_bytesrc *bytesrc) { - d->bytesrc = bytesrc; - d->top = &d->stack[0]; - d->top->msgdef = d->toplevel_msgdef; - // Never want to end top-level message, so treat it like a group. - d->top->end_offset = UPB_GROUP_END_OFFSET; -} - -void upb_decoder_uninit(upb_decoder *d) { - upb_string_unref(d->buf); - upb_string_unref(d->tmp); -} - -upb_src *upb_decoder_src(upb_decoder *d) { return &d->src; } diff --git a/stream/upb_decoder.h b/stream/upb_decoder.h deleted file mode 100644 index 1c62753..0000000 --- a/stream/upb_decoder.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * upb_decoder implements a high performance, streaming decoder for protobuf - * data that works by implementing upb_src and getting its data from a - * upb_bytesrc. - * - * The decoder does not currently support non-blocking I/O, in the sense that - * if the bytesrc returns UPB_STATUS_TRYAGAIN it is not possible to resume the - * decoder when data becomes available again. Support for this could be added, - * but it would add complexity and perhaps cost efficiency also. - * - * Copyright (c) 2009-2010 Joshua Haberman. See LICENSE for details. - */ - -#ifndef UPB_DECODER_H_ -#define UPB_DECODER_H_ - -#include <stdbool.h> -#include <stdint.h> -#include "upb_def.h" -#include "upb_stream.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* upb_decoder *****************************************************************/ - -// The decoder keeps a stack with one entry per level of recursion. -// upb_decoder_frame is one frame of that stack. -typedef struct { - upb_msgdef *msgdef; - size_t end_offset; // For groups, 0. -} upb_decoder_frame; - -struct _upb_decoder { - // Immutable state of the decoder. - upb_src src; - upb_dispatcher dispatcher; - upb_bytesrc *bytesrc; - upb_msgdef *toplevel_msgdef; - upb_decoder_frame stack[UPB_MAX_NESTING]; - - // Mutable state of the decoder. - - // Where we will store any errors that occur. - upb_status *status; - - // Stack entries store the offset where the submsg ends (for groups, 0). - upb_decoder_frame *top, *limit; - - // Current input buffer. - upb_string *buf; - - // Temporary string for passing to callbacks. - upb_string *tmp; - - // The offset within the overall stream represented by the *beginning* of buf. - size_t buf_stream_offset; -}; - -// A upb_decoder decodes the binary protocol buffer format, writing the data it -// decodes to a upb_sink. -struct _upb_decoder; -typedef struct _upb_decoder upb_decoder; - -// Allocates and frees a upb_decoder, respectively. -void upb_decoder_init(upb_decoder *d, upb_msgdef *md); -void upb_decoder_uninit(upb_decoder *d); - -// Resets the internal state of an already-allocated decoder. This puts it in a -// state where it has not seen any data, and expects the next data to be from -// the beginning of a new protobuf. Parsers must be reset before they can be -// used. A decoder can be reset multiple times. -void upb_decoder_reset(upb_decoder *d, upb_bytesrc *bytesrc); - -// Returns a upb_src pointer by which the decoder can be used. The returned -// upb_src is invalidated by upb_decoder_reset() or upb_decoder_free(). -upb_src *upb_decoder_src(upb_decoder *d); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_DECODER_H_ */ diff --git a/stream/upb_encoder.c b/stream/upb_encoder.c deleted file mode 100644 index 304a423..0000000 --- a/stream/upb_encoder.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. - */ - -#include "upb_encoder.h" - -#include <stdlib.h> -#include "descriptor.h" - -/* Functions for calculating sizes of wire values. ****************************/ - -static 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; -} - -static 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); -} -static size_t upb_v_uint32_t_size(uint32_t val) { - return upb_v_uint64_t_size(val); -} -static size_t upb_f_uint64_t_size(uint64_t val) { - (void)val; // Length is independent of value. - return sizeof(uint64_t); -} -static 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. ********************************************/ - -// Since we know in advance the longest that the value could be, we always make -// sure that our buffer is long enough. This saves us from having to perform -// bounds checks. - -// Puts a varint (wire type: UPB_WIRE_TYPE_VARINT). -static uint8_t *upb_put_v_uint64_t(uint8_t *buf, uint64_t val) -{ - do { - uint8_t byte = val & 0x7f; - val >>= 7; - if(val) byte |= 0x80; - *buf++ = byte; - } while(val); - return buf; -} - -// Puts an unsigned 32-bit varint, verbatim. Never uses the high 64 bits. -static uint8_t *upb_put_v_uint32_t(uint8_t *buf, uint32_t val) -{ - return upb_put_v_uint64_t(buf, val); -} - -// Puts a signed 32-bit varint, first sign-extending to 64-bits. We do this to -// maintain wire-compatibility with 64-bit signed integers. -static uint8_t *upb_put_v_int32_t(uint8_t *buf, int32_t val) -{ - return upb_put_v_uint64_t(buf, (int64_t)val); -} - -static 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). -static uint8_t *upb_put_f_uint32_t(uint8_t *buf, uint32_t val) -{ - uint8_t *uint32_end = buf + sizeof(uint32_t); -#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). -static uint8_t *upb_put_f_uint64_t(uint8_t *buf, uint64_t val) -{ - uint8_t *uint64_end = buf + sizeof(uint64_t); -#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 and calculate sizes for .proto values. ******************/ - -// Performs zig-zag encoding, which is used by sint32 and sint64. -static uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); } -static 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, int32_t val); - * - * // Returns the number of bytes required to encode 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) \ - static wire_t upb_vtowv_ ## type(val_t s) - -#define PUT(type, v_or_f, wire_t, val_t, member_name) \ - static uint8_t *upb_put_ ## type(uint8_t *buf, val_t val) { \ - wire_t tmp = upb_vtowv_ ## type(val); \ - return upb_put_ ## v_or_f ## _ ## wire_t(buf, tmp); \ - } - -#define T(type, v_or_f, wire_t, val_t, member_name) \ - static 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, int32_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) { - upb_value v; - v._double = s; - return v.uint64; -} -T(FLOAT, f, uint32_t, float, _float) { - upb_value v; - v._float = s; - return v.uint32; -} -#undef VTOWV -#undef PUT -#undef T - -static uint8_t *upb_encode_value(uint8_t *buf, upb_field_type_t ft, upb_value v) -{ -#define CASE(t, member_name) \ - case UPB_TYPE(t): return upb_put_ ## t(buf, v.member_name); - switch(ft) { - CASE(DOUBLE, _double) - CASE(FLOAT, _float) - CASE(INT32, int32) - CASE(INT64, int64) - CASE(UINT32, uint32) - CASE(UINT64, uint64) - CASE(SINT32, int32) - CASE(SINT64, int64) - CASE(FIXED32, uint32) - CASE(FIXED64, uint64) - CASE(SFIXED32, int32) - CASE(SFIXED64, int64) - CASE(BOOL, _bool) - CASE(ENUM, int32) - default: assert(false); return buf; - } -#undef CASE -} - -static uint32_t _upb_get_value_size(upb_field_type_t ft, upb_value v) -{ -#define CASE(t, member_name) \ - case UPB_TYPE(t): return upb_get_ ## t ## _size(v.member_name); - switch(ft) { - CASE(DOUBLE, _double) - CASE(FLOAT, _float) - CASE(INT32, int32) - CASE(INT64, int64) - CASE(UINT32, uint32) - CASE(UINT64, uint64) - CASE(SINT32, int32) - CASE(SINT64, int64) - CASE(FIXED32, uint32) - CASE(FIXED64, uint64) - CASE(SFIXED32, int32) - CASE(SFIXED64, int64) - CASE(BOOL, _bool) - CASE(ENUM, int32) - default: assert(false); return 0; - } -#undef CASE -} - -static uint8_t *_upb_put_tag(uint8_t *buf, upb_field_number_t num, - upb_wire_type_t wt) -{ - return upb_put_UINT32(buf, wt | (num << 3)); -} - -static uint32_t _upb_get_tag_size(upb_field_number_t num) -{ - return upb_get_UINT32_size(num << 3); -} - - -/* upb_sizebuilder ************************************************************/ - -struct upb_sizebuilder { - // Accumulating size for the current level. - uint32_t size; - - // Stack of sizes for our current nesting. - uint32_t stack[UPB_MAX_NESTING], *top; - - // Vector of sizes. - uint32_t *sizes; - int sizes_len; - int sizes_size; - - upb_status status; -}; - -// upb_sink callbacks. -static upb_sink_status _upb_sizebuilder_valuecb(upb_sink *sink, upb_fielddef *f, - upb_value val, - upb_status *status) -{ - (void)status; - upb_sizebuilder *sb = (upb_sizebuilder*)sink; - uint32_t size = 0; - size += _upb_get_tag_size(f->number); - size += _upb_get_value_size(f->type, val); - sb->size += size; - return UPB_SINK_CONTINUE; -} - -static upb_sink_status _upb_sizebuilder_strcb(upb_sink *sink, upb_fielddef *f, - upb_strptr str, - int32_t start, uint32_t end, - upb_status *status) -{ - (void)status; - (void)str; // String data itself is not used. - upb_sizebuilder *sb = (upb_sizebuilder*)sink; - if(start >= 0) { - uint32_t size = 0; - size += _upb_get_tag_size(f->number); - size += upb_get_UINT32_size(end - start); - sb->size += size; - } - return UPB_SINK_CONTINUE; -} - -static upb_sink_status _upb_sizebuilder_startcb(upb_sink *sink, upb_fielddef *f, - upb_status *status) -{ - (void)status; - (void)f; // Unused (we calculate tag size and delimiter in endcb). - upb_sizebuilder *sb = (upb_sizebuilder*)sink; - if(f->type == UPB_TYPE(MESSAGE)) { - *sb->top = sb->size; - sb->top++; - sb->size = 0; - } else { - assert(f->type == UPB_TYPE(GROUP)); - sb->size += _upb_get_tag_size(f->number); - } - return UPB_SINK_CONTINUE; -} - -static upb_sink_status _upb_sizebuilder_endcb(upb_sink *sink, upb_fielddef *f, - upb_status *status) -{ - (void)status; - upb_sizebuilder *sb = (upb_sizebuilder*)sink; - if(f->type == UPB_TYPE(MESSAGE)) { - sb->top--; - if(sb->sizes_len == sb->sizes_size) { - sb->sizes_size *= 2; - sb->sizes = realloc(sb->sizes, sb->sizes_size * sizeof(*sb->sizes)); - } - uint32_t child_size = sb->size; - uint32_t parent_size = *sb->top; - sb->sizes[sb->sizes_len++] = child_size; - // The size according to the parent includes the tag size and delimiter of - // the submessage. - parent_size += upb_get_UINT32_size(child_size); - parent_size += _upb_get_tag_size(f->number); - // Include size accumulated in parent before child began. - sb->size = child_size + parent_size; - } else { - assert(f->type == UPB_TYPE(GROUP)); - // As an optimization, we could just add this number twice in startcb, to - // avoid having to recalculate it. - sb->size += _upb_get_tag_size(f->number); - } - return UPB_SINK_CONTINUE; -} - -upb_sink_callbacks _upb_sizebuilder_sink_vtbl = { - _upb_sizebuilder_valuecb, - _upb_sizebuilder_strcb, - _upb_sizebuilder_startcb, - _upb_sizebuilder_endcb -}; - - -/* upb_sink callbacks *********************************************************/ - -struct upb_encoder { - upb_sink base; - //upb_bytesink *bytesink; - uint32_t *sizes; - int size_offset; -}; - - -// Within one callback we may need to encode up to two separate values. -#define UPB_ENCODER_BUFSIZE (UPB_MAX_ENCODED_SIZE * 2) - -static upb_sink_status _upb_encoder_push_buf(upb_encoder *s, const uint8_t *buf, - size_t len, upb_status *status) -{ - // TODO: conjure a upb_strptr that points to buf. - //upb_strptr ptr; - (void)s; - (void)buf; - (void)status; - size_t written = 5;// = upb_bytesink_onbytes(s->bytesink, ptr); - if(written < len) { - // TODO: mark to skip "written" bytes next time. - return UPB_SINK_STOP; - } else { - return UPB_SINK_CONTINUE; - } -} - -static upb_sink_status _upb_encoder_valuecb(upb_sink *sink, upb_fielddef *f, - upb_value val, upb_status *status) -{ - upb_encoder *s = (upb_encoder*)sink; - uint8_t buf[UPB_ENCODER_BUFSIZE], *ptr = buf; - upb_wire_type_t wt = upb_types[f->type].expected_wire_type; - // TODO: handle packed encoding. - ptr = _upb_put_tag(ptr, f->number, wt); - ptr = upb_encode_value(ptr, f->type, val); - return _upb_encoder_push_buf(s, buf, ptr - buf, status); -} - -static upb_sink_status _upb_encoder_strcb(upb_sink *sink, upb_fielddef *f, - upb_strptr str, - int32_t start, uint32_t end, - upb_status *status) -{ - upb_encoder *s = (upb_encoder*)sink; - uint8_t buf[UPB_ENCODER_BUFSIZE], *ptr = buf; - if(start >= 0) { - ptr = _upb_put_tag(ptr, f->number, UPB_WIRE_TYPE_DELIMITED); - ptr = upb_put_UINT32(ptr, end - start); - } - // TODO: properly handle partially consumed strings and partially supplied - // strings. - _upb_encoder_push_buf(s, buf, ptr - buf, status); - return _upb_encoder_push_buf(s, (uint8_t*)upb_string_getrobuf(str), end - start, status); -} - -static upb_sink_status _upb_encoder_startcb(upb_sink *sink, upb_fielddef *f, - upb_status *status) -{ - upb_encoder *s = (upb_encoder*)sink; - uint8_t buf[UPB_ENCODER_BUFSIZE], *ptr = buf; - if(f->type == UPB_TYPE(GROUP)) { - ptr = _upb_put_tag(ptr, f->number, UPB_WIRE_TYPE_START_GROUP); - } else { - ptr = _upb_put_tag(ptr, f->number, UPB_WIRE_TYPE_DELIMITED); - ptr = upb_put_UINT32(ptr, s->sizes[--s->size_offset]); - } - return _upb_encoder_push_buf(s, buf, ptr - buf, status); -} - -static upb_sink_status _upb_encoder_endcb(upb_sink *sink, upb_fielddef *f, - upb_status *status) -{ - upb_encoder *s = (upb_encoder*)sink; - uint8_t buf[UPB_ENCODER_BUFSIZE], *ptr = buf; - if(f->type != UPB_TYPE(GROUP)) return UPB_SINK_CONTINUE; - ptr = _upb_put_tag(ptr, f->number, UPB_WIRE_TYPE_END_GROUP); - return _upb_encoder_push_buf(s, buf, ptr - buf, status); -} - -upb_sink_callbacks _upb_encoder_sink_vtbl = { - _upb_encoder_valuecb, - _upb_encoder_strcb, - _upb_encoder_startcb, - _upb_encoder_endcb -}; - diff --git a/stream/upb_encoder.h b/stream/upb_encoder.h deleted file mode 100644 index e879b0b..0000000 --- a/stream/upb_encoder.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Implements a upb_sink that writes protobuf data to the binary wire format. - * - * For messages that have any submessages, the encoder 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-2010 Joshua Haberman. See LICENSE for details. - */ - -#ifndef UPB_ENCODER_H_ -#define UPB_ENCODER_H_ - -#include "upb.h" -#include "upb_srcsink.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* upb_encoder ****************************************************************/ - -// A upb_encoder is a upb_sink that emits data to a upb_bytesink in the protocol -// buffer binary wire format. -struct upb_encoder; -typedef struct upb_encoder upb_encoder; - -upb_encoder *upb_encoder_new(upb_msgdef *md); -void upb_encoder_free(upb_encoder *e); - -// Resets the given upb_encoder such that is is ready to begin encoding, -// outputting data to "bytesink" (which must live until the encoder is -// reset or destroyed). -void upb_encoder_reset(upb_encoder *e, upb_bytesink *bytesink); - -// Returns the upb_sink to which data can be written. The sink is invalidated -// when the encoder is reset or destroyed. Note that if the client wants to -// encode any length-delimited submessages it must first call -// upb_encoder_buildsizes() below. -upb_sink *upb_encoder_sink(upb_encoder *e); - -// Call prior to pushing any data with embedded submessages. "src" must yield -// exactly the same data as what will next be encoded, but in reverse order. -// The encoder iterates over this data in order to determine the sizes of the -// submessages. If any errors are returned by the upb_src, the status will -// be saved in *status. If the client is sure that the upb_src will not throw -// any errors, "status" may be NULL. -void upb_encoder_buildsizes(upb_encoder *e, upb_src *src, upb_status *status); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_ENCODER_H_ */ diff --git a/stream/upb_stdio.c b/stream/upb_stdio.c deleted file mode 100644 index 8857677..0000000 --- a/stream/upb_stdio.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. - */ - -#include "upb_stdio.h" - -#include <stddef.h> -#include <stdlib.h> -#include "upb_string.h" - -// We can make this configurable if necessary. -#define BLOCK_SIZE 4096 - -struct upb_stdio { - upb_bytesrc bytesrc; - upb_bytesink bytesink; - FILE *file; -}; - -void upb_stdio_reset(upb_stdio *stdio, FILE* file) { - stdio->file = file; -} - - -/* upb_bytesrc methods ********************************************************/ - -static upb_strlen_t upb_stdio_read(upb_bytesrc *src, void *buf, - upb_strlen_t count, upb_status *status) { - upb_stdio *stdio = (upb_stdio*)src; - assert(count > 0); - size_t read = fread(buf, 1, count, stdio->file); - if(read < (size_t)count) { - // Error or EOF. - if(feof(stdio->file)) { - upb_seterr(status, UPB_EOF, ""); - return read; - } else if(ferror(stdio->file)) { - upb_seterr(status, UPB_ERROR, "Error reading from stdio stream."); - return -1; - } - } - return read; -} - -static bool upb_stdio_getstr(upb_bytesrc *src, upb_string *str, - upb_status *status) { - upb_strlen_t read = upb_stdio_read( - src, upb_string_getrwbuf(str, BLOCK_SIZE), BLOCK_SIZE, status); - if (read <= 0) return false; - upb_string_getrwbuf(str, read); - return true; -} - - -/* upb_bytesink methods *******************************************************/ - -upb_strlen_t upb_stdio_putstr(upb_bytesink *sink, upb_string *str, upb_status *status) { - upb_stdio *stdio = (upb_stdio*)((char*)sink - offsetof(upb_stdio, bytesink)); - upb_strlen_t len = upb_string_len(str); - upb_strlen_t written = fwrite(upb_string_getrobuf(str), 1, len, stdio->file); - if(written < len) { - upb_seterr(status, UPB_ERROR, "Error writing to stdio stream."); - return -1; - } - return written; -} - -upb_strlen_t upb_stdio_vprintf(upb_bytesink *sink, upb_status *status, - const char *fmt, va_list args) { - upb_stdio *stdio = (upb_stdio*)((char*)sink - offsetof(upb_stdio, bytesink)); - upb_strlen_t written = vfprintf(stdio->file, fmt, args); - if (written < 0) { - upb_seterr(status, UPB_ERROR, "Error writing to stdio stream."); - return -1; - } - return written; -} - -upb_stdio *upb_stdio_new() { - static upb_bytesrc_vtbl bytesrc_vtbl = { - upb_stdio_read, - upb_stdio_getstr, - }; - - static upb_bytesink_vtbl bytesink_vtbl = { - NULL, - upb_stdio_putstr, - upb_stdio_vprintf - }; - - upb_stdio *stdio = malloc(sizeof(*stdio)); - upb_bytesrc_init(&stdio->bytesrc, &bytesrc_vtbl); - upb_bytesink_init(&stdio->bytesink, &bytesink_vtbl); - return stdio; -} - -void upb_stdio_free(upb_stdio *stdio) { - free(stdio); -} - -upb_bytesrc* upb_stdio_bytesrc(upb_stdio *stdio) { return &stdio->bytesrc; } -upb_bytesink* upb_stdio_bytesink(upb_stdio *stdio) { return &stdio->bytesink; } diff --git a/stream/upb_stdio.h b/stream/upb_stdio.h deleted file mode 100644 index fd71fdd..0000000 --- a/stream/upb_stdio.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * This file provides upb_bytesrc and upb_bytesink implementations for - * ANSI C stdio. - * - * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. - */ - -#include <stdio.h> -#include "upb_stream.h" - -#ifndef UPB_STDIO_H_ -#define UPB_STDIO_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -struct upb_stdio; -typedef struct upb_stdio upb_stdio; - -// Creation/deletion. -upb_stdio *upb_stdio_new(); -void upb_stdio_free(upb_stdio *stdio); - -// Reset/initialize the object for use. The src or sink will call -// fread()/fwrite()/etc. on the given FILE*. -void upb_stdio_reset(upb_stdio *stdio, FILE* file); - -// Gets a bytesrc or bytesink for the given stdio. The returned pointer is -// invalidated by upb_stdio_reset above. It is perfectly valid to get both -// a bytesrc and a bytesink for the same stdio if the FILE* is open for reading -// and writing. -upb_bytesrc* upb_stdio_bytesrc(upb_stdio *stdio); -upb_bytesink* upb_stdio_bytesink(upb_stdio *stdio); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/stream/upb_strstream.c b/stream/upb_strstream.c deleted file mode 100644 index a7967d4..0000000 --- a/stream/upb_strstream.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. - */ - -#include "upb_strstream.h" - -#include <stdlib.h> -#include "upb_string.h" - -static upb_strlen_t upb_stringsrc_read(upb_bytesrc *_src, void *buf, - upb_strlen_t count, upb_status *status) { - upb_stringsrc *src = (upb_stringsrc*)_src; - if (src->offset == upb_string_len(src->str)) { - status->code = UPB_EOF; - return -1; - } else { - upb_strlen_t to_read = UPB_MIN(count, upb_string_len(src->str) - src->offset); - memcpy(buf, upb_string_getrobuf(src->str) + src->offset, to_read); - src->offset += to_read; - return to_read; - } -} - -static bool upb_stringsrc_getstr(upb_bytesrc *_src, upb_string *str, - upb_status *status) { - upb_stringsrc *src = (upb_stringsrc*)_src; - if (src->offset == upb_string_len(src->str)) { - status->code = UPB_EOF; - return false; - } else { - upb_strlen_t len = upb_string_len(src->str) - src->offset; - upb_string_substr(str, src->str, src->offset, len); - src->offset += len; - assert(src->offset == upb_string_len(src->str)); - return true; - } -} - -void upb_stringsrc_init(upb_stringsrc *s) { - static upb_bytesrc_vtbl bytesrc_vtbl = { - upb_stringsrc_read, - upb_stringsrc_getstr, - }; - s->str = NULL; - upb_bytesrc_init(&s->bytesrc, &bytesrc_vtbl); -} - -void upb_stringsrc_reset(upb_stringsrc *s, upb_string *str) { - if (str != s->str) { - upb_string_unref(s->str); - s->str = upb_string_getref(str); - } - s->offset = 0; -} - -void upb_stringsrc_uninit(upb_stringsrc *s) { - upb_string_unref(s->str); -} - - -upb_bytesrc *upb_stringsrc_bytesrc(upb_stringsrc *s) { - return &s->bytesrc; -} diff --git a/stream/upb_strstream.h b/stream/upb_strstream.h deleted file mode 100644 index 1a8792b..0000000 --- a/stream/upb_strstream.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * This file contains upb_bytesrc and upb_bytesink implementations for - * upb_string. - * - * Copyright (c) 2009-2010 Joshua Haberman. See LICENSE for details. - */ - -#ifndef UPB_STRSTREAM_H -#define UPB_STRSTREAM_H - -#include "upb_stream.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* upb_stringsrc **************************************************************/ - -struct _upb_stringsrc { - upb_bytesrc bytesrc; - upb_string *str; - upb_strlen_t offset; -}; -typedef struct _upb_stringsrc upb_stringsrc; - -// Create/free a stringsrc. -void upb_stringsrc_init(upb_stringsrc *s); -void upb_stringsrc_uninit(upb_stringsrc *s); - -// Resets the stringsrc to a state where it will vend the given string. The -// stringsrc will take a reference on the string, so the caller need not ensure -// that it outlives the stringsrc. A stringsrc can be reset multiple times. -void upb_stringsrc_reset(upb_stringsrc *s, upb_string *str); - -// Returns the upb_bytesrc* for this stringsrc. Invalidated by reset above. -upb_bytesrc *upb_stringsrc_bytesrc(upb_stringsrc *s); - - -/* upb_stringsink *************************************************************/ - -struct upb_stringsink; -typedef struct upb_stringsink upb_stringsink; - -// Create/free a stringsrc. -upb_stringsink *upb_stringsink_new(); -void upb_stringsink_free(upb_stringsink *s); - -// Gets a string containing the data that has been written to this stringsink. -// The caller does *not* own any references to this string. -upb_string *upb_stringsink_getstring(upb_stringsink *s); - -// Clears the internal string of accumulated data, resetting it to empty. -void upb_stringsink_reset(upb_stringsink *s); - -// Returns the upb_bytesrc* for this stringsrc. Invalidated by reset above. -upb_bytesink *upb_stringsrc_bytesink(); - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/stream/upb_textprinter.c b/stream/upb_textprinter.c deleted file mode 100644 index 894a1ea..0000000 --- a/stream/upb_textprinter.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. - */ - -#include "upb_textprinter.h" - -#include <inttypes.h> -#include <stdlib.h> -#include "upb_def.h" -#include "upb_string.h" - -struct _upb_textprinter { - upb_bytesink *bytesink; - int indent_depth; - bool single_line; - upb_status status; -}; - -#define CHECK(x) if ((x) < 0) goto err; - -static int upb_textprinter_indent(upb_textprinter *p) -{ - if(!p->single_line) - for(int i = 0; i < p->indent_depth; i++) - CHECK(upb_bytesink_putstr(p->bytesink, UPB_STRLIT(" "), &p->status)); - return 0; -err: - return -1; -} - -static int upb_textprinter_endfield(upb_textprinter *p) { - if(p->single_line) { - CHECK(upb_bytesink_putstr(p->bytesink, UPB_STRLIT(" "), &p->status)); - } else { - CHECK(upb_bytesink_putstr(p->bytesink, UPB_STRLIT("\n"), &p->status)); - } - return 0; -err: - return -1; -} - -static upb_flow_t upb_textprinter_value(void *_p, upb_fielddef *f, - upb_value val) { - upb_textprinter *p = _p; - upb_textprinter_indent(p); - CHECK(upb_bytesink_printf(p->bytesink, &p->status, UPB_STRFMT ": ", UPB_STRARG(f->name))); -#define CASE(fmtstr, member) \ - CHECK(upb_bytesink_printf(p->bytesink, &p->status, fmtstr, upb_value_get ## member(val))); break; - switch(f->type) { - case UPB_TYPE(DOUBLE): - CASE("%0.f", double); - case UPB_TYPE(FLOAT): - CASE("%0.f", float) - case UPB_TYPE(INT64): - case UPB_TYPE(SFIXED64): - case UPB_TYPE(SINT64): - CASE("%" PRId64, int64) - case UPB_TYPE(UINT64): - case UPB_TYPE(FIXED64): - CASE("%" PRIu64, uint64) - case UPB_TYPE(UINT32): - case UPB_TYPE(FIXED32): - CASE("%" PRIu32, uint32); - case UPB_TYPE(ENUM): { - upb_enumdef *enum_def = upb_downcast_enumdef(f->def); - upb_string *enum_label = - upb_enumdef_iton(enum_def, upb_value_getint32(val)); - if (enum_label) { - // We found a corresponding string for this enum. Otherwise we fall - // through to the int32 code path. - CHECK(upb_bytesink_putstr(p->bytesink, enum_label, &p->status)); - break; - } - } - case UPB_TYPE(INT32): - case UPB_TYPE(SFIXED32): - case UPB_TYPE(SINT32): - CASE("%" PRId32, int32) - case UPB_TYPE(BOOL): - CASE("%hhu", bool); - case UPB_TYPE(STRING): - case UPB_TYPE(BYTES): - // TODO: escaping. - CHECK(upb_bytesink_putstr(p->bytesink, UPB_STRLIT("\""), &p->status)); - CHECK(upb_bytesink_putstr(p->bytesink, upb_value_getstr(val), &p->status)) - CHECK(upb_bytesink_putstr(p->bytesink, UPB_STRLIT("\""), &p->status)); - break; - } - upb_textprinter_endfield(p); - return UPB_CONTINUE; -err: - return UPB_BREAK; -} - -static upb_flow_t upb_textprinter_startsubmsg(void *_p, upb_fielddef *f, - upb_handlers *delegate_to) { - (void)delegate_to; - upb_textprinter *p = _p; - upb_textprinter_indent(p); - CHECK(upb_bytesink_printf(p->bytesink, &p->status, UPB_STRFMT " {", UPB_STRARG(f->name))); - if(!p->single_line) upb_bytesink_putstr(p->bytesink, UPB_STRLIT("\n"), &p->status); - p->indent_depth++; - return UPB_CONTINUE; -err: - return UPB_BREAK; -} - -static upb_flow_t upb_textprinter_endsubmsg(void *_p) -{ - upb_textprinter *p = _p; - p->indent_depth--; - upb_textprinter_indent(p); - upb_bytesink_putstr(p->bytesink, UPB_STRLIT("}"), &p->status); - upb_textprinter_endfield(p); - return UPB_CONTINUE; -} - -upb_textprinter *upb_textprinter_new() { - upb_textprinter *p = malloc(sizeof(*p)); - return p; -} - -void upb_textprinter_free(upb_textprinter *p) { - free(p); -} - -void upb_textprinter_reset(upb_textprinter *p, upb_handlers *handlers, - upb_bytesink *sink, bool single_line) { - static upb_handlerset handlerset = { - NULL, // startmsg - NULL, // endmsg - upb_textprinter_value, - upb_textprinter_startsubmsg, - upb_textprinter_endsubmsg, - }; - p->bytesink = sink; - p->single_line = single_line; - p->indent_depth = 0; - upb_register_handlerset(handlers, &handlerset); - upb_set_handler_closure(handlers, p, &p->status); -} diff --git a/stream/upb_textprinter.h b/stream/upb_textprinter.h deleted file mode 100644 index a880626..0000000 --- a/stream/upb_textprinter.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. - */ - -#ifndef UPB_TEXT_H_ -#define UPB_TEXT_H_ - -#include "upb_stream.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct _upb_textprinter; -typedef struct _upb_textprinter upb_textprinter; - -upb_textprinter *upb_textprinter_new(); -void upb_textprinter_free(upb_textprinter *p); -void upb_textprinter_reset(upb_textprinter *p, upb_handlers *handlers, - upb_bytesink *sink, bool single_line); -void upb_textprinter_sethandlers(upb_textprinter *p, upb_handlers *h); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_TEXT_H_ */ |