parent
a1a9596d02
commit
c9105bbf58
2 changed files with 170 additions and 0 deletions
@ -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 |
@ -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_ */ |
Loading…
Reference in new issue