From 87b2c69c15716b96a294f5918878fb8b7b9a0b40 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sat, 17 Jul 2010 12:56:04 -0700 Subject: Fleshed out upb_stdio and upb_textprinter. test_decoder now compiles and links! But it doesn't work yet. --- stream/upb_textprinter.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 stream/upb_textprinter.c (limited to 'stream/upb_textprinter.c') diff --git a/stream/upb_textprinter.c b/stream/upb_textprinter.c new file mode 100644 index 0000000..0f0357a --- /dev/null +++ b/stream/upb_textprinter.c @@ -0,0 +1,131 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. + */ + +#include "upb_textprinter.h" + +#include +#include +#include "upb_def.h" +#include "upb_string.h" + +struct _upb_textprinter { + upb_sink sink; + upb_bytesink *bytesink; + upb_string *str; + int indent_depth; + bool single_line; + upb_fielddef *f; +}; + +static void upb_textprinter_endfield(upb_textprinter *p) +{ + if(p->single_line) + upb_bytesink_put(p->bytesink, UPB_STRLIT(' ')); + else + upb_bytesink_put(p->bytesink, UPB_STRLIT('\n')); +} + +static bool upb_textprinter_putval(upb_textprinter *p, upb_value val) { + p->str = upb_string_tryrecycle(p->str); +#define CASE(fmtstr, member) upb_string_printf(p->str, fmtstr, val.member); break; + switch(p->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(INT32): + case UPB_TYPE(SFIXED32): + case UPB_TYPE(SINT32): + CASE("%" PRId32, int32) + case UPB_TYPE(UINT32): + case UPB_TYPE(FIXED32): + case UPB_TYPE(ENUM): + CASE("%" PRIu32, uint32); + case UPB_TYPE(BOOL): + CASE("%hhu", _bool); + } + upb_bytesink_put(p->bytesink, p->str); + upb_textprinter_endfield(p); + return upb_ok(upb_bytesink_status(p->bytesink)); +} + +static bool upb_textprinter_putstr(upb_textprinter *p, upb_string *str) { + upb_bytesink_put(p->bytesink, UPB_STRLIT("\"")); + // TODO: escaping. + upb_bytesink_put(p->bytesink, str); + upb_bytesink_put(p->bytesink, UPB_STRLIT("\"")); + upb_textprinter_endfield(p); + return upb_ok(upb_bytesink_status(p->bytesink)); +} + +static void upb_textprinter_indent(upb_textprinter *p) +{ + if(!p->single_line) + for(int i = 0; i < p->indent_depth; i++) + upb_bytesink_put(p->bytesink, UPB_STRLIT(" ")); +} + +static bool upb_textprinter_putdef(upb_textprinter *p, upb_fielddef *f) +{ + upb_textprinter_indent(p); + upb_bytesink_put(p->bytesink, f->name); + upb_bytesink_put(p->bytesink, UPB_STRLIT(":")); + p->f = f; + return upb_ok(upb_bytesink_status(p->bytesink)); +} + +static bool upb_textprinter_startmsg(upb_textprinter *p) +{ + upb_textprinter_indent(p); + upb_bytesink_put(p->bytesink, p->f->def->fqname); + upb_bytesink_put(p->bytesink, UPB_STRLIT(" {")); + if(!p->single_line) upb_bytesink_put(p->bytesink, UPB_STRLIT('\n')); + p->indent_depth++; + return upb_ok(upb_bytesink_status(p->bytesink)); +} + +static bool upb_textprinter_endmsg(upb_textprinter *p) +{ + p->indent_depth--; + upb_textprinter_indent(p); + upb_bytesink_put(p->bytesink, UPB_STRLIT("}")); + upb_textprinter_endfield(p); + return upb_ok(upb_bytesink_status(p->bytesink)); +} + +upb_sink_vtable upb_textprinter_vtbl = { + (upb_sink_putdef_fptr)upb_textprinter_putdef, + (upb_sink_putval_fptr)upb_textprinter_putval, + (upb_sink_putstr_fptr)upb_textprinter_putstr, + (upb_sink_startmsg_fptr)upb_textprinter_startmsg, + (upb_sink_endmsg_fptr)upb_textprinter_endmsg, +}; + +upb_textprinter *upb_textprinter_new() { + upb_textprinter *p = malloc(sizeof(*p)); + upb_sink_init(&p->sink, &upb_textprinter_vtbl); + return p; +} + +void upb_textprinter_free(upb_textprinter *p) { + free(p); +} + +void upb_textprinter_reset(upb_textprinter *p, upb_bytesink *sink, + bool single_line) { + p->bytesink = sink; + p->single_line = single_line; + p->indent_depth = 0; +} + +upb_sink *upb_textprinter_sink(upb_textprinter *p) { return &p->sink; } -- cgit v1.2.3 From af9d691a344746b15fb1df2e454273b637d20433 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sat, 17 Jul 2010 15:05:57 -0700 Subject: Added Xcode project. --- core/upb_string.c | 2 +- stream/upb_textprinter.c | 2 +- upb.xcodeproj/project.pbxproj | 497 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 499 insertions(+), 2 deletions(-) create mode 100644 upb.xcodeproj/project.pbxproj (limited to 'stream/upb_textprinter.c') diff --git a/core/upb_string.c b/core/upb_string.c index ca3c669..93686f5 100644 --- a/core/upb_string.c +++ b/core/upb_string.c @@ -71,7 +71,7 @@ upb_string *upb_string_tryrecycle(upb_string *str) { } char *upb_string_getrwbuf(upb_string *str, upb_strlen_t len) { - assert(str->ptr == NULL); + // assert(str->ptr == NULL); uint32_t size = upb_string_size(str); if (size < len) { size = upb_round_up_pow2(len); diff --git a/stream/upb_textprinter.c b/stream/upb_textprinter.c index 0f0357a..11ad6a8 100644 --- a/stream/upb_textprinter.c +++ b/stream/upb_textprinter.c @@ -7,7 +7,7 @@ #include "upb_textprinter.h" #include -#include +#include #include "upb_def.h" #include "upb_string.h" diff --git a/upb.xcodeproj/project.pbxproj b/upb.xcodeproj/project.pbxproj new file mode 100644 index 0000000..8b4eb4e --- /dev/null +++ b/upb.xcodeproj/project.pbxproj @@ -0,0 +1,497 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 420E6F1C11F258AE001DA8FE /* test_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D4F11F24F3E0076AD28 /* test_decoder.c */; }; + 420E6F3B11F259B3001DA8FE /* liblibupbcore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42BD1D5C11F24F920076AD28 /* liblibupbcore.a */; }; + 420E6F3C11F259B3001DA8FE /* liblibupbstream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42BD1D6411F24FBA0076AD28 /* liblibupbstream.a */; }; + 42BD1D6E11F2500D0076AD28 /* upb.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D3211F24E4C0076AD28 /* upb.c */; }; + 42BD1D7011F2500D0076AD28 /* upb_def.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D2911F24E4C0076AD28 /* upb_def.c */; }; + 42BD1D7211F2500D0076AD28 /* upb_stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D2C11F24E4C0076AD28 /* upb_stream.c */; }; + 42BD1D7311F2500D0076AD28 /* upb_string.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D2E11F24E4C0076AD28 /* upb_string.c */; }; + 42BD1D7411F2500D0076AD28 /* upb_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D3011F24E4C0076AD28 /* upb_table.c */; }; + 42BD1D7611F250B90076AD28 /* upb_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D3E11F24EA30076AD28 /* upb_decoder.c */; }; + 42BD1D7711F250B90076AD28 /* upb_stdio.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D4011F24EA30076AD28 /* upb_stdio.c */; }; + 42BD1D7811F250B90076AD28 /* upb_textprinter.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D4211F24EA30076AD28 /* upb_textprinter.c */; }; + 42BD1D9011F251820076AD28 /* descriptor_const.h in Headers */ = {isa = PBXBuildFile; fileRef = 42BD1D8D11F251820076AD28 /* descriptor_const.h */; }; + 42BD1D9111F251820076AD28 /* descriptor.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D8E11F251820076AD28 /* descriptor.c */; }; + 42BD1D9211F251820076AD28 /* descriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 42BD1D8F11F251820076AD28 /* descriptor.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 420E6F3311F2598D001DA8FE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 42BD1D5B11F24F920076AD28 /* upbcore */; + remoteInfo = upbcore; + }; + 420E6F3511F2598D001DA8FE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 42BD1D6311F24FBA0076AD28 /* upbstream */; + remoteInfo = upbstream; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 420E6F1811F2589F001DA8FE /* test_decoder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_decoder; sourceTree = BUILT_PRODUCTS_DIR; }; + 42BD1D2811F24E4C0076AD28 /* upb_atomic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_atomic.h; path = core/upb_atomic.h; sourceTree = ""; }; + 42BD1D2911F24E4C0076AD28 /* upb_def.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_def.c; path = core/upb_def.c; sourceTree = ""; }; + 42BD1D2A11F24E4C0076AD28 /* upb_def.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_def.h; path = core/upb_def.h; sourceTree = ""; }; + 42BD1D2B11F24E4C0076AD28 /* upb_stream_vtbl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_stream_vtbl.h; path = core/upb_stream_vtbl.h; sourceTree = ""; }; + 42BD1D2C11F24E4C0076AD28 /* upb_stream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_stream.c; path = core/upb_stream.c; sourceTree = ""; }; + 42BD1D2D11F24E4C0076AD28 /* upb_stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_stream.h; path = core/upb_stream.h; sourceTree = ""; }; + 42BD1D2E11F24E4C0076AD28 /* upb_string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_string.c; path = core/upb_string.c; sourceTree = ""; }; + 42BD1D2F11F24E4C0076AD28 /* upb_string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_string.h; path = core/upb_string.h; sourceTree = ""; }; + 42BD1D3011F24E4C0076AD28 /* upb_table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_table.c; path = core/upb_table.c; sourceTree = ""; }; + 42BD1D3111F24E4C0076AD28 /* upb_table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_table.h; path = core/upb_table.h; sourceTree = ""; }; + 42BD1D3211F24E4C0076AD28 /* upb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb.c; path = core/upb.c; sourceTree = ""; }; + 42BD1D3311F24E4C0076AD28 /* upb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb.h; path = core/upb.h; sourceTree = ""; }; + 42BD1D3E11F24EA30076AD28 /* upb_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_decoder.c; path = stream/upb_decoder.c; sourceTree = ""; }; + 42BD1D3F11F24EA30076AD28 /* upb_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_decoder.h; path = stream/upb_decoder.h; sourceTree = ""; }; + 42BD1D4011F24EA30076AD28 /* upb_stdio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_stdio.c; path = stream/upb_stdio.c; sourceTree = ""; }; + 42BD1D4111F24EA30076AD28 /* upb_stdio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_stdio.h; path = stream/upb_stdio.h; sourceTree = ""; }; + 42BD1D4211F24EA30076AD28 /* upb_textprinter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_textprinter.c; path = stream/upb_textprinter.c; sourceTree = ""; }; + 42BD1D4311F24EA30076AD28 /* upb_textprinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_textprinter.h; path = stream/upb_textprinter.h; sourceTree = ""; }; + 42BD1D4F11F24F3E0076AD28 /* test_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = test_decoder.c; path = tests/test_decoder.c; sourceTree = ""; }; + 42BD1D5011F24F3E0076AD28 /* test_def.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = test_def.c; path = tests/test_def.c; sourceTree = ""; }; + 42BD1D5111F24F3E0076AD28 /* test_string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = test_string.c; path = tests/test_string.c; sourceTree = ""; }; + 42BD1D5211F24F3E0076AD28 /* test_table.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test_table.cc; path = tests/test_table.cc; sourceTree = ""; }; + 42BD1D5311F24F3E0076AD28 /* test_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test_util.h; path = tests/test_util.h; sourceTree = ""; }; + 42BD1D5C11F24F920076AD28 /* liblibupbcore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblibupbcore.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 42BD1D6411F24FBA0076AD28 /* liblibupbstream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblibupbstream.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 42BD1D8D11F251820076AD28 /* descriptor_const.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = descriptor_const.h; path = descriptor/descriptor_const.h; sourceTree = ""; }; + 42BD1D8E11F251820076AD28 /* descriptor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = descriptor.c; path = descriptor/descriptor.c; sourceTree = ""; }; + 42BD1D8F11F251820076AD28 /* descriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = descriptor.h; path = descriptor/descriptor.h; sourceTree = ""; }; + C6A0FF2C0290799A04C91782 /* upb.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = upb.1; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 420E6F1611F2589F001DA8FE /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 420E6F3B11F259B3001DA8FE /* liblibupbcore.a in Frameworks */, + 420E6F3C11F259B3001DA8FE /* liblibupbstream.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 42BD1D5A11F24F920076AD28 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 42BD1D6211F24FBA0076AD28 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* upb */ = { + isa = PBXGroup; + children = ( + 08FB7795FE84155DC02AAC07 /* Source */, + C6A0FF2B0290797F04C91782 /* Documentation */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = upb; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 42BD1D8A11F251670076AD28 /* descriptor */, + 42BD1D4711F24EB20076AD28 /* tests */, + 42BD1D3B11F24E810076AD28 /* stream */, + 42BD1D3A11F24E5F0076AD28 /* core */, + ); + name = Source; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 42BD1D5C11F24F920076AD28 /* liblibupbcore.a */, + 42BD1D6411F24FBA0076AD28 /* liblibupbstream.a */, + 420E6F1811F2589F001DA8FE /* test_decoder */, + ); + name = Products; + sourceTree = ""; + }; + 42BD1D3A11F24E5F0076AD28 /* core */ = { + isa = PBXGroup; + children = ( + 42BD1D2811F24E4C0076AD28 /* upb_atomic.h */, + 42BD1D2911F24E4C0076AD28 /* upb_def.c */, + 42BD1D2A11F24E4C0076AD28 /* upb_def.h */, + 42BD1D2B11F24E4C0076AD28 /* upb_stream_vtbl.h */, + 42BD1D2C11F24E4C0076AD28 /* upb_stream.c */, + 42BD1D2D11F24E4C0076AD28 /* upb_stream.h */, + 42BD1D2E11F24E4C0076AD28 /* upb_string.c */, + 42BD1D2F11F24E4C0076AD28 /* upb_string.h */, + 42BD1D3011F24E4C0076AD28 /* upb_table.c */, + 42BD1D3111F24E4C0076AD28 /* upb_table.h */, + 42BD1D3211F24E4C0076AD28 /* upb.c */, + 42BD1D3311F24E4C0076AD28 /* upb.h */, + ); + name = core; + sourceTree = ""; + }; + 42BD1D3B11F24E810076AD28 /* stream */ = { + isa = PBXGroup; + children = ( + 42BD1D3E11F24EA30076AD28 /* upb_decoder.c */, + 42BD1D3F11F24EA30076AD28 /* upb_decoder.h */, + 42BD1D4011F24EA30076AD28 /* upb_stdio.c */, + 42BD1D4111F24EA30076AD28 /* upb_stdio.h */, + 42BD1D4211F24EA30076AD28 /* upb_textprinter.c */, + 42BD1D4311F24EA30076AD28 /* upb_textprinter.h */, + ); + name = stream; + sourceTree = ""; + }; + 42BD1D4711F24EB20076AD28 /* tests */ = { + isa = PBXGroup; + children = ( + 42BD1D4F11F24F3E0076AD28 /* test_decoder.c */, + 42BD1D5011F24F3E0076AD28 /* test_def.c */, + 42BD1D5111F24F3E0076AD28 /* test_string.c */, + 42BD1D5211F24F3E0076AD28 /* test_table.cc */, + 42BD1D5311F24F3E0076AD28 /* test_util.h */, + ); + name = tests; + sourceTree = ""; + }; + 42BD1D8A11F251670076AD28 /* descriptor */ = { + isa = PBXGroup; + children = ( + 42BD1D8D11F251820076AD28 /* descriptor_const.h */, + 42BD1D8E11F251820076AD28 /* descriptor.c */, + 42BD1D8F11F251820076AD28 /* descriptor.h */, + ); + name = descriptor; + sourceTree = ""; + }; + C6A0FF2B0290797F04C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + C6A0FF2C0290799A04C91782 /* upb.1 */, + ); + name = Documentation; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 42BD1D5811F24F920076AD28 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 42BD1D9011F251820076AD28 /* descriptor_const.h in Headers */, + 42BD1D9211F251820076AD28 /* descriptor.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 42BD1D6011F24FBA0076AD28 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 420E6F1711F2589F001DA8FE /* test_decoder */ = { + isa = PBXNativeTarget; + buildConfigurationList = 420E6F1F11F258CC001DA8FE /* Build configuration list for PBXNativeTarget "test_decoder" */; + buildPhases = ( + 420E6F1511F2589F001DA8FE /* Sources */, + 420E6F1611F2589F001DA8FE /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 420E6F3411F2598D001DA8FE /* PBXTargetDependency */, + 420E6F3611F2598D001DA8FE /* PBXTargetDependency */, + ); + name = test_decoder; + productName = test_decoder; + productReference = 420E6F1811F2589F001DA8FE /* test_decoder */; + productType = "com.apple.product-type.tool"; + }; + 42BD1D5B11F24F920076AD28 /* upbcore */ = { + isa = PBXNativeTarget; + buildConfigurationList = 42BD1D5F11F24FB10076AD28 /* Build configuration list for PBXNativeTarget "upbcore" */; + buildPhases = ( + 42BD1D5811F24F920076AD28 /* Headers */, + 42BD1D5911F24F920076AD28 /* Sources */, + 42BD1D5A11F24F920076AD28 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = upbcore; + productName = libupbcore; + productReference = 42BD1D5C11F24F920076AD28 /* liblibupbcore.a */; + productType = "com.apple.product-type.library.static"; + }; + 42BD1D6311F24FBA0076AD28 /* upbstream */ = { + isa = PBXNativeTarget; + buildConfigurationList = 42BD1D6911F24FED0076AD28 /* Build configuration list for PBXNativeTarget "upbstream" */; + buildPhases = ( + 42BD1D6011F24FBA0076AD28 /* Headers */, + 42BD1D6111F24FBA0076AD28 /* Sources */, + 42BD1D6211F24FBA0076AD28 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = upbstream; + productName = libupbstream; + productReference = 42BD1D6411F24FBA0076AD28 /* liblibupbstream.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "upb" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* upb */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 42BD1D5B11F24F920076AD28 /* upbcore */, + 42BD1D6311F24FBA0076AD28 /* upbstream */, + 420E6F1711F2589F001DA8FE /* test_decoder */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 420E6F1511F2589F001DA8FE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 420E6F1C11F258AE001DA8FE /* test_decoder.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 42BD1D5911F24F920076AD28 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 42BD1D6E11F2500D0076AD28 /* upb.c in Sources */, + 42BD1D7011F2500D0076AD28 /* upb_def.c in Sources */, + 42BD1D7211F2500D0076AD28 /* upb_stream.c in Sources */, + 42BD1D7311F2500D0076AD28 /* upb_string.c in Sources */, + 42BD1D7411F2500D0076AD28 /* upb_table.c in Sources */, + 42BD1D9111F251820076AD28 /* descriptor.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 42BD1D6111F24FBA0076AD28 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 42BD1D7611F250B90076AD28 /* upb_decoder.c in Sources */, + 42BD1D7711F250B90076AD28 /* upb_stdio.c in Sources */, + 42BD1D7811F250B90076AD28 /* upb_textprinter.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 420E6F3411F2598D001DA8FE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 42BD1D5B11F24F920076AD28 /* upbcore */; + targetProxy = 420E6F3311F2598D001DA8FE /* PBXContainerItemProxy */; + }; + 420E6F3611F2598D001DA8FE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 42BD1D6311F24FBA0076AD28 /* upbstream */; + targetProxy = 420E6F3511F2598D001DA8FE /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 1DEB928A08733DD80010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = UPB_THREAD_UNSAFE; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Debug; + }; + 1DEB928B08733DD80010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = UPB_THREAD_UNSAFE; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Release; + }; + 420E6F1A11F258A0001DA8FE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = /usr/local/bin; + PREBINDING = NO; + PRODUCT_NAME = test_decoder; + }; + name = Debug; + }; + 420E6F1B11F258A0001DA8FE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = /usr/local/bin; + PREBINDING = NO; + PRODUCT_NAME = test_decoder; + ZERO_LINK = NO; + }; + name = Release; + }; + 42BD1D5D11F24F930076AD28 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = libupbcore; + }; + name = Debug; + }; + 42BD1D5E11F24F930076AD28 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = libupbcore; + ZERO_LINK = NO; + }; + name = Release; + }; + 42BD1D6511F24FBA0076AD28 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = libupbstream; + }; + name = Debug; + }; + 42BD1D6611F24FBA0076AD28 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = libupbstream; + ZERO_LINK = NO; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "upb" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB928A08733DD80010E9CD /* Debug */, + 1DEB928B08733DD80010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 420E6F1F11F258CC001DA8FE /* Build configuration list for PBXNativeTarget "test_decoder" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 420E6F1A11F258A0001DA8FE /* Debug */, + 420E6F1B11F258A0001DA8FE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 42BD1D5F11F24FB10076AD28 /* Build configuration list for PBXNativeTarget "upbcore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 42BD1D5D11F24F930076AD28 /* Debug */, + 42BD1D5E11F24F930076AD28 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 42BD1D6911F24FED0076AD28 /* Build configuration list for PBXNativeTarget "upbstream" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 42BD1D6511F24FBA0076AD28 /* Debug */, + 42BD1D6611F24FBA0076AD28 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} -- cgit v1.2.3 From b77db146466a113bbfb9e56472bda1975f7a25a5 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sat, 17 Jul 2010 15:13:05 -0700 Subject: Fixed broken submsg support in upb_streamdata. --- core/upb_stream.c | 38 ++++++++++++++++++++++---------------- stream/upb_textprinter.c | 2 +- 2 files changed, 23 insertions(+), 17 deletions(-) (limited to 'stream/upb_textprinter.c') diff --git a/core/upb_stream.c b/core/upb_stream.c index bda11de..e63ba00 100644 --- a/core/upb_stream.c +++ b/core/upb_stream.c @@ -14,24 +14,30 @@ void upb_streamdata(upb_src *src, upb_sink *sink, upb_status *status) { upb_fielddef *f; upb_string *str = NULL; - while((f = upb_src_getdef(src)) != NULL) { - CHECKSINK(upb_sink_putdef(sink, f)); - if(upb_issubmsg(f)) { - // We always recurse into submessages, but the putdef above already told - // the sink that. - } else if(upb_isstring(f)) { - str = upb_string_tryrecycle(str); - CHECKSRC(upb_src_getstr(src, str)); - CHECKSINK(upb_sink_putstr(sink, str)); - } else { - // Primitive type. - upb_value val; - CHECKSRC(upb_src_getval(src, upb_value_addrof(&val))); - CHECKSINK(upb_sink_putval(sink, val)); + int depth = 0; + while(1) { + while((f = upb_src_getdef(src)) != NULL) { + CHECKSINK(upb_sink_putdef(sink, f)); + if(upb_issubmsg(f)) { + upb_src_startmsg(src); + upb_sink_startmsg(sink); + ++depth; + } else if(upb_isstring(f)) { + str = upb_string_tryrecycle(str); + CHECKSRC(upb_src_getstr(src, str)); + CHECKSINK(upb_sink_putstr(sink, str)); + } else { + // Primitive type. + upb_value val; + CHECKSRC(upb_src_getval(src, upb_value_addrof(&val))); + CHECKSINK(upb_sink_putval(sink, val)); + } } + // If we're not EOF now, the loop terminated due to an error. + CHECKSRC(upb_src_eof(src)); + if (depth == 0) break; + --depth; } - // If we're not EOF now, the loop terminated due to an error. - CHECKSRC(upb_src_eof(src)); return; src_err: diff --git a/stream/upb_textprinter.c b/stream/upb_textprinter.c index 11ad6a8..201edba 100644 --- a/stream/upb_textprinter.c +++ b/stream/upb_textprinter.c @@ -79,7 +79,7 @@ static bool upb_textprinter_putdef(upb_textprinter *p, upb_fielddef *f) { upb_textprinter_indent(p); upb_bytesink_put(p->bytesink, f->name); - upb_bytesink_put(p->bytesink, UPB_STRLIT(":")); + upb_bytesink_put(p->bytesink, UPB_STRLIT(": ")); p->f = f; return upb_ok(upb_bytesink_status(p->bytesink)); } -- cgit v1.2.3 From 0fcfeab521b01160875e863575dd5b63952b1593 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sat, 17 Jul 2010 18:30:53 -0700 Subject: Bugfixes, test_decoder successfully stream-decodes a stream! --- core/upb_stream.c | 5 +++++ stream/upb_decoder.c | 39 ++++++++++++++++++--------------------- stream/upb_textprinter.c | 9 +++++---- 3 files changed, 28 insertions(+), 25 deletions(-) (limited to 'stream/upb_textprinter.c') diff --git a/core/upb_stream.c b/core/upb_stream.c index e63ba00..0d47392 100644 --- a/core/upb_stream.c +++ b/core/upb_stream.c @@ -37,14 +37,19 @@ void upb_streamdata(upb_src *src, upb_sink *sink, upb_status *status) { CHECKSRC(upb_src_eof(src)); if (depth == 0) break; --depth; + upb_src_endmsg(src); + upb_sink_endmsg(sink); } + upb_string_unref(str); return; src_err: + upb_string_unref(str); upb_copyerr(status, upb_src_status(src)); return; sink_err: + upb_string_unref(str); upb_copyerr(status, upb_sink_status(sink)); return; } diff --git a/stream/upb_decoder.c b/stream/upb_decoder.c index 64057c5..949ce2d 100644 --- a/stream/upb_decoder.c +++ b/stream/upb_decoder.c @@ -76,7 +76,7 @@ struct upb_decoder { static upb_strlen_t upb_decoder_offset(upb_decoder *d) { - return d->buf_stream_offset - d->buf_offset; + return d->buf_stream_offset + d->buf_offset; } static bool upb_decoder_nextbuf(upb_decoder *d) @@ -101,34 +101,30 @@ static bool upb_decoder_nextbuf(upb_decoder *d) d->buf_bytesleft += upb_string_len(d->buf); return true; } else { - // Error or EOF. - if(!upb_bytesrc_eof(d->bytesrc)) { - // Error from bytesrc. - upb_copyerr(&d->src.status, upb_bytesrc_status(d->bytesrc)); - return false; - } else if(d->buf_bytesleft == 0) { - // EOF from bytesrc and we don't have any residual bytes left. - d->src.eof = true; - return false; - } else { - // No more data left from the bytesrc, but we still have residual bytes. - return true; - } + return false; } } static const uint8_t *upb_decoder_getbuf_full(upb_decoder *d, uint32_t *bytes) { + if(d->buf_bytesleft < UPB_MAX_ENCODED_SIZE && !upb_bytesrc_eof(d->bytesrc)) + upb_decoder_nextbuf(d); + if(d->buf_bytesleft < UPB_MAX_ENCODED_SIZE) { - // GCC is currently complaining about use of an uninitialized value if we - // don't set this now. I think this is incorrect, but leaving this in - // to suppress the warning for now. - *bytes = 0; - if(!upb_decoder_nextbuf(d)) return NULL; + if(upb_bytesrc_eof(d->bytesrc) && d->buf_bytesleft > 0) { + // We're working through the last few bytes of the buffer. + } else if(upb_bytesrc_eof(d->bytesrc)) { + // End of stream, no more bytes left. + assert(d->buf_bytesleft == 0); + d->src.eof = true; + return NULL; + } else { + // We are short of bytes even though the bytesrc isn't EOF; must be error. + upb_copyerr(&d->src.status, upb_bytesrc_status(d->bytesrc)); + return NULL; + } } - assert(d->buf_bytesleft >= UPB_MAX_ENCODED_SIZE); - if(d->buf_offset >= 0) { // Common case: the main buffer contains at least UPB_MAX_ENCODED_SIZE // contiguous bytes, so we can read directly out of it. @@ -467,6 +463,7 @@ bool upb_decoder_startmsg(upb_decoder *d) { } else { frame->end_offset = upb_decoder_offset(d) + d->delimited_len; } + d->field = NULL; return true; } diff --git a/stream/upb_textprinter.c b/stream/upb_textprinter.c index 201edba..75668a3 100644 --- a/stream/upb_textprinter.c +++ b/stream/upb_textprinter.c @@ -23,9 +23,9 @@ struct _upb_textprinter { static void upb_textprinter_endfield(upb_textprinter *p) { if(p->single_line) - upb_bytesink_put(p->bytesink, UPB_STRLIT(' ')); + upb_bytesink_put(p->bytesink, UPB_STRLIT(" ")); else - upb_bytesink_put(p->bytesink, UPB_STRLIT('\n')); + upb_bytesink_put(p->bytesink, UPB_STRLIT("\n")); } static bool upb_textprinter_putval(upb_textprinter *p, upb_value val) { @@ -86,10 +86,9 @@ static bool upb_textprinter_putdef(upb_textprinter *p, upb_fielddef *f) static bool upb_textprinter_startmsg(upb_textprinter *p) { - upb_textprinter_indent(p); upb_bytesink_put(p->bytesink, p->f->def->fqname); upb_bytesink_put(p->bytesink, UPB_STRLIT(" {")); - if(!p->single_line) upb_bytesink_put(p->bytesink, UPB_STRLIT('\n')); + if(!p->single_line) upb_bytesink_put(p->bytesink, UPB_STRLIT("\n")); p->indent_depth++; return upb_ok(upb_bytesink_status(p->bytesink)); } @@ -114,10 +113,12 @@ upb_sink_vtable upb_textprinter_vtbl = { upb_textprinter *upb_textprinter_new() { upb_textprinter *p = malloc(sizeof(*p)); upb_sink_init(&p->sink, &upb_textprinter_vtbl); + p->str = NULL; return p; } void upb_textprinter_free(upb_textprinter *p) { + upb_string_unref(p->str); free(p); } -- cgit v1.2.3 From 4b6c8b6b2317436ab77b38e17b49a7c7b03bf3f4 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sat, 17 Jul 2010 19:00:40 -0700 Subject: Fixed bugs in textoutput. Text output from descriptor.proto is now identical to protoc! --- core/upb_def.c | 6 +++++ core/upb_def.h | 1 + stream/upb_textprinter.c | 62 +++++++++++++++++++++++++++--------------------- 3 files changed, 42 insertions(+), 27 deletions(-) (limited to 'stream/upb_textprinter.c') diff --git a/core/upb_def.c b/core/upb_def.c index c0d72db..fd00895 100644 --- a/core/upb_def.c +++ b/core/upb_def.c @@ -331,6 +331,12 @@ upb_enum_iter upb_enum_next(upb_enumdef *e, upb_enum_iter iter) { return upb_inttable_next(&e->iton, &iter->e); } +upb_string *upb_enumdef_iton(upb_enumdef *def, upb_enumval_t num) { + upb_iton_ent *e = + (upb_iton_ent*)upb_inttable_fastlookup(&def->iton, num, sizeof(*e)); + return e ? e->string : NULL; +} + /* upb_fielddef ***************************************************************/ diff --git a/core/upb_def.h b/core/upb_def.h index 82d8520..9cdc54d 100644 --- a/core/upb_def.h +++ b/core/upb_def.h @@ -202,6 +202,7 @@ typedef int32_t upb_enumval_t; // Lookups from name to integer and vice-versa. bool upb_enumdef_ntoi(upb_enumdef *e, upb_string *name, upb_enumval_t *num); +// Caller does not own a ref on the returned string. upb_string *upb_enumdef_iton(upb_enumdef *e, upb_enumval_t num); // Iteration over name/value pairs. The order is undefined. diff --git a/stream/upb_textprinter.c b/stream/upb_textprinter.c index 75668a3..2d2e237 100644 --- a/stream/upb_textprinter.c +++ b/stream/upb_textprinter.c @@ -29,38 +29,48 @@ static void upb_textprinter_endfield(upb_textprinter *p) } static bool upb_textprinter_putval(upb_textprinter *p, upb_value val) { - p->str = upb_string_tryrecycle(p->str); + upb_bytesink_put(p->bytesink, UPB_STRLIT(": ")); + upb_enumdef *enum_def; + upb_string *enum_label; + if(p->f->type == UPB_TYPE(ENUM) && + (enum_def = upb_downcast_enumdef(p->f->def)) != NULL && + (enum_label = upb_enumdef_iton(enum_def, val.int32)) != NULL) { + // This is an enum value for which we found a corresponding string. + upb_bytesink_put(p->bytesink, enum_label); + } else { + p->str = upb_string_tryrecycle(p->str); #define CASE(fmtstr, member) upb_string_printf(p->str, fmtstr, val.member); break; - switch(p->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(INT32): - case UPB_TYPE(SFIXED32): - case UPB_TYPE(SINT32): - CASE("%" PRId32, int32) - case UPB_TYPE(UINT32): - case UPB_TYPE(FIXED32): - case UPB_TYPE(ENUM): - CASE("%" PRIu32, uint32); - case UPB_TYPE(BOOL): - CASE("%hhu", _bool); + switch(p->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(INT32): + case UPB_TYPE(SFIXED32): + case UPB_TYPE(SINT32): + CASE("%" PRId32, int32) + case UPB_TYPE(UINT32): + case UPB_TYPE(FIXED32): + case UPB_TYPE(ENUM): + CASE("%" PRIu32, uint32); + case UPB_TYPE(BOOL): + CASE("%hhu", _bool); + } + upb_bytesink_put(p->bytesink, p->str); } - upb_bytesink_put(p->bytesink, p->str); upb_textprinter_endfield(p); return upb_ok(upb_bytesink_status(p->bytesink)); } static bool upb_textprinter_putstr(upb_textprinter *p, upb_string *str) { - upb_bytesink_put(p->bytesink, UPB_STRLIT("\"")); + upb_bytesink_put(p->bytesink, UPB_STRLIT(": \"")); // TODO: escaping. upb_bytesink_put(p->bytesink, str); upb_bytesink_put(p->bytesink, UPB_STRLIT("\"")); @@ -79,14 +89,12 @@ static bool upb_textprinter_putdef(upb_textprinter *p, upb_fielddef *f) { upb_textprinter_indent(p); upb_bytesink_put(p->bytesink, f->name); - upb_bytesink_put(p->bytesink, UPB_STRLIT(": ")); p->f = f; return upb_ok(upb_bytesink_status(p->bytesink)); } static bool upb_textprinter_startmsg(upb_textprinter *p) { - upb_bytesink_put(p->bytesink, p->f->def->fqname); upb_bytesink_put(p->bytesink, UPB_STRLIT(" {")); if(!p->single_line) upb_bytesink_put(p->bytesink, UPB_STRLIT("\n")); p->indent_depth++; -- cgit v1.2.3 From 2c24cbb108bbda296f01e7628028b1dcb2b9516b Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 25 Jan 2011 10:07:47 -0800 Subject: More work on decoder and stdio bytesrc/bytesink. --- Makefile | 6 ++--- core/upb.c | 17 +++++-------- core/upb_stream.h | 16 +++++++----- stream/upb_decoder.c | 14 +++++++--- stream/upb_stdio.c | 66 +++++++++++++++++++++++------------------------- stream/upb_textprinter.c | 1 - stream/upb_textprinter.h | 3 +-- 7 files changed, 63 insertions(+), 60 deletions(-) (limited to 'stream/upb_textprinter.c') diff --git a/Makefile b/Makefile index 46cb836..1dfd79d 100644 --- a/Makefile +++ b/Makefile @@ -63,10 +63,10 @@ SRC=core/upb.c \ descriptor/descriptor.c \ core/upb_def.c \ stream/upb_decoder.c \ + stream/upb_stdio.c \ + stream/upb_textprinter.c # core/upb_msg.c \ -# stream/upb_stdio.c \ # stream/upb_strstream.c \ -# stream/upb_textprinter.c $(SRC): perf-cppflags # Parts of core that are yet to be converted. @@ -114,7 +114,7 @@ TESTS=tests/test_string \ tests/test_table \ tests/test_def \ tests/test_stream \ -# tests/test_decoder \ + tests/test_decoder \ # tests/t.test_vs_proto2.googlemessage1 \ # tests/t.test_vs_proto2.googlemessage2 \ # tests/test.proto.pb diff --git a/core/upb.c b/core/upb.c index ff2d47e..525c8a8 100644 --- a/core/upb.c +++ b/core/upb.c @@ -41,16 +41,13 @@ const upb_type_info upb_types[] = { }; void upb_seterr(upb_status *status, enum upb_status_code code, - const char *msg, ...) -{ - if(upb_ok(status)) { // The first error is the most interesting. - status->code = code; - upb_string_recycle(&status->str); - va_list args; - va_start(args, msg); - upb_string_vprintf(status->str, msg, args); - va_end(args); - } + const char *msg, ...) { + status->code = code; + upb_string_recycle(&status->str); + va_list args; + va_start(args, msg); + upb_string_vprintf(status->str, msg, args); + va_end(args); } void upb_copyerr(upb_status *to, upb_status *from) diff --git a/core/upb_stream.h b/core/upb_stream.h index bf312a8..d0045cc 100644 --- a/core/upb_stream.h +++ b/core/upb_stream.h @@ -178,12 +178,16 @@ INLINE void upb_src_run(upb_src *src, upb_status *status); INLINE upb_strlen_t upb_bytesrc_read(upb_bytesrc *src, void *buf, upb_strlen_t count, upb_status *status); -// Like upb_bytesrc_read(), but modifies "str" in-place, possibly aliasing -// existing string data (which avoids a copy). On the other hand, if -// the data was *not* already in an existing string, this copies it into -// a upb_string, and if the data needs to be put in a specific range of -// memory (because eg. you need to put it into a different kind of string -// object) then upb_bytesrc_get() could be better. +// Like upb_bytesrc_read(), but modifies "str" in-place. "str" MUST be newly +// created or just recycled. Returns "false" if no data was returned, either +// due to error or EOF (check status for details). +// +// In comparison to upb_bytesrc_read(), this call can possibly alias existing +// string data (which avoids a copy). On the other hand, if the data was *not* +// already in an existing string, this copies it into a upb_string, and if the +// data needs to be put in a specific range of memory (because eg. you need to +// put it into a different kind of string object) then upb_bytesrc_get() could +// be better. INLINE bool upb_bytesrc_getstr(upb_bytesrc *src, upb_string *str, upb_status *status); diff --git a/stream/upb_decoder.c b/stream/upb_decoder.c index b4b32ff..e60915f 100644 --- a/stream/upb_decoder.c +++ b/stream/upb_decoder.c @@ -126,6 +126,7 @@ static bool upb_getbuf(upb_decoder *d, void *data, size_t bytes_wanted, } else { // End-of-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); } @@ -295,7 +296,15 @@ void upb_decoder_run(upb_src *src, upb_status *status) { while(1) { // Parse/handle tag. upb_tag tag; - CHECK(upb_decode_tag(d, &state, &tag)); + if (!upb_decode_tag(d, &state, &tag)) { + if (status->code == UPB_EOF && d->top == d->stack) { + // Normal end-of-file. + CHECK_FLOW(upb_dispatch_endmsg(&d->dispatcher)); + return; + } else { + goto err; + } + } // Decode wire data. Hopefully this branch will predict pretty well // since most types will read a varint here. @@ -361,9 +370,6 @@ void upb_decoder_run(upb_src *src, upb_status *status) { CHECK_FLOW(upb_dispatch_value(&d->dispatcher, f, val)); } - CHECK_FLOW(upb_dispatch_endmsg(&d->dispatcher)); - return; - err: if (upb_ok(status)) { upb_seterr(status, UPB_ERROR, "Callback returned UPB_BREAK"); diff --git a/stream/upb_stdio.c b/stream/upb_stdio.c index 820399b..7923664 100644 --- a/stream/upb_stdio.c +++ b/stream/upb_stdio.c @@ -23,44 +23,42 @@ void upb_stdio_reset(upb_stdio *stdio, FILE* file) { stdio->file = file; } -static bool upb_stdio_read(upb_stdio *stdio, upb_string *str, - int offset, size_t bytes_to_read) { - char *buf = upb_string_getrwbuf(str, offset + bytes_to_read) + offset; - size_t read = fread(buf, 1, bytes_to_read, stdio->file); - if(read < bytes_to_read) { +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. - stdio->bytesrc.eof = feof(stdio->file); - if(ferror(stdio->file)) { - upb_seterr(&stdio->bytesrc.status, UPB_STATUS_ERROR, - "Error reading from stdio stream."); - return false; + 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; } - // Resize to actual read size. - upb_string_getrwbuf(str, offset + read); } - return true; + return read; } -bool upb_stdio_get(upb_bytesrc *src, upb_string *str, upb_strlen_t minlen) { - // We ignore "minlen" since the stdio interfaces always return a full read - // unless they are at EOF. - (void)minlen; - return upb_stdio_read((upb_stdio*)src, str, 0, BLOCK_SIZE); -} - -bool upb_stdio_append(upb_bytesrc *src, upb_string *str, upb_strlen_t len) { - return upb_stdio_read((upb_stdio*)src, str, upb_string_len(str), len); +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; } int32_t upb_stdio_put(upb_bytesink *sink, upb_string *str) { upb_stdio *stdio = (upb_stdio*)((char*)sink - offsetof(upb_stdio, bytesink)); upb_strlen_t len = upb_string_len(str); - size_t written = fwrite(upb_string_getrobuf(str), 1, len, stdio->file); + upb_strlen_t written = fwrite(upb_string_getrobuf(str), 1, len, stdio->file); if(written < len) { // Error or EOF. stdio->bytesink.eof = feof(stdio->file); if(ferror(stdio->file)) { - upb_seterr(&stdio->bytesink.status, UPB_STATUS_ERROR, + upb_seterr(&stdio->bytesink.status, UPB_ERROR, "Error writing to stdio stream."); return 0; } @@ -68,19 +66,19 @@ int32_t upb_stdio_put(upb_bytesink *sink, upb_string *str) { return written; } -static upb_bytesrc_vtable upb_stdio_bytesrc_vtbl = { - (upb_bytesrc_get_fptr)upb_stdio_get, - (upb_bytesrc_append_fptr)upb_stdio_append, -}; +upb_stdio *upb_stdio_new() { + static upb_bytesrc_vtbl bytesrc_vtbl = { + upb_stdio_read, + upb_stdio_getstr, + }; -static upb_bytesink_vtable upb_stdio_bytesink_vtbl = { - upb_stdio_put -}; + //static upb_bytesink_vtbl bytesink_vtbl = { + // upb_stdio_put + //}; -upb_stdio *upb_stdio_new() { upb_stdio *stdio = malloc(sizeof(*stdio)); - upb_bytesrc_init(&stdio->bytesrc, &upb_stdio_bytesrc_vtbl); - upb_bytesink_init(&stdio->bytesink, &upb_stdio_bytesink_vtbl); + upb_bytesrc_init(&stdio->bytesrc, &bytesrc_vtbl); + //upb_bytesink_init(&stdio->bytesink, &bytesink_vtbl); return stdio; } diff --git a/stream/upb_textprinter.c b/stream/upb_textprinter.c index 2d2e237..3a77ab1 100644 --- a/stream/upb_textprinter.c +++ b/stream/upb_textprinter.c @@ -12,7 +12,6 @@ #include "upb_string.h" struct _upb_textprinter { - upb_sink sink; upb_bytesink *bytesink; upb_string *str; int indent_depth; diff --git a/stream/upb_textprinter.h b/stream/upb_textprinter.h index 7e35412..b40d9fa 100644 --- a/stream/upb_textprinter.h +++ b/stream/upb_textprinter.h @@ -20,8 +20,7 @@ upb_textprinter *upb_textprinter_new(); void upb_textprinter_free(upb_textprinter *p); void upb_textprinter_reset(upb_textprinter *p, upb_bytesink *sink, bool single_line); - -upb_sink *upb_textprinter_sink(upb_textprinter *p); +void upb_textprinter_sethandlers(upb_textprinter *p, upb_handlers *h); #ifdef __cplusplus } /* extern "C" */ -- cgit v1.2.3 From 5af1ade5435807da065197c0c558947b34628d58 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 28 Jan 2011 10:11:25 -0800 Subject: More work on textprinter. --- stream/upb_textprinter.c | 143 +++++++++++++++++++++-------------------------- 1 file changed, 64 insertions(+), 79 deletions(-) (limited to 'stream/upb_textprinter.c') diff --git a/stream/upb_textprinter.c b/stream/upb_textprinter.c index 3a77ab1..2209173 100644 --- a/stream/upb_textprinter.c +++ b/stream/upb_textprinter.c @@ -13,119 +13,104 @@ struct _upb_textprinter { upb_bytesink *bytesink; - upb_string *str; int indent_depth; bool single_line; upb_fielddef *f; }; -static void upb_textprinter_endfield(upb_textprinter *p) +static void upb_textprinter_indent(upb_textprinter *p) { + if(!p->single_line) + for(int i = 0; i < p->indent_depth; i++) + upb_bytesink_put(p->bytesink, UPB_STRLIT(" ")); +} + +static void upb_textprinter_endfield(upb_textprinter *p) { if(p->single_line) upb_bytesink_put(p->bytesink, UPB_STRLIT(" ")); else upb_bytesink_put(p->bytesink, UPB_STRLIT("\n")); } -static bool upb_textprinter_putval(upb_textprinter *p, upb_value val) { - upb_bytesink_put(p->bytesink, UPB_STRLIT(": ")); - upb_enumdef *enum_def; - upb_string *enum_label; - if(p->f->type == UPB_TYPE(ENUM) && - (enum_def = upb_downcast_enumdef(p->f->def)) != NULL && - (enum_label = upb_enumdef_iton(enum_def, val.int32)) != NULL) { - // This is an enum value for which we found a corresponding string. - upb_bytesink_put(p->bytesink, enum_label); - } else { - p->str = upb_string_tryrecycle(p->str); -#define CASE(fmtstr, member) upb_string_printf(p->str, fmtstr, val.member); break; - switch(p->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(INT32): - case UPB_TYPE(SFIXED32): - case UPB_TYPE(SINT32): - CASE("%" PRId32, int32) - case UPB_TYPE(UINT32): - case UPB_TYPE(FIXED32): - case UPB_TYPE(ENUM): - CASE("%" PRIu32, uint32); - case UPB_TYPE(BOOL): - CASE("%hhu", _bool); +static upb_flow_t upb_textprinter_value(void *_p, upb_fielddef *f, + upb_value val) { + upb_textprinter *p = _p; + upb_textprinter_indent(p); + upb_bytesink_printf(p->bytesink, UPB_STRFMT ": ", UPB_STRARG(f->name)); +#define CASE(fmtstr, member) upb_bytesink_printf(p->bytesink, fmtstr, val.member); break; + switch(p->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(INT32): + case UPB_TYPE(SFIXED32): + case UPB_TYPE(SINT32): + CASE("%" PRId32, int32) + case UPB_TYPE(UINT32): + case UPB_TYPE(FIXED32): + CASE("%" PRIu32, uint32); + case UPB_TYPE(ENUM): { + upb_enumdef *enum_def; + upb_string *enum_label; + (enum_def = upb_downcast_enumdef(p->f->def)) != NULL && + (enum_label = upb_enumdef_iton(enum_def, val.int32)) != NULL) { + // This is an enum value for which we found a corresponding string. + upb_bytesink_put(p->bytesink, enum_label); + CASE("%" PRIu32, uint32); } - upb_bytesink_put(p->bytesink, p->str); + case UPB_TYPE(BOOL): + CASE("%hhu", _bool); + case UPB_TYPE(STRING): + case UPB_TYPE(BYTES): + upb_bytesink_put(p->bytesink, UPB_STRLIT(": \"")); + upb_bytesink_put(p->bytesink, str); + upb_bytesink_put(p->bytesink, UPB_STRLIT("\"")); + break; } upb_textprinter_endfield(p); - return upb_ok(upb_bytesink_status(p->bytesink)); -} - -static bool upb_textprinter_putstr(upb_textprinter *p, upb_string *str) { - upb_bytesink_put(p->bytesink, UPB_STRLIT(": \"")); - // TODO: escaping. - upb_bytesink_put(p->bytesink, str); - upb_bytesink_put(p->bytesink, UPB_STRLIT("\"")); - upb_textprinter_endfield(p); - return upb_ok(upb_bytesink_status(p->bytesink)); -} - -static void upb_textprinter_indent(upb_textprinter *p) -{ - if(!p->single_line) - for(int i = 0; i < p->indent_depth; i++) - upb_bytesink_put(p->bytesink, UPB_STRLIT(" ")); + return UPB_CONTINUE; } -static bool upb_textprinter_putdef(upb_textprinter *p, upb_fielddef *f) -{ - upb_textprinter_indent(p); - upb_bytesink_put(p->bytesink, f->name); - p->f = f; - return upb_ok(upb_bytesink_status(p->bytesink)); -} - -static bool upb_textprinter_startmsg(upb_textprinter *p) -{ +static upb_flow_t upb_textprinter_startsubmsg(void *_p, upb_fielddef *f) { + upb_textprinter *p = _p; + p->indent_depth++; upb_bytesink_put(p->bytesink, UPB_STRLIT(" {")); if(!p->single_line) upb_bytesink_put(p->bytesink, UPB_STRLIT("\n")); - p->indent_depth++; - return upb_ok(upb_bytesink_status(p->bytesink)); + return UPB_CONTINUE; } -static bool upb_textprinter_endmsg(upb_textprinter *p) +static upb_flow_t upb_textprinter_endsubmsg(void *_p) { + upb_textprinter *p = _p; p->indent_depth--; upb_textprinter_indent(p); upb_bytesink_put(p->bytesink, UPB_STRLIT("}")); upb_textprinter_endfield(p); - return upb_ok(upb_bytesink_status(p->bytesink)); + return UPB_CONTINUE; } -upb_sink_vtable upb_textprinter_vtbl = { - (upb_sink_putdef_fptr)upb_textprinter_putdef, - (upb_sink_putval_fptr)upb_textprinter_putval, - (upb_sink_putstr_fptr)upb_textprinter_putstr, - (upb_sink_startmsg_fptr)upb_textprinter_startmsg, - (upb_sink_endmsg_fptr)upb_textprinter_endmsg, -}; - upb_textprinter *upb_textprinter_new() { + static upb_handlerset handlers = { + NULL, // startmsg + NULL, // endmsg + upb_textprinter_putval, + upb_textprinter_startsubmsg, + upb_textprinter_endsubmsg, + }; upb_textprinter *p = malloc(sizeof(*p)); - upb_sink_init(&p->sink, &upb_textprinter_vtbl); - p->str = NULL; + upb_byte_init(&p->sink, &upb_textprinter_vtbl); return p; } void upb_textprinter_free(upb_textprinter *p) { - upb_string_unref(p->str); free(p); } -- cgit v1.2.3 From d98db7cb567f17a3bb56e2af8499d2e3aef03b3b Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sat, 29 Jan 2011 12:07:09 -0800 Subject: Textprinter is compiling again. --- core/upb_stream.h | 22 ++++++--- core/upb_stream_vtbl.h | 21 ++++++--- stream/upb_textprinter.c | 114 ++++++++++++++++++++++++++++------------------- stream/upb_textprinter.h | 4 +- 4 files changed, 103 insertions(+), 58 deletions(-) (limited to 'stream/upb_textprinter.c') diff --git a/core/upb_stream.h b/core/upb_stream.h index 09e4025..aa23549 100644 --- a/core/upb_stream.h +++ b/core/upb_stream.h @@ -245,16 +245,26 @@ INLINE bool upb_value_getfullstr(upb_value val, upb_string *str, struct _upb_bytesink; typedef struct _upb_bytesink upb_bytesink; -INLINE bool upb_bytesink_printf(upb_bytesink *sink, const char *fmt, ...); +// TODO: Figure out how buffering should be handled. Should the caller buffer +// data and only call these functions when a buffer is full? Seems most +// efficient, but then buffering has to be configured in the caller, which +// could be anything, which makes it hard to have a standard interface for +// controlling buffering. +// +// The downside of having the bytesink buffer is efficiency: the caller is +// making more (virtual) function calls, and the caller can't arrange to have +// a big contiguous buffer. The bytesink can do this, but will have to copy +// to make the data contiguous. + +// Returns the number of bytes written. +INLINE upb_strlen_t upb_bytesink_printf(upb_bytesink *sink, upb_status *status, + const char *fmt, ...); // Puts the given string, returning true if the operation was successful, otherwise // check "status" for details. Ownership of the string is *not* passed; if // the callee wants a reference he must call upb_string_getref() on it. -INLINE bool upb_bytesink_putstr(upb_bytesink *sink, upb_string *str, - upb_status *status); - -// Returns the current error status for the stream. -INLINE upb_status *upb_bytesink_status(upb_bytesink *sink); +INLINE upb_strlen_t upb_bytesink_putstr(upb_bytesink *sink, upb_string *str, + upb_status *status); #include "upb_stream_vtbl.h" diff --git a/core/upb_stream_vtbl.h b/core/upb_stream_vtbl.h index ef655fd..8e8971f 100644 --- a/core/upb_stream_vtbl.h +++ b/core/upb_stream_vtbl.h @@ -34,8 +34,10 @@ typedef bool (*upb_bytesrc_getstr_fptr)( // upb_bytesink. typedef upb_strlen_t (*upb_bytesink_write_fptr)( upb_bytesink *bytesink, void *buf, upb_strlen_t count); -typedef upb_strlen_t (*upb_bytesink_putstr_fptr)( - upb_bytesink *bytesink, upb_string *str); +typedef bool (*upb_bytesink_putstr_fptr)( + upb_bytesink *bytesink, upb_string *str, upb_status *status); +typedef upb_strlen_t (*upb_bytesink_vprintf_fptr)( + upb_status *status, const char *fmt, va_list args); // Vtables for the above interfaces. typedef struct { @@ -44,8 +46,9 @@ typedef struct { } upb_bytesrc_vtbl; typedef struct { - upb_bytesink_write_fptr write; - upb_bytesink_putstr_fptr putstr; + upb_bytesink_write_fptr write; + upb_bytesink_putstr_fptr putstr; + upb_bytesink_vprintf_fptr vprintf; } upb_bytesink_vtbl; typedef struct { @@ -140,13 +143,21 @@ INLINE upb_strlen_t upb_bytesink_write(upb_bytesink *sink, void *buf, } INLINE upb_strlen_t upb_bytesink_putstr(upb_bytesink *sink, upb_string *str, upb_status *status) { - return sink->vtbl->putstr(sink, str); + return sink->vtbl->putstr(sink, str, status); } INLINE upb_status *upb_bytesink_status(upb_bytesink *sink) { return &sink->status; } +INLINE upb_strlen_t upb_bytesink_printf(upb_bytesink *sink, upb_status *status, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + upb_strlen_t ret = sink->vtbl->vprintf(status, fmt, args); + va_end(args); + return ret; +} + // upb_handlers struct _upb_handlers { upb_handlerset *set; diff --git a/stream/upb_textprinter.c b/stream/upb_textprinter.c index 2209173..7025494 100644 --- a/stream/upb_textprinter.c +++ b/stream/upb_textprinter.c @@ -15,34 +15,51 @@ struct _upb_textprinter { upb_bytesink *bytesink; int indent_depth; bool single_line; - upb_fielddef *f; + upb_status status; }; -static void upb_textprinter_indent(upb_textprinter *p) +#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++) - upb_bytesink_put(p->bytesink, UPB_STRLIT(" ")); + CHECK(upb_bytesink_putstr(p->bytesink, UPB_STRLIT(" "), &p->status)); + return 0; +err: + return -1; } -static void upb_textprinter_endfield(upb_textprinter *p) { - if(p->single_line) - upb_bytesink_put(p->bytesink, UPB_STRLIT(" ")); - else - upb_bytesink_put(p->bytesink, UPB_STRLIT("\n")); +static int upb_textprinter_startfield(upb_textprinter *p, upb_fielddef *f) { + upb_textprinter_indent(p); + CHECK(upb_bytesink_printf(p->bytesink, &p->status, UPB_STRFMT ": ", UPB_STRARG(f->name))); + 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); - upb_bytesink_printf(p->bytesink, UPB_STRFMT ": ", UPB_STRARG(f->name)); -#define CASE(fmtstr, member) upb_bytesink_printf(p->bytesink, fmtstr, val.member); break; - switch(p->f->type) { + upb_textprinter_startfield(p, f); +#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("%0.f", double); case UPB_TYPE(FLOAT): - CASE("%0.f", _float) + CASE("%0.f", float) case UPB_TYPE(INT64): case UPB_TYPE(SFIXED64): case UPB_TYPE(SINT64): @@ -50,40 +67,48 @@ static upb_flow_t upb_textprinter_value(void *_p, upb_fielddef *f, case UPB_TYPE(UINT64): case UPB_TYPE(FIXED64): CASE("%" PRIu64, uint64) - case UPB_TYPE(INT32): - case UPB_TYPE(SFIXED32): - case UPB_TYPE(SINT32): - CASE("%" PRId32, int32) case UPB_TYPE(UINT32): case UPB_TYPE(FIXED32): CASE("%" PRIu32, uint32); case UPB_TYPE(ENUM): { - upb_enumdef *enum_def; - upb_string *enum_label; - (enum_def = upb_downcast_enumdef(p->f->def)) != NULL && - (enum_label = upb_enumdef_iton(enum_def, val.int32)) != NULL) { - // This is an enum value for which we found a corresponding string. - upb_bytesink_put(p->bytesink, enum_label); - CASE("%" PRIu32, uint32); + 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("%hhu", bool); case UPB_TYPE(STRING): case UPB_TYPE(BYTES): - upb_bytesink_put(p->bytesink, UPB_STRLIT(": \"")); - upb_bytesink_put(p->bytesink, str); - upb_bytesink_put(p->bytesink, UPB_STRLIT("\"")); + // 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) { +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_startfield(p, f); p->indent_depth++; - upb_bytesink_put(p->bytesink, UPB_STRLIT(" {")); - if(!p->single_line) upb_bytesink_put(p->bytesink, UPB_STRLIT("\n")); + upb_bytesink_putstr(p->bytesink, UPB_STRLIT(" {"), &p->status); + if(!p->single_line) upb_bytesink_putstr(p->bytesink, UPB_STRLIT("\n"), &p->status); return UPB_CONTINUE; } @@ -92,21 +117,13 @@ static upb_flow_t upb_textprinter_endsubmsg(void *_p) upb_textprinter *p = _p; p->indent_depth--; upb_textprinter_indent(p); - upb_bytesink_put(p->bytesink, UPB_STRLIT("}")); + upb_bytesink_putstr(p->bytesink, UPB_STRLIT("}"), &p->status); upb_textprinter_endfield(p); return UPB_CONTINUE; } upb_textprinter *upb_textprinter_new() { - static upb_handlerset handlers = { - NULL, // startmsg - NULL, // endmsg - upb_textprinter_putval, - upb_textprinter_startsubmsg, - upb_textprinter_endsubmsg, - }; upb_textprinter *p = malloc(sizeof(*p)); - upb_byte_init(&p->sink, &upb_textprinter_vtbl); return p; } @@ -114,11 +131,18 @@ void upb_textprinter_free(upb_textprinter *p) { free(p); } -void upb_textprinter_reset(upb_textprinter *p, upb_bytesink *sink, - bool single_line) { +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); } - -upb_sink *upb_textprinter_sink(upb_textprinter *p) { return &p->sink; } diff --git a/stream/upb_textprinter.h b/stream/upb_textprinter.h index b40d9fa..a880626 100644 --- a/stream/upb_textprinter.h +++ b/stream/upb_textprinter.h @@ -18,8 +18,8 @@ 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_bytesink *sink, - bool single_line); +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 -- cgit v1.2.3 From 02a8cdfff29d6a17836847490a06dfe535855d52 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sat, 29 Jan 2011 23:22:33 -0800 Subject: Fixes to decoder, stdio, textprinter. --- core/upb_stream_vtbl.h | 6 ++--- stream/upb_decoder.c | 68 ++++++++++++++++++++++++++++++++---------------- stream/upb_stdio.c | 38 ++++++++++++++++++--------- stream/upb_textprinter.c | 4 +-- tests/test_decoder.c | 10 +++++-- 5 files changed, 85 insertions(+), 41 deletions(-) (limited to 'stream/upb_textprinter.c') diff --git a/core/upb_stream_vtbl.h b/core/upb_stream_vtbl.h index 8e8971f..a6990bc 100644 --- a/core/upb_stream_vtbl.h +++ b/core/upb_stream_vtbl.h @@ -34,10 +34,10 @@ typedef bool (*upb_bytesrc_getstr_fptr)( // upb_bytesink. typedef upb_strlen_t (*upb_bytesink_write_fptr)( upb_bytesink *bytesink, void *buf, upb_strlen_t count); -typedef bool (*upb_bytesink_putstr_fptr)( +typedef upb_strlen_t (*upb_bytesink_putstr_fptr)( upb_bytesink *bytesink, upb_string *str, upb_status *status); typedef upb_strlen_t (*upb_bytesink_vprintf_fptr)( - upb_status *status, const char *fmt, va_list args); + upb_bytesink *bytesink, upb_status *status, const char *fmt, va_list args); // Vtables for the above interfaces. typedef struct { @@ -153,7 +153,7 @@ INLINE upb_status *upb_bytesink_status(upb_bytesink *sink) { INLINE upb_strlen_t upb_bytesink_printf(upb_bytesink *sink, upb_status *status, const char *fmt, ...) { va_list args; va_start(args, fmt); - upb_strlen_t ret = sink->vtbl->vprintf(status, fmt, args); + upb_strlen_t ret = sink->vtbl->vprintf(sink, status, fmt, args); va_end(args); return ret; } diff --git a/stream/upb_decoder.c b/stream/upb_decoder.c index e60915f..a7a2c76 100644 --- a/stream/upb_decoder.c +++ b/stream/upb_decoder.c @@ -18,22 +18,24 @@ // possibilities for optimization/experimentation here. INLINE bool upb_decode_varint_fast(const char **ptr, uint64_t *val, upb_status *status) { + const char *p = *ptr; uint32_t low, high = 0; uint32_t b; - b = *(*ptr++); low = (b & 0x7f) ; if(!(b & 0x80)) goto done; - b = *(*ptr++); low |= (b & 0x7f) << 7; if(!(b & 0x80)) goto done; - b = *(*ptr++); low |= (b & 0x7f) << 14; if(!(b & 0x80)) goto done; - b = *(*ptr++); low |= (b & 0x7f) << 21; if(!(b & 0x80)) goto done; - b = *(*ptr++); low |= (b & 0x7f) << 28; - high = (b & 0x7f) >> 3; if(!(b & 0x80)) goto done; - b = *(*ptr++); high |= (b & 0x7f) << 4; if(!(b & 0x80)) goto done; - b = *(*ptr++); high |= (b & 0x7f) << 11; if(!(b & 0x80)) goto done; - b = *(*ptr++); high |= (b & 0x7f) << 18; if(!(b & 0x80)) goto done; - b = *(*ptr++); high |= (b & 0x7f) << 25; if(!(b & 0x80)) goto done; + 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) >> 3; if(!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7f) << 4; if(!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7f) << 11; if(!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7f) << 18; if(!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7f) << 25; if(!(b & 0x80)) goto done; upb_seterr(status, UPB_ERROR, "Unterminated varint"); return false; done: + *ptr = p; *val = ((uint64_t)high << 32) | low; return true; } @@ -50,7 +52,7 @@ INLINE int64_t upb_zzdec_64(uint64_t n) { return (n >> 1) ^ -(int64_t)(n & 1); } typedef struct { upb_msgdef *msgdef; upb_fielddef *field; - ssize_t end_offset; // For groups, 0. + size_t end_offset; // For groups, 0. } upb_decoder_frame; struct upb_decoder { @@ -73,7 +75,7 @@ struct upb_decoder { upb_string *buf; // The offset within the overall stream represented by the *beginning* of buf. - upb_strlen_t buf_stream_offset; + size_t buf_stream_offset; }; typedef struct { @@ -98,7 +100,7 @@ static upb_flow_t upb_pop(upb_decoder *d); // 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 -1 +#define UPB_GROUP_END_OFFSET 0 #define UPB_MAX_VARINT_ENCODED_SIZE 10 // Called only from the slow path, this function copies the next "len" bytes @@ -132,12 +134,12 @@ static bool upb_getbuf(upb_decoder *d, void *data, size_t bytes_wanted, } // Wait for end-of-submessage or end-of-buffer, whichever comes first. - ssize_t offset_in_buf = s->ptr - upb_string_getrobuf(d->buf); - ssize_t buf_remaining = upb_string_getbufend(d->buf) - s->ptr; - ssize_t submsg_remaining = + size_t offset_in_buf = s->ptr - upb_string_getrobuf(d->buf); + size_t buf_remaining = upb_string_getbufend(d->buf) - s->ptr; + size_t submsg_remaining = d->top->end_offset - d->buf_stream_offset - offset_in_buf; if (d->top->end_offset == UPB_GROUP_END_OFFSET || - buf_remaining > submsg_remaining) { + buf_remaining < submsg_remaining) { s->len = buf_remaining; } else { // Check that non of our subtraction overflowed. @@ -165,13 +167,16 @@ static bool upb_decode_varint_slow(upb_decoder *d, upb_dstate *s, 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_setint64(val, val64); + upb_value_setraw(val, val64); return true; } } @@ -210,7 +215,7 @@ INLINE bool upb_decode_varint(upb_decoder *d, upb_dstate *s, upb_value *val) { 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_setint64(val, val64); + upb_value_setraw(val, val64); return true; } else { return upb_decode_varint_slow(d, s, val); @@ -245,6 +250,7 @@ INLINE bool upb_decode_string(upb_decoder *d, upb_value *val, upb_string **str, if (!upb_getbuf(d, upb_string_getrwbuf(*str, strlen), strlen, s)) return false; } + upb_value_setstr(val, *str); return true; } @@ -259,7 +265,7 @@ INLINE bool upb_check_type(upb_wire_type_t wt, upb_fieldtype_t ft) { } static upb_flow_t upb_push(upb_decoder *d, upb_dstate *s, upb_fielddef *f, - upb_strlen_t submsg_len, upb_fieldtype_t type) { + upb_value submsg_len, upb_fieldtype_t type) { d->top->field = f; d->top++; if(d->top >= d->limit) { @@ -268,7 +274,7 @@ static upb_flow_t upb_push(upb_decoder *d, upb_dstate *s, upb_fielddef *f, } d->top->end_offset = (type == UPB_TYPE(GROUP)) ? UPB_GROUP_END_OFFSET : - d->buf_stream_offset + (s->ptr - upb_string_getrobuf(d->buf)) + submsg_len; + d->buf_stream_offset + (s->ptr - upb_string_getrobuf(d->buf)) + upb_value_getint32(submsg_len); d->top->msgdef = upb_downcast_msgdef(f->def); return upb_dispatch_startsubmsg(&d->dispatcher, f); } @@ -280,6 +286,7 @@ static upb_flow_t upb_pop(upb_decoder *d) { 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. @@ -299,9 +306,14 @@ void upb_decoder_run(upb_src *src, upb_status *status) { 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; } } @@ -352,7 +364,7 @@ void upb_decoder_run(upb_src *src, upb_status *status) { switch (f->type) { case UPB_TYPE(MESSAGE): case UPB_TYPE(GROUP): - CHECK_FLOW(upb_push(d, &state, f, upb_value_getint32(val), f->type)); + 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): @@ -397,9 +409,21 @@ upb_decoder *upb_decoder_new(upb_msgdef *msgdef) { upb_dispatcher_init(&d->dispatcher); d->toplevel_msgdef = msgdef; d->limit = &d->stack[UPB_MAX_NESTING]; + d->buf = NULL; return d; } +void upb_decoder_reset(upb_decoder *d, upb_bytesrc *bytesrc) { + d->bytesrc = bytesrc; + d->top = &d->stack[0]; + d->top->msgdef = d->toplevel_msgdef; + d->top->end_offset = SIZE_MAX; // never want to end top-level message. + upb_string_unref(d->buf); + d->buf = NULL; +} + void upb_decoder_free(upb_decoder *d) { free(d); } + +upb_src *upb_decoder_src(upb_decoder *d) { return &d->src; } diff --git a/stream/upb_stdio.c b/stream/upb_stdio.c index 7923664..8857677 100644 --- a/stream/upb_stdio.c +++ b/stream/upb_stdio.c @@ -23,6 +23,9 @@ 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; @@ -50,18 +53,27 @@ static bool upb_stdio_getstr(upb_bytesrc *src, upb_string *str, return true; } -int32_t upb_stdio_put(upb_bytesink *sink, upb_string *str) { + +/* 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) { - // Error or EOF. - stdio->bytesink.eof = feof(stdio->file); - if(ferror(stdio->file)) { - upb_seterr(&stdio->bytesink.status, UPB_ERROR, - "Error writing to stdio stream."); - return 0; - } + 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; } @@ -72,13 +84,15 @@ upb_stdio *upb_stdio_new() { upb_stdio_getstr, }; - //static upb_bytesink_vtbl bytesink_vtbl = { - // upb_stdio_put - //}; + 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); + upb_bytesink_init(&stdio->bytesink, &bytesink_vtbl); return stdio; } diff --git a/stream/upb_textprinter.c b/stream/upb_textprinter.c index 7025494..531da12 100644 --- a/stream/upb_textprinter.c +++ b/stream/upb_textprinter.c @@ -90,7 +90,7 @@ static upb_flow_t upb_textprinter_value(void *_p, upb_fielddef *f, 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_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; @@ -107,7 +107,7 @@ static upb_flow_t upb_textprinter_startsubmsg(void *_p, upb_fielddef *f, upb_textprinter *p = _p; upb_textprinter_startfield(p, f); p->indent_depth++; - upb_bytesink_putstr(p->bytesink, UPB_STRLIT(" {"), &p->status); + upb_bytesink_putstr(p->bytesink, UPB_STRLIT("{"), &p->status); if(!p->single_line) upb_bytesink_putstr(p->bytesink, UPB_STRLIT("\n"), &p->status); return UPB_CONTINUE; } diff --git a/tests/test_decoder.c b/tests/test_decoder.c index 0e6f19c..ed5a77e 100644 --- a/tests/test_decoder.c +++ b/tests/test_decoder.c @@ -16,13 +16,19 @@ int main() { upb_decoder *d = upb_decoder_new(upb_downcast_msgdef(fds)); upb_decoder_reset(d, upb_stdio_bytesrc(in)); upb_textprinter *p = upb_textprinter_new(); - upb_textprinter_reset(p, upb_stdio_bytesink(out), false); + upb_handlers handlers; + upb_handlers_init(&handlers); + upb_textprinter_reset(p, &handlers, upb_stdio_bytesink(out), false); + upb_src *src = upb_decoder_src(d); + upb_src_sethandlers(src, &handlers); upb_status status = UPB_STATUS_INIT; - upb_streamdata(upb_decoder_src(d), upb_textprinter_sink(p), &status); + upb_src_run(src, &status); + upb_printerr(&status); assert(upb_ok(&status)); + upb_stdio_free(in); upb_stdio_free(out); upb_decoder_free(d); -- cgit v1.2.3 From 9aa7e559d634a3ecf087ee376f82704e2290f478 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sun, 30 Jan 2011 16:28:37 -0800 Subject: Fixes to decoder and textprinter: it works (for some input)! A protobuf -> text stream for descriptor.proto now outputs the same text as proto2. --- stream/upb_decoder.c | 98 ++++++++++++++++++++++++------------------------ stream/upb_textprinter.c | 19 ++++------ tests/test_decoder.c | 8 +++- 3 files changed, 62 insertions(+), 63 deletions(-) (limited to 'stream/upb_textprinter.c') diff --git a/stream/upb_decoder.c b/stream/upb_decoder.c index a7a2c76..3a279a1 100644 --- a/stream/upb_decoder.c +++ b/stream/upb_decoder.c @@ -51,7 +51,6 @@ INLINE int64_t upb_zzdec_64(uint64_t n) { return (n >> 1) ^ -(int64_t)(n & 1); } // upb_decoder_frame is one frame of that stack. typedef struct { upb_msgdef *msgdef; - upb_fielddef *field; size_t end_offset; // For groups, 0. } upb_decoder_frame; @@ -82,29 +81,37 @@ typedef struct { // Our current position in the data buffer. const char *ptr; - // Number of bytes available at ptr, until either end-of-buf or - // end-of-submessage (whichever is smaller). + // 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; } -static upb_flow_t upb_pop(upb_decoder *d); +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); +} -// 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 +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 "buf" and "len" appropriately. +// 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) { @@ -112,41 +119,17 @@ static bool upb_getbuf(upb_decoder *d, void *data, size_t bytes_wanted, memcpy(data, s->ptr, to_copy); upb_dstate_advance(s, to_copy); bytes_wanted -= to_copy; - if (bytes_wanted == 0) return true; - - // Did "len" indicate end-of-submessage or end-of-buffer? - ssize_t buf_offset = - d->buf ? ((const char*)s->ptr - upb_string_getrobuf(d->buf)) : 0; - if (d->top->end_offset > 0 && - d->top->end_offset == d->buf_stream_offset + buf_offset) { - // End-of-submessage. - if (bytes_wanted > 0) { - upb_seterr(d->status, UPB_ERROR, "Bad submessage end."); - return false; - } - if (upb_pop(d) != UPB_CONTINUE) return false; - } else { - // End-of-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); + if (bytes_wanted == 0) { + upb_dstate_setmsgend(d, s); + return true; } - // Wait for end-of-submessage or end-of-buffer, whichever comes first. - size_t offset_in_buf = s->ptr - upb_string_getrobuf(d->buf); - size_t buf_remaining = upb_string_getbufend(d->buf) - s->ptr; - size_t submsg_remaining = - d->top->end_offset - d->buf_stream_offset - offset_in_buf; - if (d->top->end_offset == UPB_GROUP_END_OFFSET || - buf_remaining < submsg_remaining) { - s->len = buf_remaining; - } else { - // Check that non of our subtraction overflowed. - assert(d->top->end_offset > d->buf_stream_offset); - assert(d->top->end_offset - d->buf_stream_offset > offset_in_buf); - s->len = submsg_remaining; - } + // 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); } } @@ -266,7 +249,6 @@ INLINE bool upb_check_type(upb_wire_type_t wt, upb_fieldtype_t ft) { 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->field = f; d->top++; if(d->top >= d->limit) { upb_seterr(d->status, UPB_ERROR, "Nesting too deep."); @@ -274,13 +256,16 @@ static upb_flow_t upb_push(upb_decoder *d, upb_dstate *s, upb_fielddef *f, } 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->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) { +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); } @@ -290,7 +275,7 @@ void upb_decoder_run(upb_src *src, upb_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, 0, d->top->msgdef}; + upb_dstate state = {NULL, (void*)0x1, 0, d->top->msgdef}; upb_string *str = NULL; // TODO: handle UPB_SKIPSUBMSG @@ -301,6 +286,15 @@ void upb_decoder_run(upb_src *src, upb_status *status) { // 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)) { @@ -308,6 +302,7 @@ void upb_decoder_run(upb_src *src, upb_status *status) { // Normal end-of-file. upb_clearerr(status); CHECK_FLOW(upb_dispatch_endmsg(&d->dispatcher)); + upb_string_unref(str); return; } else { if (status->code == UPB_EOF) { @@ -322,12 +317,14 @@ void upb_decoder_run(upb_src *src, upb_status *status) { // 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)); + CHECK_FLOW(upb_pop(d, &state)); continue; // We have no value to dispatch. case UPB_WIRE_TYPE_VARINT: case UPB_WIRE_TYPE_DELIMITED: @@ -383,6 +380,7 @@ void upb_decoder_run(upb_src *src, upb_status *status) { } err: + upb_string_unref(str); if (upb_ok(status)) { upb_seterr(status, UPB_ERROR, "Callback returned UPB_BREAK"); } @@ -417,12 +415,14 @@ void upb_decoder_reset(upb_decoder *d, upb_bytesrc *bytesrc) { d->bytesrc = bytesrc; d->top = &d->stack[0]; d->top->msgdef = d->toplevel_msgdef; - d->top->end_offset = SIZE_MAX; // never want to end top-level message. + // Never want to end top-level message, so treat it like a group. + d->top->end_offset = UPB_GROUP_END_OFFSET; upb_string_unref(d->buf); d->buf = NULL; } void upb_decoder_free(upb_decoder *d) { + upb_string_unref(d->buf); free(d); } diff --git a/stream/upb_textprinter.c b/stream/upb_textprinter.c index 531da12..894a1ea 100644 --- a/stream/upb_textprinter.c +++ b/stream/upb_textprinter.c @@ -30,14 +30,6 @@ err: return -1; } -static int upb_textprinter_startfield(upb_textprinter *p, upb_fielddef *f) { - upb_textprinter_indent(p); - CHECK(upb_bytesink_printf(p->bytesink, &p->status, UPB_STRFMT ": ", UPB_STRARG(f->name))); - 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)); @@ -52,7 +44,8 @@ err: static upb_flow_t upb_textprinter_value(void *_p, upb_fielddef *f, upb_value val) { upb_textprinter *p = _p; - upb_textprinter_startfield(p, f); + 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) { @@ -105,11 +98,13 @@ 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_startfield(p, f); - p->indent_depth++; - upb_bytesink_putstr(p->bytesink, UPB_STRLIT("{"), &p->status); + 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) diff --git a/tests/test_decoder.c b/tests/test_decoder.c index ed5a77e..f48472d 100644 --- a/tests/test_decoder.c +++ b/tests/test_decoder.c @@ -25,14 +25,18 @@ int main() { upb_status status = UPB_STATUS_INIT; upb_src_run(src, &status); - upb_printerr(&status); assert(upb_ok(&status)); - + upb_status_uninit(&status); upb_stdio_free(in); upb_stdio_free(out); upb_decoder_free(d); upb_textprinter_free(p); upb_def_unref(fds); upb_symtab_unref(symtab); + + // Prevent C library from holding buffers open, so Valgrind doesn't see + // memory leaks. + fclose(stdin); + fclose(stdout); } -- cgit v1.2.3