summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2009-07-21 17:40:52 -0700
committerJoshua Haberman <joshua@reverberate.org>2009-07-21 17:40:52 -0700
commitc9105bbf58b7c98058ca2d2fe5dd7cd87e1554c7 (patch)
tree159f656b422fb70cb7a57cb31be2b42c9386a8c2 /src
parenta1a9596d02f5297d60448edac994c2bcb56edc4a (diff)
Support for dumping protobufs in text format.
Diffstat (limited to 'src')
-rw-r--r--src/upb_text.c133
-rw-r--r--src/upb_text.h37
2 files changed, 170 insertions, 0 deletions
diff --git a/src/upb_text.c b/src/upb_text.c
new file mode 100644
index 0000000..d51db06
--- /dev/null
+++ b/src/upb_text.c
@@ -0,0 +1,133 @@
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2009 Joshua Haberman. See LICENSE for details.
+ */
+
+#include <inttypes.h>
+#include "upb_text.h"
+#include "descriptor.h"
+
+void upb_text_printval(upb_field_type_t type, union upb_value_ptr p, FILE *file)
+{
+#define CASE(fmtstr, member) fprintf(file, fmtstr, *p.member); break;
+ switch(type) {
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_DOUBLE:
+ CASE("%0.f", _double);
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FLOAT:
+ CASE("%0.f", _float)
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT64:
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SFIXED64:
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SINT64:
+ CASE("%" PRId64, int64)
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_UINT64:
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FIXED64:
+ CASE("%" PRIu64, uint64)
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32:
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SFIXED32:
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SINT32:
+ CASE("%" PRId32, int32)
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_UINT32:
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FIXED32:
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_ENUM:
+ CASE("%" PRIu32, uint32);
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_BOOL:
+ CASE("%hhu", _bool);
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_STRING:
+ case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_BYTES:
+ /* TODO: escaping. */
+ fprintf(file, "\"" UPB_STRFMT "\"", UPB_STRARG(**p.str)); break;
+ }
+}
+
+static void print_indent(struct upb_text_printer *p, FILE *stream)
+{
+ if(!p->single_line)
+ for(int i = 0; i < p->indent_depth; i++)
+ fprintf(stream, " ");
+}
+
+void upb_text_printfield(struct upb_text_printer *p,
+ struct upb_string name,
+ upb_field_type_t valtype, union upb_value_ptr val,
+ FILE *stream)
+{
+ print_indent(p, stream);
+ fprintf(stream, UPB_STRFMT ":", UPB_STRARG(name));
+ upb_text_printval(valtype, val, stream);
+ if(p->single_line)
+ fputc(' ', stream);
+ else
+ fputc('\n', stream);
+}
+
+void upb_text_push(struct upb_text_printer *p,
+ struct upb_string submsg_type,
+ FILE *stream)
+{
+ print_indent(p, stream);
+ fprintf(stream, UPB_STRFMT " {", UPB_STRARG(submsg_type));
+ if(!p->single_line) fputc('\n', stream);
+ p->indent_depth++;
+}
+
+void upb_text_pop(struct upb_text_printer *p,
+ FILE *stream)
+{
+ p->indent_depth--;
+ print_indent(p, stream);
+ fprintf(stream, "}\n");
+}
+
+#if 0
+bool upb_array_eql(struct upb_array *arr1, struct upb_array *arr2,
+ struct upb_msg_field *f, bool recursive)
+{
+ if(arr1->len != arr2->len) return false;
+ if(upb_issubmsg(f)) {
+ if(!recursive) return true;
+ for(uint32_t i = 0; i < arr1->len; i++)
+ if(!upb_msg_eql(arr1->elements.msg[i], arr2->elements.msg[i],
+ f->ref.msg, recursive))
+ return false;
+ } else if(upb_isstring(f)) {
+ for(uint32_t i = 0; i < arr1->len; i++)
+ if(!upb_streql(arr1->elements.str[i], arr2->elements.str[i]))
+ return false;
+ } else {
+ /* For primitive types we can compare the memory directly. */
+ return memcmp(arr1->elements._void, arr2->elements._void,
+ arr1->len * upb_type_info[f->type].size) == 0;
+ }
+ return true;
+}
+
+ void *data1, struct upb_msg *m, bool single_line)
+ /* Must have the same fields set. TODO: is this wrong? Should we also
+ * consider absent defaults equal to explicitly set defaults? */
+ if(memcmp(data1, data2, m->set_flags_bytes) != 0)
+ return false;
+
+ /* Possible optimization: create a mask of the bytes in the messages that
+ * contain only primitive values (not strings, arrays, submessages, or
+ * padding) and memcmp the masked messages. */
+
+ for(uint32_t i = 0; i < m->num_fields; i++) {
+ struct upb_msg_field *f = &m->fields[i];
+ if(!upb_msg_is_set(data1, f)) continue;
+ union upb_value_ptr p1 = upb_msg_getptr(data1, f);
+ union upb_value_ptr p2 = upb_msg_getptr(data2, f);
+ if(f->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REPEATED) {
+ if(!upb_array_eql(*p1.arr, *p2.arr, f, recursive)) return false;
+ } else {
+ if(upb_issubmsg(f)) {
+ if(recursive && !upb_msg_eql(p1.msg, p2.msg, f->ref.msg, recursive))
+ return false;
+ } else if(!upb_value_eql(p1, p2, f->type)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+#endif
diff --git a/src/upb_text.h b/src/upb_text.h
new file mode 100644
index 0000000..b1dbf59
--- /dev/null
+++ b/src/upb_text.h
@@ -0,0 +1,37 @@
+/*
+ * 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.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct upb_text_printer {
+ int indent_depth;
+ bool single_line;
+};
+
+INLINE void upb_text_printer_init(struct upb_text_printer *p, bool single_line) {
+ p->indent_depth = 0;
+ p->single_line = single_line;
+}
+void upb_text_printval(upb_field_type_t type, union upb_value_ptr p, FILE *file);
+void upb_text_printfield(struct upb_text_printer *p, struct upb_string name,
+ upb_field_type_t valtype, union upb_value_ptr val,
+ FILE *stream);
+void upb_text_push(struct upb_text_printer *p, struct upb_string submsg_type,
+ FILE *stream);
+void upb_text_pop(struct upb_text_printer *p, FILE *stream);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* UPB_TEXT_H_ */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback