static bool write_repeated_varint(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) { return pb_encode_tag_for_field(stream, field) && pb_encode_varint(stream, 0) && pb_encode_tag_for_field(stream, field) && pb_encode_varint(stream, 0) && pb_encode_tag_for_field(stream, field) && pb_encode_varint(stream, 0) && pb_encode_tag_for_field(stream, field) && pb_encode_varint(stream, 0) && pb_encode_tag_for_field(stream, field) && pb_encode_varint(stream, (long)*arg); }
static int checkreturn pb_encode_array(pb_ostream_t *stream, const json_t *gprotos, const json_t *protos, const json_t *proto, json_t *array) { json_t *type = json_object_get(proto, "type"); const char *type_text = json_string_value(type); size_t len = json_array_size(array); size_t i; // simple msg if (pb__get_type(type_text) && pb__get_type(type_text) != PB_string) { if (!pb_encode_tag_for_field(stream, proto)) { return 0; } if (!pb_encode_varint(stream, len)) { return 0; } for (i = 0; i < len; i++) { if (!pb_encode_proto(stream, gprotos, protos, proto, json_array_get(array, i))) { return 0; } } } else { for (i = 0; i < len; i++) { if (!pb_encode_tag_for_field(stream, proto)) { return 0; } if (!pb_encode_proto(stream, gprotos, protos, proto, json_array_get(array, i))) { return 0; } } } return 1; }
/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */ static int pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size) { if (!pb_encode_varint(stream, (uint64_t) size)) return 0; return pb_write(stream, buffer, size); }
static int pb_encode_array(pb_ostream_t *stream, const pc_JSON *gprotos, const pc_JSON *protos, const pc_JSON *proto, pc_JSON *array) { pc_JSON *type = pc_JSON_GetObjectItem(proto, "type"); const char *type_text = type->valuestring; size_t len = pc_JSON_GetArraySize(array); size_t i; /* simple msg */ if (pb_get_type(type_text) && pb_get_type(type_text) != PB_string) { if (!pb_encode_tag_for_field(stream, proto)) { return 0; } if (!pb_encode_varint(stream, len)) { return 0; } for (i = 0; i < len; i++) { if (!pb_encode_proto(stream, gprotos, protos, proto, pc_JSON_GetArrayItem(array, i))) { return 0; } } } else { for (i = 0; i < len; i++) { if (!pb_encode_tag_for_field(stream, proto)) { return 0; } if (!pb_encode_proto(stream, gprotos, protos, proto, pc_JSON_GetArrayItem(array, i))) { return 0; } } } return 1; }
bool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size) { if (!pb_encode_varint(stream, (uint64_t)size)) return false; return pb_write(stream, buffer, size); }
void encode(thinger_message& message){ if(message.get_stream_id()!=0){ pb_encode_varint(thinger_message::STREAM_ID, message.get_stream_id()); } if(message.get_signal_flag()!=thinger_message::NONE){ pb_encode_varint(thinger_message::SIGNAL_FLAG, message.get_signal_flag()); } if(message.has_resource()){ pb_encode_tag(protoson::pson_type, thinger_message::RESOURCE); protoson::pson_encoder::encode(message.get_resources()); } if(message.has_data()){ pb_encode_tag(protoson::pson_type, thinger_message::PSON_PAYLOAD); protoson::pson_encoder::encode((protoson::pson&) message); } }
/* Encode an integer in the zig-zagged svarint format. * This works for sint32 and sint64. */ static int pb_encode_svarint(pb_ostream_t *stream, int64_t value) { uint64_t zigzagged; if (value < 0) zigzagged = (uint64_t)(~(value << 1)); else zigzagged = (uint64_t)(value << 1); return pb_encode_varint(stream, zigzagged); }
bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value) { uint64_t zigzagged; if (value < 0) zigzagged = ~((uint64_t)value << 1); else zigzagged = (uint64_t)value << 1; return pb_encode_varint(stream, zigzagged); }
static bool write_repeated_fixed64(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) { uint64_t dummy = 0; /* Make it a packed field */ return pb_encode_tag(stream, PB_WT_STRING, field->tag) && pb_encode_varint(stream, 5 * 8) && /* Number of bytes */ pb_encode_fixed64(stream, &dummy) && pb_encode_fixed64(stream, &dummy) && pb_encode_fixed64(stream, &dummy) && pb_encode_fixed64(stream, &dummy) && pb_encode_fixed64(stream, *arg); }
static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) { uint64_t value = 0; switch (field->data_size) { case 4: value = *(const uint32_t*)src; break; case 8: value = *(const uint64_t*)src; break; default: PB_RETURN_ERROR(stream, "invalid data_size"); } return pb_encode_varint(stream, value); }
bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) { /* First calculate the message size using a non-writing substream. */ pb_ostream_t substream = PB_OSTREAM_SIZING; size_t size; bool status; if (!pb_encode(&substream, fields, src_struct)) { #ifndef PB_NO_ERRMSG stream->errmsg = substream.errmsg; #endif return false; } size = substream.bytes_written; if (!pb_encode_varint(stream, (uint64_t)size)) return false; if (stream->callback == NULL) return pb_write(stream, NULL, size); /* Just sizing */ if (stream->bytes_written + size > stream->max_size) PB_RETURN_ERROR(stream, "stream full"); /* Use a substream to verify that a callback doesn't write more than * what it did the first time. */ substream.callback = stream->callback; substream.state = stream->state; substream.max_size = size; substream.bytes_written = 0; #ifndef PB_NO_ERRMSG substream.errmsg = NULL; #endif status = pb_encode(&substream, fields, src_struct); stream->bytes_written += substream.bytes_written; stream->state = substream.state; #ifndef PB_NO_ERRMSG stream->errmsg = substream.errmsg; #endif if (substream.bytes_written != size) PB_RETURN_ERROR(stream, "submsg size changed"); return status; }
bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) { uint64_t value = 0; switch (field->data_size) { case 1: value = *(const uint8_t*)src; break; case 2: value = *(const uint16_t*)src; break; case 4: value = *(const uint32_t*)src; break; case 8: value = *(const uint64_t*)src; break; default: return false; } return pb_encode_varint(stream, value); }
bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) { uint64_t value = 0; uint64_t zigzagged; uint64_t signbitmask, xormask; endian_copy(&value, src, sizeof(value), field->data_size); signbitmask = (uint64_t)0x80 << (field->data_size * 8 - 8); xormask = ((uint64_t)-1) >> (64 - field->data_size * 8); if (value & signbitmask) zigzagged = ((value ^ xormask) << 1) | 1; else zigzagged = value << 1; return pb_encode_varint(stream, zigzagged); }
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) { int64_t value = 0; /* Cases 1 and 2 are for compilers that have smaller types for bool * or enums, and for int_size option. */ switch (field->data_size) { case 1: value = *(const int8_t*)src; break; case 2: value = *(const int16_t*)src; break; case 4: value = *(const int32_t*)src; break; case 8: value = *(const int64_t*)src; break; default: PB_RETURN_ERROR(stream, "invalid data_size"); } return pb_encode_varint(stream, (uint64_t)value); }
static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) { uint64_t value = 0; if (field->data_size == sizeof(uint_least8_t)) value = *(const uint_least8_t*)src; else if (field->data_size == sizeof(uint_least16_t)) value = *(const uint_least16_t*)src; else if (field->data_size == sizeof(uint32_t)) value = *(const uint32_t*)src; else if (field->data_size == sizeof(uint64_t)) value = *(const uint64_t*)src; else PB_RETURN_ERROR(stream, "invalid data_size"); return pb_encode_varint(stream, value); }
/* Eecode submessage in __messages protos */ static int pb_encode_submessage(pb_ostream_t *stream, const pc_JSON *gprotos, const pc_JSON *protos, pc_JSON *value) { /* First calculate the message size using a non-writing substream. */ pb_ostream_t substream = { 0, 0, 0, 0 }; size_t size; int status; if (!pb_encode(&substream, gprotos, protos, value)) { return 0; } size = substream.bytes_written; if (!pb_encode_varint(stream, (uint64_t) size)) { return 0; } if (stream->callback == NULL ) return pb_write(stream, NULL, size); /* Just sizing */ if (stream->bytes_written + size > stream->max_size) return 0; /* Use a substream to verify that a callback doesn't write more than * what it did the first time. */ substream.callback = stream->callback; substream.state = stream->state; substream.max_size = size; substream.bytes_written = 0; status = pb_encode(&substream, gprotos, protos, value); stream->bytes_written += substream.bytes_written; stream->state = substream.state; if (substream.bytes_written != size) { return 0; } return status; }
bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src) { pb_ostream_t substream = {0}; size_t size; bool status; if (field->ptr == NULL) return false; if (!pb_encode(&substream, (pb_field_t*)field->ptr, src)) return false; size = substream.bytes_written; if (!pb_encode_varint(stream, size)) return false; if (stream->callback == NULL) return pb_write(stream, NULL, size); /* Just sizing */ if (stream->bytes_written + size > stream->max_size) return false; /* Use a substream to verify that a callback doesn't write more than * what it did the first time. */ substream.callback = stream->callback; substream.state = stream->state; substream.max_size = size; substream.bytes_written = 0; status = pb_encode(&substream, (pb_field_t*)field->ptr, src); stream->bytes_written += substream.bytes_written; if (substream.bytes_written != size) return false; return status; }
bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) { /* First calculate the message size using a non-writing substream. */ pb_ostream_t substream = {0,0,0,0}; size_t size; bool status; if (!pb_encode(&substream, fields, src_struct)) return false; size = substream.bytes_written; if (!pb_encode_varint(stream, (uint64_t)size)) return false; if (stream->callback == NULL) return pb_write(stream, NULL, size); /* Just sizing */ if (stream->bytes_written + size > stream->max_size) return false; /* Use a substream to verify that a callback doesn't write more than * what it did the first time. */ substream.callback = stream->callback; substream.state = stream->state; substream.max_size = size; substream.bytes_written = 0; status = pb_encode(&substream, fields, src_struct); stream->bytes_written += substream.bytes_written; stream->state = substream.state; if (substream.bytes_written != size) return false; return status; }
/* Encode a static array. Handles the size calculations and possible packing. */ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func) { size_t i; const void *p; size_t size; if (count == 0) return true; if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) PB_RETURN_ERROR(stream, "array max size exceeded"); /* We always pack arrays if the datatype allows it. */ if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) { if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) return false; /* Determine the total size of packed array. */ if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) { size = 4 * count; } else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) { size = 8 * count; } else { pb_ostream_t sizestream = PB_OSTREAM_SIZING; p = pData; for (i = 0; i < count; i++) { if (!func(&sizestream, field, p)) return false; p = (const char*)p + field->data_size; } size = sizestream.bytes_written; } if (!pb_encode_varint(stream, (uint64_t)size)) return false; if (stream->callback == NULL) return pb_write(stream, NULL, size); /* Just sizing.. */ /* Write the data */ p = pData; for (i = 0; i < count; i++) { if (!func(stream, field, p)) return false; p = (const char*)p + field->data_size; } } else { p = pData; for (i = 0; i < count; i++) { if (!pb_encode_tag_for_field(stream, field)) return false; /* Normally the data is stored directly in the array entries, but * for pointer-type string and bytes fields, the array entries are * actually pointers themselves also. So we have to dereference once * more to get to the actual data. */ if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && (PB_LTYPE(field->type) == PB_LTYPE_STRING || PB_LTYPE(field->type) == PB_LTYPE_BYTES)) { if (!func(stream, field, *(const void* const*)p)) return false; } else { if (!func(stream, field, p)) return false; } p = (const char*)p + field->data_size; } } return true; }
static int checkreturn pb_encode_proto(pb_ostream_t *stream, const json_t *gprotos, const json_t *protos, const json_t *proto, json_t *value) { json_t *_messages; json_t *_type = json_object_get(proto, "type"); json_t *sub_msg; const char *type = json_string_value(_type); const char *str; json_int_t int_val; float float_val; double double_val; int length; _messages = json_object_get(protos, "__messages"); switch (pb__get_type(type)) { case PB_uInt32: int_val = json_number_value(value); if (!pb_encode_varint(stream, int_val)) { return 0; } break; case PB_int32: case PB_sInt32: int_val = json_number_value(value); if (!pb_encode_svarint(stream, int_val)) { return 0; } break; case PB_float: float_val = json_number_value(value); if (!pb_encode_fixed32(stream, &float_val)) { return 0; } break; case PB_double: double_val = json_number_value(value); if (!pb_encode_fixed64(stream, &double_val)) { return 0; } break; case PB_string: str = json_string_value(value); length = strlen(str); if (!pb_encode_string(stream, (const uint8_t *)str, length)) { return 0; } break; default: if (_messages) { sub_msg = json_object_get(_messages, type); if (!sub_msg) { // check root msg in gprotos const char *head = "message "; char *head_text = (char *)pc_jsonp_malloc(strlen(head) + strlen(type) + 1); memset(head_text, 0, sizeof(head_text)); strcpy(head_text, head); strcat(head_text, type); sub_msg = json_object_get(gprotos, head_text); pc_jsonp_free(head_text); } if (sub_msg) { if (!pb_encode_submessage(stream, gprotos, sub_msg, value)) { return 0; } } else { return 0; } } } return 1; }
/* Encode field header by manually specifing wire type. You need to use this if * you want to write out packed arrays from a callback field. */ static int pb_encode_tag(pb_ostream_t *stream, int wiretype, uint32_t field_number) { uint64_t tag = wiretype | (field_number << 3); return pb_encode_varint(stream, tag); }
bool micropb_encode<int64_t, nullptr>(pb_ostream_t *stream, int64_t* arg) { // Yes, this looks dodgy, and yes, this is what the docs say to do: // https://jpa.kapsi.fi/nanopb/docs/reference.html#pb-encode-varint return pb_encode_varint(stream, *reinterpret_cast<uint64_t*>(arg)); }
static int pb_encode_proto(pb_ostream_t *stream, const pc_JSON *gprotos, const pc_JSON *protos, const pc_JSON *proto, pc_JSON *value) { pc_JSON *_messages; pc_JSON *_type = pc_JSON_GetObjectItem(proto, "type"); pc_JSON *sub_msg; const char *type = _type->valuestring; const char *str; int int_val; float float_val; double double_val; int length; _messages = pc_JSON_GetObjectItem(protos, "__messages"); switch (pb_get_type(type)) { case PB_uInt32: int_val = value->valueint; if (!pb_encode_varint(stream, int_val)) { return 0; } break; case PB_int32: case PB_sInt32: int_val = value->valueint; if (!pb_encode_svarint(stream, int_val)) { return 0; } break; case PB_float: float_val = (float)value->valuedouble; if (!pb_encode_fixed32(stream, &float_val)) { return 0; } break; case PB_double: double_val = value->valuedouble; if (!pb_encode_fixed64(stream, &double_val)) { return 0; } break; case PB_string: str = value->valuestring; length = strlen(str); if (!pb_encode_string(stream, (const uint8_t *)str, length)) { return 0; } break; default: if (_messages) { sub_msg = pc_JSON_GetObjectItem(_messages, type); if (!sub_msg) { /* check root msg in gprotos */ const char *head = "message "; size_t len = strlen(head) + strlen(type) + 1; char *head_text = (char *)malloc(len); memset(head_text, 0, len); strcpy(head_text, head); strcat(head_text, type); sub_msg = pc_JSON_GetObjectItem(gprotos, head_text); free(head_text); } if (sub_msg) { if (!pb_encode_submessage(stream, gprotos, sub_msg, value)) { return 0; } } else { return 0; } } } return 1; }
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, int field_number) { int tag = wiretype | (field_number << 3); return pb_encode_varint(stream, tag); }
bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) { uint64_t value = 0; endian_copy(&value, src, sizeof(value), field->data_size); return pb_encode_varint(stream, value); }
/* Callbacks don't need this function because they usually know the data type * without examining the field structure. * Therefore it is static for now. */ static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func) { size_t i; const void *p; size_t size; if (count == 0) return true; if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) { if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) return false; /* Determine the total size of packed array. */ if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) { size = 4 * count; } else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) { size = 8 * count; } else { pb_ostream_t sizestream = {0,0,0,0}; p = pData; for (i = 0; i < count; i++) { if (!func(&sizestream, field, p)) return false; p = (const char*)p + field->data_size; } size = sizestream.bytes_written; } if (!pb_encode_varint(stream, (uint64_t)size)) return false; if (stream->callback == NULL) return pb_write(stream, NULL, size); /* Just sizing.. */ /* Write the data */ p = pData; for (i = 0; i < count; i++) { if (!func(stream, field, p)) return false; p = (const char*)p + field->data_size; } } else { p = pData; for (i = 0; i < count; i++) { if (!pb_encode_tag_for_field(stream, field)) return false; if (!func(stream, field, p)) return false; p = (const char*)p + field->data_size; } } return true; }
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) { uint64_t tag = ((uint64_t)field_number << 3) | wiretype; return pb_encode_varint(stream, tag); }