Compare commits
27 Commits
nanopb-0.1
...
maintenanc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62bbe46a45 | ||
|
|
411db5b450 | ||
|
|
29479a7cca | ||
|
|
5b536d40a1 | ||
|
|
4cc3372b03 | ||
|
|
22e0a78e5e | ||
|
|
c1bd1a6ad3 | ||
|
|
e7bf063abc | ||
|
|
47b10ec0ab | ||
|
|
4b7ddabbcf | ||
|
|
c3729599b0 | ||
|
|
4f379364b3 | ||
|
|
d23939d688 | ||
|
|
4ba6a3027d | ||
|
|
39b8a5e2bb | ||
|
|
c372ebc665 | ||
|
|
38ced18639 | ||
|
|
e4b55179d1 | ||
|
|
2392d25574 | ||
|
|
eab4151a99 | ||
|
|
8e840cc81a | ||
|
|
88eba4bc27 | ||
|
|
d32d322658 | ||
|
|
b9baec6b4c | ||
|
|
d2c1604d6d | ||
|
|
93ffe14a0a | ||
|
|
bb5dc04584 |
17
CHANGELOG
17
CHANGELOG
@@ -1,3 +1,20 @@
|
|||||||
|
nanopb-0.1.9.1
|
||||||
|
Fix security issue due to size_t overflows. (issue 132)
|
||||||
|
|
||||||
|
NOTE: nanopb-0.1.x is and will remain affected by issue 97.
|
||||||
|
A fix would be too intrusive for a support release.
|
||||||
|
|
||||||
|
nanopb-0.1.9
|
||||||
|
Fixed error message bugs (issues 52, 56)
|
||||||
|
Sanitize #ifndef filename (issue 50)
|
||||||
|
Performance improvements
|
||||||
|
Add compile-time option PB_BUFFER_ONLY
|
||||||
|
Add Java package name to nanopb.proto
|
||||||
|
Check for sizeof(double) == 8 (issue 54)
|
||||||
|
Added generator option to ignore some fields. (issue 51)
|
||||||
|
Added generator option to make message structs packed. (issue 49)
|
||||||
|
Add more test cases.
|
||||||
|
|
||||||
nanopb-0.1.8
|
nanopb-0.1.8
|
||||||
Fix bugs in the enum short names introduced in 0.1.7 (issues 42, 43)
|
Fix bugs in the enum short names introduced in 0.1.7 (issues 42, 43)
|
||||||
Fix STATIC_ASSERT macro when using multiple .proto files. (issue 41)
|
Fix STATIC_ASSERT macro when using multiple .proto files. (issue 41)
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ PB_FIELD_32BIT Add support for tag numbers > 65535 and fields la
|
|||||||
Increases code size 9 bytes per each field. Compiler error will tell if you need this.
|
Increases code size 9 bytes per each field. Compiler error will tell if you need this.
|
||||||
PB_NO_ERRMSG Disables the support for error messages; only error information is the true/false return value.
|
PB_NO_ERRMSG Disables the support for error messages; only error information is the true/false return value.
|
||||||
Decreases the code size by a few hundred bytes.
|
Decreases the code size by a few hundred bytes.
|
||||||
|
PB_BUFFER_ONLY Disables the support for custom streams. Only supports encoding to memory buffers.
|
||||||
|
Speeds up execution and decreases code size slightly.
|
||||||
============================ ================================================================================================
|
============================ ================================================================================================
|
||||||
|
|
||||||
The PB_MAX_REQUIRED_FIELDS, PB_FIELD_16BIT and PB_FIELD_32BIT settings allow raising some datatype limits to suit larger messages.
|
The PB_MAX_REQUIRED_FIELDS, PB_FIELD_16BIT and PB_FIELD_32BIT settings allow raising some datatype limits to suit larger messages.
|
||||||
|
|||||||
22
example_avr_double/Makefile
Normal file
22
example_avr_double/Makefile
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
CFLAGS=-Wall -Werror -I .. -g -O0
|
||||||
|
DEPS=double_conversion.c ../pb_decode.c ../pb_decode.h ../pb_encode.c ../pb_encode.h ../pb.h
|
||||||
|
|
||||||
|
all: run_tests
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f test_conversions encode_double decode_double doubleproto.pb.c doubleproto.pb.h
|
||||||
|
|
||||||
|
test_conversions: test_conversions.c double_conversion.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
%: %.c $(DEPS) doubleproto.pb.h doubleproto.pb.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $< double_conversion.c ../pb_decode.c ../pb_encode.c doubleproto.pb.c
|
||||||
|
|
||||||
|
doubleproto.pb.c doubleproto.pb.h: doubleproto.proto ../generator/nanopb_generator.py
|
||||||
|
protoc -I. -I../generator -I/usr/include -odoubleproto.pb $<
|
||||||
|
python ../generator/nanopb_generator.py doubleproto.pb
|
||||||
|
|
||||||
|
run_tests: test_conversions encode_double decode_double
|
||||||
|
./test_conversions
|
||||||
|
./encode_double | ./decode_double
|
||||||
|
|
||||||
22
example_avr_double/README.txt
Normal file
22
example_avr_double/README.txt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Some processors/compilers, such as AVR-GCC, do not support the double
|
||||||
|
datatype. Instead, they have sizeof(double) == 4. Because protocol
|
||||||
|
binary format uses the double encoding directly, this causes trouble
|
||||||
|
if the protocol in .proto requires double fields.
|
||||||
|
|
||||||
|
This directory contains a solution to this problem. It uses uint64_t
|
||||||
|
to store the raw wire values, because its size is correct on all
|
||||||
|
platforms. The file double_conversion.c provides functions that
|
||||||
|
convert these values to/from floats, without relying on compiler
|
||||||
|
support.
|
||||||
|
|
||||||
|
To use this method, you need to make two modifications to your code:
|
||||||
|
|
||||||
|
1) Change all 'double' fields into 'fixed64' in the .proto.
|
||||||
|
|
||||||
|
2) Whenever writing to a 'double' field, use float_to_double().
|
||||||
|
|
||||||
|
3) Whenever reading a 'double' field, use double_to_float().
|
||||||
|
|
||||||
|
The conversion routines should be as accurate as the float datatype can
|
||||||
|
be. Furthermore, they should handle all special values (NaN, inf, denormalized
|
||||||
|
numbers) correctly. There are testcases in test_conversions.c.
|
||||||
33
example_avr_double/decode_double.c
Normal file
33
example_avr_double/decode_double.c
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* Decodes a double value into a float variable.
|
||||||
|
* Used to read double values with AVR code, which doesn't support double directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <pb_decode.h>
|
||||||
|
#include "double_conversion.h"
|
||||||
|
#include "doubleproto.pb.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
uint8_t buffer[32];
|
||||||
|
size_t count = fread(buffer, 1, sizeof(buffer), stdin);
|
||||||
|
pb_istream_t stream = pb_istream_from_buffer(buffer, count);
|
||||||
|
|
||||||
|
AVRDoubleMessage message;
|
||||||
|
pb_decode(&stream, AVRDoubleMessage_fields, &message);
|
||||||
|
|
||||||
|
float v1 = double_to_float(message.field1);
|
||||||
|
float v2 = double_to_float(message.field2);
|
||||||
|
|
||||||
|
printf("Values: %f %f\n", v1, v2);
|
||||||
|
|
||||||
|
if (v1 == 1234.5678f &&
|
||||||
|
v2 == 0.00001f)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
123
example_avr_double/double_conversion.c
Normal file
123
example_avr_double/double_conversion.c
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/* Conversion routines for platforms that do not support 'double' directly. */
|
||||||
|
|
||||||
|
#include "double_conversion.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
float f;
|
||||||
|
uint32_t i;
|
||||||
|
} conversion_t;
|
||||||
|
|
||||||
|
/* Note: IEE 754 standard specifies float formats as follows:
|
||||||
|
* Single precision: sign, 8-bit exp, 23-bit frac.
|
||||||
|
* Double precision: sign, 11-bit exp, 52-bit frac.
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint64_t float_to_double(float value)
|
||||||
|
{
|
||||||
|
conversion_t in;
|
||||||
|
in.f = value;
|
||||||
|
uint8_t sign;
|
||||||
|
int16_t exponent;
|
||||||
|
uint64_t mantissa;
|
||||||
|
|
||||||
|
/* Decompose input value */
|
||||||
|
sign = (in.i >> 31) & 1;
|
||||||
|
exponent = ((in.i >> 23) & 0xFF) - 127;
|
||||||
|
mantissa = in.i & 0x7FFFFF;
|
||||||
|
|
||||||
|
if (exponent == 128)
|
||||||
|
{
|
||||||
|
/* Special value (NaN etc.) */
|
||||||
|
exponent = 1024;
|
||||||
|
}
|
||||||
|
else if (exponent == -127)
|
||||||
|
{
|
||||||
|
if (!mantissa)
|
||||||
|
{
|
||||||
|
/* Zero */
|
||||||
|
exponent = -1023;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Denormalized */
|
||||||
|
mantissa <<= 1;
|
||||||
|
while (!(mantissa & 0x800000))
|
||||||
|
{
|
||||||
|
mantissa <<= 1;
|
||||||
|
exponent--;
|
||||||
|
}
|
||||||
|
mantissa &= 0x7FFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Combine fields */
|
||||||
|
mantissa <<= 29;
|
||||||
|
mantissa |= (uint64_t)(exponent + 1023) << 52;
|
||||||
|
mantissa |= (uint64_t)sign << 63;
|
||||||
|
|
||||||
|
return mantissa;
|
||||||
|
}
|
||||||
|
|
||||||
|
float double_to_float(uint64_t value)
|
||||||
|
{
|
||||||
|
uint8_t sign;
|
||||||
|
int16_t exponent;
|
||||||
|
uint32_t mantissa;
|
||||||
|
conversion_t out;
|
||||||
|
|
||||||
|
/* Decompose input value */
|
||||||
|
sign = (value >> 63) & 1;
|
||||||
|
exponent = ((value >> 52) & 0x7FF) - 1023;
|
||||||
|
mantissa = (value >> 28) & 0xFFFFFF; /* Highest 24 bits */
|
||||||
|
|
||||||
|
/* Figure if value is in range representable by floats. */
|
||||||
|
if (exponent == 1024)
|
||||||
|
{
|
||||||
|
/* Special value */
|
||||||
|
exponent = 128;
|
||||||
|
}
|
||||||
|
else if (exponent > 127)
|
||||||
|
{
|
||||||
|
/* Too large */
|
||||||
|
if (sign)
|
||||||
|
return -INFINITY;
|
||||||
|
else
|
||||||
|
return INFINITY;
|
||||||
|
}
|
||||||
|
else if (exponent < -150)
|
||||||
|
{
|
||||||
|
/* Too small */
|
||||||
|
if (sign)
|
||||||
|
return -0.0f;
|
||||||
|
else
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
else if (exponent < -126)
|
||||||
|
{
|
||||||
|
/* Denormalized */
|
||||||
|
mantissa |= 0x1000000;
|
||||||
|
mantissa >>= (-126 - exponent);
|
||||||
|
exponent = -127;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Round off mantissa */
|
||||||
|
mantissa = (mantissa + 1) >> 1;
|
||||||
|
|
||||||
|
/* Check if mantissa went over 2.0 */
|
||||||
|
if (mantissa & 0x800000)
|
||||||
|
{
|
||||||
|
exponent += 1;
|
||||||
|
mantissa &= 0x7FFFFF;
|
||||||
|
mantissa >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Combine fields */
|
||||||
|
out.i = mantissa;
|
||||||
|
out.i |= (uint32_t)(exponent + 127) << 23;
|
||||||
|
out.i |= (uint32_t)sign << 31;
|
||||||
|
|
||||||
|
return out.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
26
example_avr_double/double_conversion.h
Normal file
26
example_avr_double/double_conversion.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/* AVR-GCC does not have real double datatype. Instead its double
|
||||||
|
* is equal to float, i.e. 32 bit value. If you need to communicate
|
||||||
|
* with other systems that use double in their .proto files, you
|
||||||
|
* need to do some conversion.
|
||||||
|
*
|
||||||
|
* These functions use bitwise operations to mangle floats into doubles
|
||||||
|
* and then store them in uint64_t datatype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DOUBLE_CONVERSION
|
||||||
|
#define DOUBLE_CONVERSION
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Convert native 4-byte float into a 8-byte double. */
|
||||||
|
extern uint64_t float_to_double(float value);
|
||||||
|
|
||||||
|
/* Convert 8-byte double into native 4-byte float.
|
||||||
|
* Values are rounded to nearest, 0.5 away from zero.
|
||||||
|
* Overflowing values are converted to Inf or -Inf.
|
||||||
|
*/
|
||||||
|
extern float double_to_float(uint64_t value);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
13
example_avr_double/doubleproto.proto
Normal file
13
example_avr_double/doubleproto.proto
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// A message containing doubles, as used by other applications.
|
||||||
|
message DoubleMessage {
|
||||||
|
required double field1 = 1;
|
||||||
|
required double field2 = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A message containing doubles, but redefined using uint64_t.
|
||||||
|
// For use in AVR code.
|
||||||
|
message AVRDoubleMessage {
|
||||||
|
required fixed64 field1 = 1;
|
||||||
|
required fixed64 field2 = 2;
|
||||||
|
}
|
||||||
|
|
||||||
25
example_avr_double/encode_double.c
Normal file
25
example_avr_double/encode_double.c
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/* Encodes a float value into a double on the wire.
|
||||||
|
* Used to emit doubles from AVR code, which doesn't support double directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <pb_encode.h>
|
||||||
|
#include "double_conversion.h"
|
||||||
|
#include "doubleproto.pb.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
AVRDoubleMessage message = {
|
||||||
|
float_to_double(1234.5678f),
|
||||||
|
float_to_double(0.00001f)
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t buffer[32];
|
||||||
|
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
pb_encode(&stream, AVRDoubleMessage_fields, &message);
|
||||||
|
fwrite(buffer, 1, stream.bytes_written, stdout);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
56
example_avr_double/test_conversions.c
Normal file
56
example_avr_double/test_conversions.c
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#include "double_conversion.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static const double testvalues[] = {
|
||||||
|
0.0, -0.0, 0.1, -0.1,
|
||||||
|
M_PI, -M_PI, 123456.789, -123456.789,
|
||||||
|
INFINITY, -INFINITY, NAN, INFINITY - INFINITY,
|
||||||
|
1e38, -1e38, 1e39, -1e39,
|
||||||
|
1e-38, -1e-38, 1e-39, -1e-39,
|
||||||
|
3.14159e-37,-3.14159e-37, 3.14159e-43, -3.14159e-43,
|
||||||
|
1e-60, -1e-60, 1e-45, -1e-45,
|
||||||
|
0.99999999999999, -0.99999999999999, 127.999999999999, -127.999999999999
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TESTVALUES_COUNT (sizeof(testvalues)/sizeof(testvalues[0]))
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < TESTVALUES_COUNT; i++)
|
||||||
|
{
|
||||||
|
double orig = testvalues[i];
|
||||||
|
float expected_float = (float)orig;
|
||||||
|
double expected_double = (double)expected_float;
|
||||||
|
|
||||||
|
float got_float = double_to_float(*(uint64_t*)&orig);
|
||||||
|
uint64_t got_double = float_to_double(got_float);
|
||||||
|
|
||||||
|
uint32_t e1 = *(uint32_t*)&expected_float;
|
||||||
|
uint32_t g1 = *(uint32_t*)&got_float;
|
||||||
|
uint64_t e2 = *(uint64_t*)&expected_double;
|
||||||
|
uint64_t g2 = got_double;
|
||||||
|
|
||||||
|
if (g1 != e1)
|
||||||
|
{
|
||||||
|
printf("%3d double_to_float fail: %08x != %08x\n", i, g1, e1);
|
||||||
|
status = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g2 != e2)
|
||||||
|
{
|
||||||
|
printf("%3d float_to_double fail: %016llx != %016llx\n", i,
|
||||||
|
(unsigned long long)g2,
|
||||||
|
(unsigned long long)e2);
|
||||||
|
status = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -7,10 +7,13 @@
|
|||||||
|
|
||||||
import "google/protobuf/descriptor.proto";
|
import "google/protobuf/descriptor.proto";
|
||||||
|
|
||||||
|
option java_package = "fi.kapsi.koti.jpa.nanopb";
|
||||||
|
|
||||||
enum FieldType {
|
enum FieldType {
|
||||||
FT_DEFAULT = 0; // Automatically decide field type, generate static field if possible.
|
FT_DEFAULT = 0; // Automatically decide field type, generate static field if possible.
|
||||||
FT_CALLBACK = 1; // Always generate a callback field.
|
FT_CALLBACK = 1; // Always generate a callback field.
|
||||||
FT_STATIC = 2; // Generate a static field or raise an exception if not possible.
|
FT_STATIC = 2; // Generate a static field or raise an exception if not possible.
|
||||||
|
FT_IGNORE = 3; // Ignore the field completely.
|
||||||
}
|
}
|
||||||
|
|
||||||
message NanoPBOptions {
|
message NanoPBOptions {
|
||||||
@@ -25,6 +28,9 @@ message NanoPBOptions {
|
|||||||
|
|
||||||
// Use long names for enums, i.e. EnumName_EnumValue.
|
// Use long names for enums, i.e. EnumName_EnumValue.
|
||||||
optional bool long_names = 4 [default = true];
|
optional bool long_names = 4 [default = true];
|
||||||
|
|
||||||
|
// Add 'packed' attribute to generated structs.
|
||||||
|
optional bool packed_struct = 5 [default = false];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protocol Buffers extension number registry
|
// Protocol Buffers extension number registry
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.'''
|
'''Generate header file for nanopb from a ProtoBuf FileDescriptorSet.'''
|
||||||
nanopb_version = "nanopb-0.1.8"
|
nanopb_version = "nanopb-0.1.9.1"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import google.protobuf.descriptor_pb2 as descriptor
|
import google.protobuf.descriptor_pb2 as descriptor
|
||||||
@@ -306,7 +306,14 @@ class Field:
|
|||||||
class Message:
|
class Message:
|
||||||
def __init__(self, names, desc, message_options):
|
def __init__(self, names, desc, message_options):
|
||||||
self.name = names
|
self.name = names
|
||||||
self.fields = [Field(self.name, f, get_nanopb_suboptions(f, message_options)) for f in desc.field]
|
self.fields = []
|
||||||
|
|
||||||
|
for f in desc.field:
|
||||||
|
field_options = get_nanopb_suboptions(f, message_options)
|
||||||
|
if field_options.type != nanopb_pb2.FT_IGNORE:
|
||||||
|
self.fields.append(Field(self.name, f, field_options))
|
||||||
|
|
||||||
|
self.packed = message_options.packed_struct
|
||||||
self.ordered_fields = self.fields[:]
|
self.ordered_fields = self.fields[:]
|
||||||
self.ordered_fields.sort()
|
self.ordered_fields.sort()
|
||||||
|
|
||||||
@@ -317,7 +324,12 @@ class Message:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
result = 'typedef struct _%s {\n' % self.name
|
result = 'typedef struct _%s {\n' % self.name
|
||||||
result += '\n'.join([str(f) for f in self.ordered_fields])
|
result += '\n'.join([str(f) for f in self.ordered_fields])
|
||||||
result += '\n} %s;' % self.name
|
result += '\n}'
|
||||||
|
|
||||||
|
if self.packed:
|
||||||
|
result += ' pb_packed'
|
||||||
|
|
||||||
|
result += ' %s;' % self.name
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def types(self):
|
def types(self):
|
||||||
@@ -440,6 +452,16 @@ def sort_dependencies(messages):
|
|||||||
if msgname in message_by_name:
|
if msgname in message_by_name:
|
||||||
yield message_by_name[msgname]
|
yield message_by_name[msgname]
|
||||||
|
|
||||||
|
def make_identifier(headername):
|
||||||
|
'''Make #ifndef identifier that contains uppercase A-Z and digits 0-9'''
|
||||||
|
result = ""
|
||||||
|
for c in headername.upper():
|
||||||
|
if c.isalnum():
|
||||||
|
result += c
|
||||||
|
else:
|
||||||
|
result += '_'
|
||||||
|
return result
|
||||||
|
|
||||||
def generate_header(dependencies, headername, enums, messages):
|
def generate_header(dependencies, headername, enums, messages):
|
||||||
'''Generate content for a header file.
|
'''Generate content for a header file.
|
||||||
Generates strings, which should be concatenated and stored to file.
|
Generates strings, which should be concatenated and stored to file.
|
||||||
@@ -448,7 +470,7 @@ def generate_header(dependencies, headername, enums, messages):
|
|||||||
yield '/* Automatically generated nanopb header */\n'
|
yield '/* Automatically generated nanopb header */\n'
|
||||||
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
|
yield '/* Generated by %s at %s. */\n\n' % (nanopb_version, time.asctime())
|
||||||
|
|
||||||
symbol = headername.replace('.', '_').upper()
|
symbol = make_identifier(headername)
|
||||||
yield '#ifndef _PB_%s_\n' % symbol
|
yield '#ifndef _PB_%s_\n' % symbol
|
||||||
yield '#define _PB_%s_\n' % symbol
|
yield '#define _PB_%s_\n' % symbol
|
||||||
yield '#include <pb.h>\n\n'
|
yield '#include <pb.h>\n\n'
|
||||||
@@ -490,6 +512,7 @@ def generate_header(dependencies, headername, enums, messages):
|
|||||||
yield ' setting PB_MAX_REQUIRED_FIELDS to %d or more.\n' % largest_count
|
yield ' setting PB_MAX_REQUIRED_FIELDS to %d or more.\n' % largest_count
|
||||||
yield '#endif\n'
|
yield '#endif\n'
|
||||||
|
|
||||||
|
# Add checks for numeric limits
|
||||||
worst = 0
|
worst = 0
|
||||||
worst_field = ''
|
worst_field = ''
|
||||||
checks = []
|
checks = []
|
||||||
@@ -527,6 +550,20 @@ def generate_header(dependencies, headername, enums, messages):
|
|||||||
yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs)
|
yield 'STATIC_ASSERT((%s), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_%s)\n'%(assertion,msgs)
|
||||||
yield '#endif\n'
|
yield '#endif\n'
|
||||||
|
|
||||||
|
# Add check for sizeof(double)
|
||||||
|
has_double = False
|
||||||
|
for msg in messages:
|
||||||
|
for field in msg.fields:
|
||||||
|
if field.ctype == 'double':
|
||||||
|
has_double = True
|
||||||
|
|
||||||
|
if has_double:
|
||||||
|
yield '\n'
|
||||||
|
yield '/* On some platforms (such as AVR), double is really float.\n'
|
||||||
|
yield ' * These are not directly supported by nanopb, but see example_avr_double.\n'
|
||||||
|
yield ' */\n'
|
||||||
|
yield 'STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)\n'
|
||||||
|
|
||||||
yield '\n#ifdef __cplusplus\n'
|
yield '\n#ifdef __cplusplus\n'
|
||||||
yield '} /* extern "C" */\n'
|
yield '} /* extern "C" */\n'
|
||||||
yield '#endif\n'
|
yield '#endif\n'
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import google.protobuf.descriptor_pb2
|
|||||||
DESCRIPTOR = descriptor.FileDescriptor(
|
DESCRIPTOR = descriptor.FileDescriptor(
|
||||||
name='nanopb.proto',
|
name='nanopb.proto',
|
||||||
package='',
|
package='',
|
||||||
serialized_pb='\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"t\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true*;\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\r\n\tFT_STATIC\x10\x02:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions')
|
serialized_pb='\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"\x92\x01\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true\x12\x1c\n\rpacked_struct\x18\x05 \x01(\x08:\x05\x66\x61lse*J\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\r\n\tFT_STATIC\x10\x02\x12\r\n\tFT_IGNORE\x10\x03:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions')
|
||||||
|
|
||||||
_FIELDTYPE = descriptor.EnumDescriptor(
|
_FIELDTYPE = descriptor.EnumDescriptor(
|
||||||
name='FieldType',
|
name='FieldType',
|
||||||
@@ -32,17 +32,22 @@ _FIELDTYPE = descriptor.EnumDescriptor(
|
|||||||
name='FT_STATIC', index=2, number=2,
|
name='FT_STATIC', index=2, number=2,
|
||||||
options=None,
|
options=None,
|
||||||
type=None),
|
type=None),
|
||||||
|
descriptor.EnumValueDescriptor(
|
||||||
|
name='FT_IGNORE', index=3, number=3,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
],
|
],
|
||||||
containing_type=None,
|
containing_type=None,
|
||||||
options=None,
|
options=None,
|
||||||
serialized_start=168,
|
serialized_start=199,
|
||||||
serialized_end=227,
|
serialized_end=273,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
FT_DEFAULT = 0
|
FT_DEFAULT = 0
|
||||||
FT_CALLBACK = 1
|
FT_CALLBACK = 1
|
||||||
FT_STATIC = 2
|
FT_STATIC = 2
|
||||||
|
FT_IGNORE = 3
|
||||||
|
|
||||||
NANOPB_FILEOPT_FIELD_NUMBER = 1010
|
NANOPB_FILEOPT_FIELD_NUMBER = 1010
|
||||||
nanopb_fileopt = descriptor.FieldDescriptor(
|
nanopb_fileopt = descriptor.FieldDescriptor(
|
||||||
@@ -113,6 +118,13 @@ _NANOPBOPTIONS = descriptor.Descriptor(
|
|||||||
message_type=None, enum_type=None, containing_type=None,
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
is_extension=False, extension_scope=None,
|
is_extension=False, extension_scope=None,
|
||||||
options=None),
|
options=None),
|
||||||
|
descriptor.FieldDescriptor(
|
||||||
|
name='packed_struct', full_name='NanoPBOptions.packed_struct', index=4,
|
||||||
|
number=5, type=8, cpp_type=7, label=1,
|
||||||
|
has_default_value=True, default_value=False,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
],
|
],
|
||||||
extensions=[
|
extensions=[
|
||||||
],
|
],
|
||||||
@@ -122,8 +134,8 @@ _NANOPBOPTIONS = descriptor.Descriptor(
|
|||||||
options=None,
|
options=None,
|
||||||
is_extendable=False,
|
is_extendable=False,
|
||||||
extension_ranges=[],
|
extension_ranges=[],
|
||||||
serialized_start=50,
|
serialized_start=51,
|
||||||
serialized_end=166,
|
serialized_end=197,
|
||||||
)
|
)
|
||||||
|
|
||||||
_NANOPBOPTIONS.fields_by_name['type'].enum_type = _FIELDTYPE
|
_NANOPBOPTIONS.fields_by_name['type'].enum_type = _FIELDTYPE
|
||||||
|
|||||||
6
pb.h
6
pb.h
@@ -6,7 +6,7 @@
|
|||||||
* see pb_encode.h or pb_decode.h
|
* see pb_encode.h or pb_decode.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define NANOPB_VERSION nanopb-0.1.8
|
#define NANOPB_VERSION nanopb-0.1.9.1
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -100,8 +100,8 @@ typedef enum {
|
|||||||
|
|
||||||
/* Works for all required/optional/repeated fields.
|
/* Works for all required/optional/repeated fields.
|
||||||
* data_offset points to pb_callback_t structure.
|
* data_offset points to pb_callback_t structure.
|
||||||
* LTYPE should be 0 (it is ignored, but sometimes
|
* LTYPE should be valid or 0 (it is ignored, but
|
||||||
* used to speculatively index an array). */
|
* sometimes used to speculatively index an array). */
|
||||||
PB_HTYPE_CALLBACK = 0x30,
|
PB_HTYPE_CALLBACK = 0x30,
|
||||||
|
|
||||||
PB_HTYPE_MASK = 0xF0
|
PB_HTYPE_MASK = 0xF0
|
||||||
|
|||||||
142
pb_decode.c
142
pb_decode.c
@@ -39,16 +39,20 @@ static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
|
|||||||
static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count)
|
static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count)
|
||||||
{
|
{
|
||||||
uint8_t *source = (uint8_t*)stream->state;
|
uint8_t *source = (uint8_t*)stream->state;
|
||||||
|
stream->state = source + count;
|
||||||
|
|
||||||
if (buf != NULL)
|
if (buf != NULL)
|
||||||
memcpy(buf, source, count);
|
{
|
||||||
|
while (count--)
|
||||||
|
*buf++ = *source++;
|
||||||
|
}
|
||||||
|
|
||||||
stream->state = source + count;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
|
bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
|
||||||
{
|
{
|
||||||
|
#ifndef PB_BUFFER_ONLY
|
||||||
if (buf == NULL && stream->callback != buf_read)
|
if (buf == NULL && stream->callback != buf_read)
|
||||||
{
|
{
|
||||||
/* Skip input bytes */
|
/* Skip input bytes */
|
||||||
@@ -63,12 +67,18 @@ bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
|
|||||||
|
|
||||||
return pb_read(stream, tmp, count);
|
return pb_read(stream, tmp, count);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (stream->bytes_left < count)
|
if (stream->bytes_left < count)
|
||||||
PB_RETURN_ERROR(stream, "end-of-stream");
|
PB_RETURN_ERROR(stream, "end-of-stream");
|
||||||
|
|
||||||
|
#ifndef PB_BUFFER_ONLY
|
||||||
if (!stream->callback(stream, buf, count))
|
if (!stream->callback(stream, buf, count))
|
||||||
PB_RETURN_ERROR(stream, "io error");
|
PB_RETURN_ERROR(stream, "io error");
|
||||||
|
#else
|
||||||
|
if (!buf_read(stream, buf, count))
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
stream->bytes_left -= count;
|
stream->bytes_left -= count;
|
||||||
return true;
|
return true;
|
||||||
@@ -77,7 +87,11 @@ bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count)
|
|||||||
pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize)
|
pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize)
|
||||||
{
|
{
|
||||||
pb_istream_t stream;
|
pb_istream_t stream;
|
||||||
|
#ifdef PB_BUFFER_ONLY
|
||||||
|
stream.callback = NULL;
|
||||||
|
#else
|
||||||
stream.callback = &buf_read;
|
stream.callback = &buf_read;
|
||||||
|
#endif
|
||||||
stream.state = buf;
|
stream.state = buf;
|
||||||
stream.bytes_left = bufsize;
|
stream.bytes_left = bufsize;
|
||||||
#ifndef PB_NO_ERRMSG
|
#ifndef PB_NO_ERRMSG
|
||||||
@@ -92,28 +106,60 @@ pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize)
|
|||||||
|
|
||||||
static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
|
static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest)
|
||||||
{
|
{
|
||||||
uint64_t temp;
|
uint8_t byte;
|
||||||
bool status = pb_decode_varint(stream, &temp);
|
uint32_t result;
|
||||||
*dest = (uint32_t)temp;
|
|
||||||
return status;
|
if (!pb_read(stream, &byte, 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!(byte & 0x80))
|
||||||
|
{
|
||||||
|
/* Quick case, 1 byte value */
|
||||||
|
result = byte;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Multibyte case */
|
||||||
|
uint8_t bitpos = 7;
|
||||||
|
result = byte & 0x7F;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (bitpos >= 32)
|
||||||
|
PB_RETURN_ERROR(stream, "varint overflow");
|
||||||
|
|
||||||
|
if (!pb_read(stream, &byte, 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
result |= (uint32_t)(byte & 0x7F) << bitpos;
|
||||||
|
bitpos = (uint8_t)(bitpos + 7);
|
||||||
|
} while (byte & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest = result;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
|
bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest)
|
||||||
{
|
{
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
int bitpos = 0;
|
uint8_t bitpos = 0;
|
||||||
*dest = 0;
|
uint64_t result = 0;
|
||||||
|
|
||||||
while (bitpos < 64 && pb_read(stream, &byte, 1))
|
do
|
||||||
{
|
{
|
||||||
*dest |= (uint64_t)(byte & 0x7F) << bitpos;
|
if (bitpos >= 64)
|
||||||
bitpos += 7;
|
|
||||||
|
|
||||||
if (!(byte & 0x80))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PB_RETURN_ERROR(stream, "varint overflow");
|
PB_RETURN_ERROR(stream, "varint overflow");
|
||||||
|
|
||||||
|
if (!pb_read(stream, &byte, 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
result |= (uint64_t)(byte & 0x7F) << bitpos;
|
||||||
|
bitpos = (uint8_t)(bitpos + 7);
|
||||||
|
} while (byte & 0x80);
|
||||||
|
|
||||||
|
*dest = result;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkreturn pb_skip_varint(pb_istream_t *stream)
|
bool checkreturn pb_skip_varint(pb_istream_t *stream)
|
||||||
@@ -225,14 +271,18 @@ bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *su
|
|||||||
void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream)
|
void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream)
|
||||||
{
|
{
|
||||||
stream->state = substream->state;
|
stream->state = substream->state;
|
||||||
|
|
||||||
|
#ifndef PB_NO_ERRMSG
|
||||||
|
stream->errmsg = substream->errmsg;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterator for pb_field_t list */
|
/* Iterator for pb_field_t list */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const pb_field_t *start; /* Start of the pb_field_t array */
|
const pb_field_t *start; /* Start of the pb_field_t array */
|
||||||
const pb_field_t *current; /* Current position of the iterator */
|
const pb_field_t *current; /* Current position of the iterator */
|
||||||
int field_index; /* Zero-based index of the field. */
|
unsigned field_index; /* Zero-based index of the field. */
|
||||||
int required_field_index; /* Zero-based index that counts only the required fields */
|
unsigned required_field_index; /* Zero-based index that counts only the required fields */
|
||||||
void *dest_struct; /* Pointer to the destination structure to decode to */
|
void *dest_struct; /* Pointer to the destination structure to decode to */
|
||||||
void *pData; /* Pointer where to store current field value */
|
void *pData; /* Pointer where to store current field value */
|
||||||
void *pSize; /* Pointer where to store the size of current array field */
|
void *pSize; /* Pointer where to store the size of current array field */
|
||||||
@@ -278,7 +328,7 @@ static bool pb_field_next(pb_field_iterator_t *iter)
|
|||||||
|
|
||||||
static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag)
|
static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag)
|
||||||
{
|
{
|
||||||
int start = iter->field_index;
|
unsigned start = iter->field_index;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (iter->current->tag == tag)
|
if (iter->current->tag == tag)
|
||||||
@@ -311,7 +361,7 @@ static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_t
|
|||||||
&& PB_LTYPE(iter->current->type) <= PB_LTYPE_LAST_PACKABLE)
|
&& PB_LTYPE(iter->current->type) <= PB_LTYPE_LAST_PACKABLE)
|
||||||
{
|
{
|
||||||
/* Packed array */
|
/* Packed array */
|
||||||
bool status;
|
bool status = true;
|
||||||
size_t *size = (size_t*)iter->pSize;
|
size_t *size = (size_t*)iter->pSize;
|
||||||
pb_istream_t substream;
|
pb_istream_t substream;
|
||||||
if (!pb_make_string_substream(stream, &substream))
|
if (!pb_make_string_substream(stream, &substream))
|
||||||
@@ -321,11 +371,17 @@ static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_t
|
|||||||
{
|
{
|
||||||
void *pItem = (uint8_t*)iter->pData + iter->current->data_size * (*size);
|
void *pItem = (uint8_t*)iter->pData + iter->current->data_size * (*size);
|
||||||
if (!func(&substream, iter->current, pItem))
|
if (!func(&substream, iter->current, pItem))
|
||||||
return false;
|
{
|
||||||
|
status = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
(*size)++;
|
(*size)++;
|
||||||
}
|
}
|
||||||
status = (substream.bytes_left == 0);
|
|
||||||
pb_close_string_substream(stream, &substream);
|
pb_close_string_substream(stream, &substream);
|
||||||
|
|
||||||
|
if (substream.bytes_left != 0)
|
||||||
|
PB_RETURN_ERROR(stream, "array overflow");
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -473,15 +529,34 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check that all required fields were present. */
|
/* Check that all required fields were present. */
|
||||||
pb_field_init(&iter, fields, dest_struct);
|
|
||||||
do {
|
|
||||||
if (PB_HTYPE(iter.current->type) == PB_HTYPE_REQUIRED &&
|
|
||||||
iter.required_field_index < PB_MAX_REQUIRED_FIELDS &&
|
|
||||||
!(fields_seen[iter.required_field_index >> 3] & (1 << (iter.required_field_index & 7))))
|
|
||||||
{
|
{
|
||||||
|
/* First figure out the number of required fields by
|
||||||
|
* seeking to the end of the field array. Usually we
|
||||||
|
* are already close to end after decoding.
|
||||||
|
*/
|
||||||
|
unsigned req_field_count;
|
||||||
|
pb_type_t last_type;
|
||||||
|
unsigned i;
|
||||||
|
do {
|
||||||
|
req_field_count = iter.required_field_index;
|
||||||
|
last_type = iter.current->type;
|
||||||
|
} while (pb_field_next(&iter));
|
||||||
|
|
||||||
|
/* Fixup if last field was also required. */
|
||||||
|
if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED)
|
||||||
|
req_field_count++;
|
||||||
|
|
||||||
|
/* Check the whole bytes */
|
||||||
|
for (i = 0; i < (req_field_count >> 3); i++)
|
||||||
|
{
|
||||||
|
if (fields_seen[i] != 0xFF)
|
||||||
|
PB_RETURN_ERROR(stream, "missing required field");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the remaining bits */
|
||||||
|
if (fields_seen[req_field_count >> 3] != (0xFF >> (8 - (req_field_count & 7))))
|
||||||
PB_RETURN_ERROR(stream, "missing required field");
|
PB_RETURN_ERROR(stream, "missing required field");
|
||||||
}
|
}
|
||||||
} while (pb_field_next(&iter));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -603,6 +678,9 @@ bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, voi
|
|||||||
return false;
|
return false;
|
||||||
x->size = temp;
|
x->size = temp;
|
||||||
|
|
||||||
|
if (x->size < temp)
|
||||||
|
PB_RETURN_ERROR(stream, "size too large");
|
||||||
|
|
||||||
/* Check length, noting the space taken by the size_t header. */
|
/* Check length, noting the space taken by the size_t header. */
|
||||||
if (x->size > field->data_size - offsetof(pb_bytes_array_t, bytes))
|
if (x->size > field->data_size - offsetof(pb_bytes_array_t, bytes))
|
||||||
PB_RETURN_ERROR(stream, "bytes overflow");
|
PB_RETURN_ERROR(stream, "bytes overflow");
|
||||||
@@ -613,12 +691,18 @@ bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, voi
|
|||||||
bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest)
|
bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest)
|
||||||
{
|
{
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
|
size_t alloc_size;
|
||||||
bool status;
|
bool status;
|
||||||
if (!pb_decode_varint32(stream, &size))
|
if (!pb_decode_varint32(stream, &size))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
alloc_size = size + 1;
|
||||||
|
|
||||||
|
if (alloc_size < size)
|
||||||
|
PB_RETURN_ERROR(stream, "size too large");
|
||||||
|
|
||||||
/* Check length, noting the null terminator */
|
/* Check length, noting the null terminator */
|
||||||
if (size + 1 > field->data_size)
|
if (alloc_size > field->data_size)
|
||||||
PB_RETURN_ERROR(stream, "string overflow");
|
PB_RETURN_ERROR(stream, "string overflow");
|
||||||
|
|
||||||
status = pb_read(stream, (uint8_t*)dest, size);
|
status = pb_read(stream, (uint8_t*)dest, size);
|
||||||
|
|||||||
@@ -32,7 +32,16 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
struct _pb_istream_t
|
struct _pb_istream_t
|
||||||
{
|
{
|
||||||
|
#ifdef PB_BUFFER_ONLY
|
||||||
|
/* Callback pointer is not used in buffer-only configuration.
|
||||||
|
* Having an int pointer here allows binary compatibility but
|
||||||
|
* gives an error if someone tries to assign callback function.
|
||||||
|
*/
|
||||||
|
int *callback;
|
||||||
|
#else
|
||||||
bool (*callback)(pb_istream_t *stream, uint8_t *buf, size_t count);
|
bool (*callback)(pb_istream_t *stream, uint8_t *buf, size_t count);
|
||||||
|
#endif
|
||||||
|
|
||||||
void *state; /* Free field for use by callback implementation */
|
void *state; /* Free field for use by callback implementation */
|
||||||
size_t bytes_left;
|
size_t bytes_left;
|
||||||
|
|
||||||
|
|||||||
14
pb_encode.c
14
pb_encode.c
@@ -37,15 +37,22 @@ static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
|
|||||||
static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
|
static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count)
|
||||||
{
|
{
|
||||||
uint8_t *dest = (uint8_t*)stream->state;
|
uint8_t *dest = (uint8_t*)stream->state;
|
||||||
memcpy(dest, buf, count);
|
|
||||||
stream->state = dest + count;
|
stream->state = dest + count;
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
*dest++ = *buf++;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize)
|
pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize)
|
||||||
{
|
{
|
||||||
pb_ostream_t stream;
|
pb_ostream_t stream;
|
||||||
|
#ifdef PB_BUFFER_ONLY
|
||||||
|
stream.callback = (void*)1; /* Just some marker value */
|
||||||
|
#else
|
||||||
stream.callback = &buf_write;
|
stream.callback = &buf_write;
|
||||||
|
#endif
|
||||||
stream.state = buf;
|
stream.state = buf;
|
||||||
stream.max_size = bufsize;
|
stream.max_size = bufsize;
|
||||||
stream.bytes_written = 0;
|
stream.bytes_written = 0;
|
||||||
@@ -59,8 +66,13 @@ bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count
|
|||||||
if (stream->bytes_written + count > stream->max_size)
|
if (stream->bytes_written + count > stream->max_size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#ifdef PB_BUFFER_ONLY
|
||||||
|
if (!buf_write(stream, buf, count))
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
if (!stream->callback(stream, buf, count))
|
if (!stream->callback(stream, buf, count))
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->bytes_written += count;
|
stream->bytes_written += count;
|
||||||
|
|||||||
10
pb_encode.h
10
pb_encode.h
@@ -32,7 +32,17 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
struct _pb_ostream_t
|
struct _pb_ostream_t
|
||||||
{
|
{
|
||||||
|
#ifdef PB_BUFFER_ONLY
|
||||||
|
/* Callback pointer is not used in buffer-only configuration.
|
||||||
|
* Having an int pointer here allows binary compatibility but
|
||||||
|
* gives an error if someone tries to assign callback function.
|
||||||
|
* Also, NULL pointer marks a 'sizing stream' that does not
|
||||||
|
* write anything.
|
||||||
|
*/
|
||||||
|
int *callback;
|
||||||
|
#else
|
||||||
bool (*callback)(pb_ostream_t *stream, const uint8_t *buf, size_t count);
|
bool (*callback)(pb_ostream_t *stream, const uint8_t *buf, size_t count);
|
||||||
|
#endif
|
||||||
void *state; /* Free field for use by callback implementation */
|
void *state; /* Free field for use by callback implementation */
|
||||||
size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */
|
size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */
|
||||||
size_t bytes_written;
|
size_t bytes_written;
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ DEPS=../pb_decode.h ../pb_encode.h ../pb.h person.pb.h \
|
|||||||
callbacks2.pb.h callbacks.pb.h unittests.h unittestproto.pb.h \
|
callbacks2.pb.h callbacks.pb.h unittests.h unittestproto.pb.h \
|
||||||
alltypes.pb.h missing_fields.pb.h
|
alltypes.pb.h missing_fields.pb.h
|
||||||
TESTS= decode_unittests encode_unittests \
|
TESTS= decode_unittests encode_unittests \
|
||||||
test_decode1 test_decode2 test_decode3 \
|
test_decode1 test_decode2 test_decode3 test_decode3_buf \
|
||||||
test_encode1 test_encode2 test_encode3 \
|
test_encode1 test_encode2 test_encode3 test_encode3_buf \
|
||||||
test_decode_callbacks test_encode_callbacks \
|
test_decode_callbacks test_encode_callbacks \
|
||||||
test_missing_fields test_no_messages \
|
test_missing_fields test_no_messages test_funny_name \
|
||||||
test_multiple_files test_cxxcompile test_options
|
test_multiple_files test_cxxcompile test_options \
|
||||||
|
bc_encode bc_decode
|
||||||
|
|
||||||
# More strict checks for the core part of nanopb
|
# More strict checks for the core part of nanopb
|
||||||
CC_VERSION=$(shell $(CC) -v 2>&1)
|
CC_VERSION=$(shell $(CC) -v 2>&1)
|
||||||
@@ -38,11 +39,26 @@ pb_encode.o: ../pb_encode.c $(DEPS)
|
|||||||
pb_decode.o: ../pb_decode.c $(DEPS)
|
pb_decode.o: ../pb_decode.c $(DEPS)
|
||||||
$(CC) $(CFLAGS) $(CFLAGS_CORE) -c -o $@ $<
|
$(CC) $(CFLAGS) $(CFLAGS_CORE) -c -o $@ $<
|
||||||
|
|
||||||
|
# Test for compilability with c++ compiler
|
||||||
|
|
||||||
pb_encode.cxx.o: ../pb_encode.c $(DEPS)
|
pb_encode.cxx.o: ../pb_encode.c $(DEPS)
|
||||||
$(CXX) $(CFLAGS) $(CFLAGS_CORE) -c -o $@ $<
|
$(CXX) $(CFLAGS) $(CFLAGS_CORE) -c -o $@ $<
|
||||||
pb_decode.cxx.o: ../pb_decode.c $(DEPS)
|
pb_decode.cxx.o: ../pb_decode.c $(DEPS)
|
||||||
$(CXX) $(CFLAGS) $(CFLAGS_CORE) -c -o $@ $<
|
$(CXX) $(CFLAGS) $(CFLAGS_CORE) -c -o $@ $<
|
||||||
|
|
||||||
|
# Test for PB_BUF_ONLY compilation option
|
||||||
|
|
||||||
|
pb_encode.buf.o: ../pb_encode.c $(DEPS)
|
||||||
|
$(CC) -DPB_BUFFER_ONLY $(CFLAGS) $(CFLAGS_CORE) -c -o $@ $<
|
||||||
|
pb_decode.buf.o: ../pb_decode.c $(DEPS)
|
||||||
|
$(CC) -DPB_BUFFER_ONLY $(CFLAGS) $(CFLAGS_CORE) -c -o $@ $<
|
||||||
|
%.buf.o: %.c $(DEPS)
|
||||||
|
$(CC) -DPB_BUFFER_ONLY $(CFLAGS) -c -o $@ $<
|
||||||
|
test_encode3_buf: test_encode3.buf.o pb_encode.buf.o alltypes.pb.o
|
||||||
|
$(CC) $(LDFLAGS) $^ -o $@
|
||||||
|
test_decode3_buf: test_decode3.buf.o pb_decode.buf.o alltypes.pb.o
|
||||||
|
$(CC) $(LDFLAGS) $^ -o $@
|
||||||
|
|
||||||
test_cxxcompile: pb_encode.cxx.o pb_decode.cxx.o
|
test_cxxcompile: pb_encode.cxx.o pb_decode.cxx.o
|
||||||
test_decode1: test_decode1.o pb_decode.o person.pb.o
|
test_decode1: test_decode1.o pb_decode.o person.pb.o
|
||||||
test_decode2: test_decode2.o pb_decode.o person.pb.o
|
test_decode2: test_decode2.o pb_decode.o person.pb.o
|
||||||
@@ -57,6 +73,9 @@ test_missing_fields: test_missing_fields.o pb_encode.o pb_decode.o missing_field
|
|||||||
decode_unittests: decode_unittests.o pb_decode.o unittestproto.pb.o
|
decode_unittests: decode_unittests.o pb_decode.o unittestproto.pb.o
|
||||||
encode_unittests: encode_unittests.o pb_encode.o unittestproto.pb.o
|
encode_unittests: encode_unittests.o pb_encode.o unittestproto.pb.o
|
||||||
test_no_messages: no_messages.pb.h no_messages.pb.c no_messages.pb.o
|
test_no_messages: no_messages.pb.h no_messages.pb.c no_messages.pb.o
|
||||||
|
test_funny_name: funny-proto+name.pb.h funny-proto+name.pb.o
|
||||||
|
bc_encode: bc_alltypes.pb.o pb_encode.o bc_encode.o
|
||||||
|
bc_decode: bc_alltypes.pb.o pb_decode.o bc_decode.o
|
||||||
|
|
||||||
%.pb: %.proto
|
%.pb: %.proto
|
||||||
protoc -I. -I../generator -I/usr/include -o$@ $<
|
protoc -I. -I../generator -I/usr/include -o$@ $<
|
||||||
@@ -95,6 +114,8 @@ run_unittests: $(TESTS)
|
|||||||
./test_encode3 | ./test_decode3
|
./test_encode3 | ./test_decode3
|
||||||
./test_encode3 1 | ./test_decode3 1
|
./test_encode3 1 | ./test_decode3 1
|
||||||
./test_encode3 1 | protoc --decode=AllTypes -I. -I../generator -I/usr/include alltypes.proto >/dev/null
|
./test_encode3 1 | protoc --decode=AllTypes -I. -I../generator -I/usr/include alltypes.proto >/dev/null
|
||||||
|
./test_encode3_buf 1 | ./test_decode3_buf 1
|
||||||
|
./bc_encode | ./bc_decode
|
||||||
|
|
||||||
./test_missing_fields
|
./test_missing_fields
|
||||||
|
|
||||||
|
|||||||
326
tests/bc_alltypes.pb.c
Normal file
326
tests/bc_alltypes.pb.c
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
/* Automatically generated nanopb constant definitions */
|
||||||
|
#include "bc_alltypes.pb.h"
|
||||||
|
|
||||||
|
const char SubMessage_substuff1_default[17] = "1";
|
||||||
|
const int32_t SubMessage_substuff2_default = 2;
|
||||||
|
const uint32_t SubMessage_substuff3_default = 3;
|
||||||
|
const int32_t AllTypes_opt_int32_default = 4041;
|
||||||
|
const int64_t AllTypes_opt_int64_default = 4042;
|
||||||
|
const uint32_t AllTypes_opt_uint32_default = 4043;
|
||||||
|
const uint64_t AllTypes_opt_uint64_default = 4044;
|
||||||
|
const int32_t AllTypes_opt_sint32_default = 4045;
|
||||||
|
const int64_t AllTypes_opt_sint64_default = 4046;
|
||||||
|
const bool AllTypes_opt_bool_default = false;
|
||||||
|
const uint32_t AllTypes_opt_fixed32_default = 4048;
|
||||||
|
const int32_t AllTypes_opt_sfixed32_default = 4049;
|
||||||
|
const float AllTypes_opt_float_default = 4050;
|
||||||
|
const uint64_t AllTypes_opt_fixed64_default = 4051;
|
||||||
|
const int64_t AllTypes_opt_sfixed64_default = 4052;
|
||||||
|
const double AllTypes_opt_double_default = 4053;
|
||||||
|
const char AllTypes_opt_string_default[17] = "4054";
|
||||||
|
const AllTypes_opt_bytes_t AllTypes_opt_bytes_default = {4, {0x34,0x30,0x35,0x35}};
|
||||||
|
const MyEnum AllTypes_opt_enum_default = MyEnum_Second;
|
||||||
|
|
||||||
|
|
||||||
|
const pb_field_t SubMessage_fields[4] = {
|
||||||
|
{1, PB_HTYPE_REQUIRED | PB_LTYPE_STRING,
|
||||||
|
offsetof(SubMessage, substuff1), 0,
|
||||||
|
pb_membersize(SubMessage, substuff1), 0,
|
||||||
|
&SubMessage_substuff1_default},
|
||||||
|
|
||||||
|
{2, PB_HTYPE_REQUIRED | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(SubMessage, substuff2, substuff1), 0,
|
||||||
|
pb_membersize(SubMessage, substuff2), 0,
|
||||||
|
&SubMessage_substuff2_default},
|
||||||
|
|
||||||
|
{3, PB_HTYPE_OPTIONAL | PB_LTYPE_FIXED32,
|
||||||
|
pb_delta_end(SubMessage, substuff3, substuff2),
|
||||||
|
pb_delta(SubMessage, has_substuff3, substuff3),
|
||||||
|
pb_membersize(SubMessage, substuff3), 0,
|
||||||
|
&SubMessage_substuff3_default},
|
||||||
|
|
||||||
|
PB_LAST_FIELD
|
||||||
|
};
|
||||||
|
|
||||||
|
const pb_field_t AllTypes_fields[53] = {
|
||||||
|
{1, PB_HTYPE_REQUIRED | PB_LTYPE_VARINT,
|
||||||
|
offsetof(AllTypes, req_int32), 0,
|
||||||
|
pb_membersize(AllTypes, req_int32), 0, 0},
|
||||||
|
|
||||||
|
{2, PB_HTYPE_REQUIRED | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, req_int64, req_int32), 0,
|
||||||
|
pb_membersize(AllTypes, req_int64), 0, 0},
|
||||||
|
|
||||||
|
{3, PB_HTYPE_REQUIRED | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, req_uint32, req_int64), 0,
|
||||||
|
pb_membersize(AllTypes, req_uint32), 0, 0},
|
||||||
|
|
||||||
|
{4, PB_HTYPE_REQUIRED | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, req_uint64, req_uint32), 0,
|
||||||
|
pb_membersize(AllTypes, req_uint64), 0, 0},
|
||||||
|
|
||||||
|
{5, PB_HTYPE_REQUIRED | PB_LTYPE_SVARINT,
|
||||||
|
pb_delta_end(AllTypes, req_sint32, req_uint64), 0,
|
||||||
|
pb_membersize(AllTypes, req_sint32), 0, 0},
|
||||||
|
|
||||||
|
{6, PB_HTYPE_REQUIRED | PB_LTYPE_SVARINT,
|
||||||
|
pb_delta_end(AllTypes, req_sint64, req_sint32), 0,
|
||||||
|
pb_membersize(AllTypes, req_sint64), 0, 0},
|
||||||
|
|
||||||
|
{7, PB_HTYPE_REQUIRED | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, req_bool, req_sint64), 0,
|
||||||
|
pb_membersize(AllTypes, req_bool), 0, 0},
|
||||||
|
|
||||||
|
{8, PB_HTYPE_REQUIRED | PB_LTYPE_FIXED32,
|
||||||
|
pb_delta_end(AllTypes, req_fixed32, req_bool), 0,
|
||||||
|
pb_membersize(AllTypes, req_fixed32), 0, 0},
|
||||||
|
|
||||||
|
{9, PB_HTYPE_REQUIRED | PB_LTYPE_FIXED32,
|
||||||
|
pb_delta_end(AllTypes, req_sfixed32, req_fixed32), 0,
|
||||||
|
pb_membersize(AllTypes, req_sfixed32), 0, 0},
|
||||||
|
|
||||||
|
{10, PB_HTYPE_REQUIRED | PB_LTYPE_FIXED32,
|
||||||
|
pb_delta_end(AllTypes, req_float, req_sfixed32), 0,
|
||||||
|
pb_membersize(AllTypes, req_float), 0, 0},
|
||||||
|
|
||||||
|
{11, PB_HTYPE_REQUIRED | PB_LTYPE_FIXED64,
|
||||||
|
pb_delta_end(AllTypes, req_fixed64, req_float), 0,
|
||||||
|
pb_membersize(AllTypes, req_fixed64), 0, 0},
|
||||||
|
|
||||||
|
{12, PB_HTYPE_REQUIRED | PB_LTYPE_FIXED64,
|
||||||
|
pb_delta_end(AllTypes, req_sfixed64, req_fixed64), 0,
|
||||||
|
pb_membersize(AllTypes, req_sfixed64), 0, 0},
|
||||||
|
|
||||||
|
{13, PB_HTYPE_REQUIRED | PB_LTYPE_FIXED64,
|
||||||
|
pb_delta_end(AllTypes, req_double, req_sfixed64), 0,
|
||||||
|
pb_membersize(AllTypes, req_double), 0, 0},
|
||||||
|
|
||||||
|
{14, PB_HTYPE_REQUIRED | PB_LTYPE_STRING,
|
||||||
|
pb_delta_end(AllTypes, req_string, req_double), 0,
|
||||||
|
pb_membersize(AllTypes, req_string), 0, 0},
|
||||||
|
|
||||||
|
{15, PB_HTYPE_REQUIRED | PB_LTYPE_BYTES,
|
||||||
|
pb_delta_end(AllTypes, req_bytes, req_string), 0,
|
||||||
|
pb_membersize(AllTypes, req_bytes), 0, 0},
|
||||||
|
|
||||||
|
{16, PB_HTYPE_REQUIRED | PB_LTYPE_SUBMESSAGE,
|
||||||
|
pb_delta_end(AllTypes, req_submsg, req_bytes), 0,
|
||||||
|
pb_membersize(AllTypes, req_submsg), 0,
|
||||||
|
&SubMessage_fields},
|
||||||
|
|
||||||
|
{17, PB_HTYPE_REQUIRED | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, req_enum, req_submsg), 0,
|
||||||
|
pb_membersize(AllTypes, req_enum), 0, 0},
|
||||||
|
|
||||||
|
{21, PB_HTYPE_ARRAY | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, rep_int32, req_enum),
|
||||||
|
pb_delta(AllTypes, rep_int32_count, rep_int32),
|
||||||
|
pb_membersize(AllTypes, rep_int32[0]),
|
||||||
|
pb_membersize(AllTypes, rep_int32) / pb_membersize(AllTypes, rep_int32[0]), 0},
|
||||||
|
|
||||||
|
{22, PB_HTYPE_ARRAY | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, rep_int64, rep_int32),
|
||||||
|
pb_delta(AllTypes, rep_int64_count, rep_int64),
|
||||||
|
pb_membersize(AllTypes, rep_int64[0]),
|
||||||
|
pb_membersize(AllTypes, rep_int64) / pb_membersize(AllTypes, rep_int64[0]), 0},
|
||||||
|
|
||||||
|
{23, PB_HTYPE_ARRAY | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, rep_uint32, rep_int64),
|
||||||
|
pb_delta(AllTypes, rep_uint32_count, rep_uint32),
|
||||||
|
pb_membersize(AllTypes, rep_uint32[0]),
|
||||||
|
pb_membersize(AllTypes, rep_uint32) / pb_membersize(AllTypes, rep_uint32[0]), 0},
|
||||||
|
|
||||||
|
{24, PB_HTYPE_ARRAY | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, rep_uint64, rep_uint32),
|
||||||
|
pb_delta(AllTypes, rep_uint64_count, rep_uint64),
|
||||||
|
pb_membersize(AllTypes, rep_uint64[0]),
|
||||||
|
pb_membersize(AllTypes, rep_uint64) / pb_membersize(AllTypes, rep_uint64[0]), 0},
|
||||||
|
|
||||||
|
{25, PB_HTYPE_ARRAY | PB_LTYPE_SVARINT,
|
||||||
|
pb_delta_end(AllTypes, rep_sint32, rep_uint64),
|
||||||
|
pb_delta(AllTypes, rep_sint32_count, rep_sint32),
|
||||||
|
pb_membersize(AllTypes, rep_sint32[0]),
|
||||||
|
pb_membersize(AllTypes, rep_sint32) / pb_membersize(AllTypes, rep_sint32[0]), 0},
|
||||||
|
|
||||||
|
{26, PB_HTYPE_ARRAY | PB_LTYPE_SVARINT,
|
||||||
|
pb_delta_end(AllTypes, rep_sint64, rep_sint32),
|
||||||
|
pb_delta(AllTypes, rep_sint64_count, rep_sint64),
|
||||||
|
pb_membersize(AllTypes, rep_sint64[0]),
|
||||||
|
pb_membersize(AllTypes, rep_sint64) / pb_membersize(AllTypes, rep_sint64[0]), 0},
|
||||||
|
|
||||||
|
{27, PB_HTYPE_ARRAY | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, rep_bool, rep_sint64),
|
||||||
|
pb_delta(AllTypes, rep_bool_count, rep_bool),
|
||||||
|
pb_membersize(AllTypes, rep_bool[0]),
|
||||||
|
pb_membersize(AllTypes, rep_bool) / pb_membersize(AllTypes, rep_bool[0]), 0},
|
||||||
|
|
||||||
|
{28, PB_HTYPE_ARRAY | PB_LTYPE_FIXED32,
|
||||||
|
pb_delta_end(AllTypes, rep_fixed32, rep_bool),
|
||||||
|
pb_delta(AllTypes, rep_fixed32_count, rep_fixed32),
|
||||||
|
pb_membersize(AllTypes, rep_fixed32[0]),
|
||||||
|
pb_membersize(AllTypes, rep_fixed32) / pb_membersize(AllTypes, rep_fixed32[0]), 0},
|
||||||
|
|
||||||
|
{29, PB_HTYPE_ARRAY | PB_LTYPE_FIXED32,
|
||||||
|
pb_delta_end(AllTypes, rep_sfixed32, rep_fixed32),
|
||||||
|
pb_delta(AllTypes, rep_sfixed32_count, rep_sfixed32),
|
||||||
|
pb_membersize(AllTypes, rep_sfixed32[0]),
|
||||||
|
pb_membersize(AllTypes, rep_sfixed32) / pb_membersize(AllTypes, rep_sfixed32[0]), 0},
|
||||||
|
|
||||||
|
{30, PB_HTYPE_ARRAY | PB_LTYPE_FIXED32,
|
||||||
|
pb_delta_end(AllTypes, rep_float, rep_sfixed32),
|
||||||
|
pb_delta(AllTypes, rep_float_count, rep_float),
|
||||||
|
pb_membersize(AllTypes, rep_float[0]),
|
||||||
|
pb_membersize(AllTypes, rep_float) / pb_membersize(AllTypes, rep_float[0]), 0},
|
||||||
|
|
||||||
|
{31, PB_HTYPE_ARRAY | PB_LTYPE_FIXED64,
|
||||||
|
pb_delta_end(AllTypes, rep_fixed64, rep_float),
|
||||||
|
pb_delta(AllTypes, rep_fixed64_count, rep_fixed64),
|
||||||
|
pb_membersize(AllTypes, rep_fixed64[0]),
|
||||||
|
pb_membersize(AllTypes, rep_fixed64) / pb_membersize(AllTypes, rep_fixed64[0]), 0},
|
||||||
|
|
||||||
|
{32, PB_HTYPE_ARRAY | PB_LTYPE_FIXED64,
|
||||||
|
pb_delta_end(AllTypes, rep_sfixed64, rep_fixed64),
|
||||||
|
pb_delta(AllTypes, rep_sfixed64_count, rep_sfixed64),
|
||||||
|
pb_membersize(AllTypes, rep_sfixed64[0]),
|
||||||
|
pb_membersize(AllTypes, rep_sfixed64) / pb_membersize(AllTypes, rep_sfixed64[0]), 0},
|
||||||
|
|
||||||
|
{33, PB_HTYPE_ARRAY | PB_LTYPE_FIXED64,
|
||||||
|
pb_delta_end(AllTypes, rep_double, rep_sfixed64),
|
||||||
|
pb_delta(AllTypes, rep_double_count, rep_double),
|
||||||
|
pb_membersize(AllTypes, rep_double[0]),
|
||||||
|
pb_membersize(AllTypes, rep_double) / pb_membersize(AllTypes, rep_double[0]), 0},
|
||||||
|
|
||||||
|
{34, PB_HTYPE_ARRAY | PB_LTYPE_STRING,
|
||||||
|
pb_delta_end(AllTypes, rep_string, rep_double),
|
||||||
|
pb_delta(AllTypes, rep_string_count, rep_string),
|
||||||
|
pb_membersize(AllTypes, rep_string[0]),
|
||||||
|
pb_membersize(AllTypes, rep_string) / pb_membersize(AllTypes, rep_string[0]), 0},
|
||||||
|
|
||||||
|
{35, PB_HTYPE_ARRAY | PB_LTYPE_BYTES,
|
||||||
|
pb_delta_end(AllTypes, rep_bytes, rep_string),
|
||||||
|
pb_delta(AllTypes, rep_bytes_count, rep_bytes),
|
||||||
|
pb_membersize(AllTypes, rep_bytes[0]),
|
||||||
|
pb_membersize(AllTypes, rep_bytes) / pb_membersize(AllTypes, rep_bytes[0]), 0},
|
||||||
|
|
||||||
|
{36, PB_HTYPE_ARRAY | PB_LTYPE_SUBMESSAGE,
|
||||||
|
pb_delta_end(AllTypes, rep_submsg, rep_bytes),
|
||||||
|
pb_delta(AllTypes, rep_submsg_count, rep_submsg),
|
||||||
|
pb_membersize(AllTypes, rep_submsg[0]),
|
||||||
|
pb_membersize(AllTypes, rep_submsg) / pb_membersize(AllTypes, rep_submsg[0]),
|
||||||
|
&SubMessage_fields},
|
||||||
|
|
||||||
|
{37, PB_HTYPE_ARRAY | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, rep_enum, rep_submsg),
|
||||||
|
pb_delta(AllTypes, rep_enum_count, rep_enum),
|
||||||
|
pb_membersize(AllTypes, rep_enum[0]),
|
||||||
|
pb_membersize(AllTypes, rep_enum) / pb_membersize(AllTypes, rep_enum[0]), 0},
|
||||||
|
|
||||||
|
{41, PB_HTYPE_OPTIONAL | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, opt_int32, rep_enum),
|
||||||
|
pb_delta(AllTypes, has_opt_int32, opt_int32),
|
||||||
|
pb_membersize(AllTypes, opt_int32), 0,
|
||||||
|
&AllTypes_opt_int32_default},
|
||||||
|
|
||||||
|
{42, PB_HTYPE_OPTIONAL | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, opt_int64, opt_int32),
|
||||||
|
pb_delta(AllTypes, has_opt_int64, opt_int64),
|
||||||
|
pb_membersize(AllTypes, opt_int64), 0,
|
||||||
|
&AllTypes_opt_int64_default},
|
||||||
|
|
||||||
|
{43, PB_HTYPE_OPTIONAL | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, opt_uint32, opt_int64),
|
||||||
|
pb_delta(AllTypes, has_opt_uint32, opt_uint32),
|
||||||
|
pb_membersize(AllTypes, opt_uint32), 0,
|
||||||
|
&AllTypes_opt_uint32_default},
|
||||||
|
|
||||||
|
{44, PB_HTYPE_OPTIONAL | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, opt_uint64, opt_uint32),
|
||||||
|
pb_delta(AllTypes, has_opt_uint64, opt_uint64),
|
||||||
|
pb_membersize(AllTypes, opt_uint64), 0,
|
||||||
|
&AllTypes_opt_uint64_default},
|
||||||
|
|
||||||
|
{45, PB_HTYPE_OPTIONAL | PB_LTYPE_SVARINT,
|
||||||
|
pb_delta_end(AllTypes, opt_sint32, opt_uint64),
|
||||||
|
pb_delta(AllTypes, has_opt_sint32, opt_sint32),
|
||||||
|
pb_membersize(AllTypes, opt_sint32), 0,
|
||||||
|
&AllTypes_opt_sint32_default},
|
||||||
|
|
||||||
|
{46, PB_HTYPE_OPTIONAL | PB_LTYPE_SVARINT,
|
||||||
|
pb_delta_end(AllTypes, opt_sint64, opt_sint32),
|
||||||
|
pb_delta(AllTypes, has_opt_sint64, opt_sint64),
|
||||||
|
pb_membersize(AllTypes, opt_sint64), 0,
|
||||||
|
&AllTypes_opt_sint64_default},
|
||||||
|
|
||||||
|
{47, PB_HTYPE_OPTIONAL | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, opt_bool, opt_sint64),
|
||||||
|
pb_delta(AllTypes, has_opt_bool, opt_bool),
|
||||||
|
pb_membersize(AllTypes, opt_bool), 0,
|
||||||
|
&AllTypes_opt_bool_default},
|
||||||
|
|
||||||
|
{48, PB_HTYPE_OPTIONAL | PB_LTYPE_FIXED32,
|
||||||
|
pb_delta_end(AllTypes, opt_fixed32, opt_bool),
|
||||||
|
pb_delta(AllTypes, has_opt_fixed32, opt_fixed32),
|
||||||
|
pb_membersize(AllTypes, opt_fixed32), 0,
|
||||||
|
&AllTypes_opt_fixed32_default},
|
||||||
|
|
||||||
|
{49, PB_HTYPE_OPTIONAL | PB_LTYPE_FIXED32,
|
||||||
|
pb_delta_end(AllTypes, opt_sfixed32, opt_fixed32),
|
||||||
|
pb_delta(AllTypes, has_opt_sfixed32, opt_sfixed32),
|
||||||
|
pb_membersize(AllTypes, opt_sfixed32), 0,
|
||||||
|
&AllTypes_opt_sfixed32_default},
|
||||||
|
|
||||||
|
{50, PB_HTYPE_OPTIONAL | PB_LTYPE_FIXED32,
|
||||||
|
pb_delta_end(AllTypes, opt_float, opt_sfixed32),
|
||||||
|
pb_delta(AllTypes, has_opt_float, opt_float),
|
||||||
|
pb_membersize(AllTypes, opt_float), 0,
|
||||||
|
&AllTypes_opt_float_default},
|
||||||
|
|
||||||
|
{51, PB_HTYPE_OPTIONAL | PB_LTYPE_FIXED64,
|
||||||
|
pb_delta_end(AllTypes, opt_fixed64, opt_float),
|
||||||
|
pb_delta(AllTypes, has_opt_fixed64, opt_fixed64),
|
||||||
|
pb_membersize(AllTypes, opt_fixed64), 0,
|
||||||
|
&AllTypes_opt_fixed64_default},
|
||||||
|
|
||||||
|
{52, PB_HTYPE_OPTIONAL | PB_LTYPE_FIXED64,
|
||||||
|
pb_delta_end(AllTypes, opt_sfixed64, opt_fixed64),
|
||||||
|
pb_delta(AllTypes, has_opt_sfixed64, opt_sfixed64),
|
||||||
|
pb_membersize(AllTypes, opt_sfixed64), 0,
|
||||||
|
&AllTypes_opt_sfixed64_default},
|
||||||
|
|
||||||
|
{53, PB_HTYPE_OPTIONAL | PB_LTYPE_FIXED64,
|
||||||
|
pb_delta_end(AllTypes, opt_double, opt_sfixed64),
|
||||||
|
pb_delta(AllTypes, has_opt_double, opt_double),
|
||||||
|
pb_membersize(AllTypes, opt_double), 0,
|
||||||
|
&AllTypes_opt_double_default},
|
||||||
|
|
||||||
|
{54, PB_HTYPE_OPTIONAL | PB_LTYPE_STRING,
|
||||||
|
pb_delta_end(AllTypes, opt_string, opt_double),
|
||||||
|
pb_delta(AllTypes, has_opt_string, opt_string),
|
||||||
|
pb_membersize(AllTypes, opt_string), 0,
|
||||||
|
&AllTypes_opt_string_default},
|
||||||
|
|
||||||
|
{55, PB_HTYPE_OPTIONAL | PB_LTYPE_BYTES,
|
||||||
|
pb_delta_end(AllTypes, opt_bytes, opt_string),
|
||||||
|
pb_delta(AllTypes, has_opt_bytes, opt_bytes),
|
||||||
|
pb_membersize(AllTypes, opt_bytes), 0,
|
||||||
|
&AllTypes_opt_bytes_default},
|
||||||
|
|
||||||
|
{56, PB_HTYPE_OPTIONAL | PB_LTYPE_SUBMESSAGE,
|
||||||
|
pb_delta_end(AllTypes, opt_submsg, opt_bytes),
|
||||||
|
pb_delta(AllTypes, has_opt_submsg, opt_submsg),
|
||||||
|
pb_membersize(AllTypes, opt_submsg), 0,
|
||||||
|
&SubMessage_fields},
|
||||||
|
|
||||||
|
{57, PB_HTYPE_OPTIONAL | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, opt_enum, opt_submsg),
|
||||||
|
pb_delta(AllTypes, has_opt_enum, opt_enum),
|
||||||
|
pb_membersize(AllTypes, opt_enum), 0,
|
||||||
|
&AllTypes_opt_enum_default},
|
||||||
|
|
||||||
|
{99, PB_HTYPE_REQUIRED | PB_LTYPE_VARINT,
|
||||||
|
pb_delta_end(AllTypes, end, opt_enum), 0,
|
||||||
|
pb_membersize(AllTypes, end), 0, 0},
|
||||||
|
|
||||||
|
PB_LAST_FIELD
|
||||||
|
};
|
||||||
|
|
||||||
155
tests/bc_alltypes.pb.h
Normal file
155
tests/bc_alltypes.pb.h
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
/* Automatically generated nanopb header */
|
||||||
|
/* This is a file generated using nanopb-0.1.1.
|
||||||
|
* It is used as a part of test suite in order to detect any
|
||||||
|
* incompatible changes made to the generator in future versions.
|
||||||
|
*/
|
||||||
|
#ifndef _PB_BC_ALLTYPES_PB_H_
|
||||||
|
#define _PB_BC_ALLTYPES_PB_H_
|
||||||
|
#include <pb.h>
|
||||||
|
|
||||||
|
/* Enum definitions */
|
||||||
|
typedef enum {
|
||||||
|
MyEnum_Zero = 0,
|
||||||
|
MyEnum_First = 1,
|
||||||
|
MyEnum_Second = 2,
|
||||||
|
MyEnum_Truth = 42
|
||||||
|
} MyEnum;
|
||||||
|
|
||||||
|
/* Struct definitions */
|
||||||
|
typedef struct {
|
||||||
|
char substuff1[16];
|
||||||
|
int32_t substuff2;
|
||||||
|
bool has_substuff3;
|
||||||
|
uint32_t substuff3;
|
||||||
|
} SubMessage;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t size;
|
||||||
|
uint8_t bytes[16];
|
||||||
|
} AllTypes_req_bytes_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t size;
|
||||||
|
uint8_t bytes[16];
|
||||||
|
} AllTypes_rep_bytes_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t size;
|
||||||
|
uint8_t bytes[16];
|
||||||
|
} AllTypes_opt_bytes_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t req_int32;
|
||||||
|
int64_t req_int64;
|
||||||
|
uint32_t req_uint32;
|
||||||
|
uint64_t req_uint64;
|
||||||
|
int32_t req_sint32;
|
||||||
|
int64_t req_sint64;
|
||||||
|
bool req_bool;
|
||||||
|
uint32_t req_fixed32;
|
||||||
|
int32_t req_sfixed32;
|
||||||
|
float req_float;
|
||||||
|
uint64_t req_fixed64;
|
||||||
|
int64_t req_sfixed64;
|
||||||
|
double req_double;
|
||||||
|
char req_string[16];
|
||||||
|
AllTypes_req_bytes_t req_bytes;
|
||||||
|
SubMessage req_submsg;
|
||||||
|
MyEnum req_enum;
|
||||||
|
size_t rep_int32_count;
|
||||||
|
int32_t rep_int32[5];
|
||||||
|
size_t rep_int64_count;
|
||||||
|
int64_t rep_int64[5];
|
||||||
|
size_t rep_uint32_count;
|
||||||
|
uint32_t rep_uint32[5];
|
||||||
|
size_t rep_uint64_count;
|
||||||
|
uint64_t rep_uint64[5];
|
||||||
|
size_t rep_sint32_count;
|
||||||
|
int32_t rep_sint32[5];
|
||||||
|
size_t rep_sint64_count;
|
||||||
|
int64_t rep_sint64[5];
|
||||||
|
size_t rep_bool_count;
|
||||||
|
bool rep_bool[5];
|
||||||
|
size_t rep_fixed32_count;
|
||||||
|
uint32_t rep_fixed32[5];
|
||||||
|
size_t rep_sfixed32_count;
|
||||||
|
int32_t rep_sfixed32[5];
|
||||||
|
size_t rep_float_count;
|
||||||
|
float rep_float[5];
|
||||||
|
size_t rep_fixed64_count;
|
||||||
|
uint64_t rep_fixed64[5];
|
||||||
|
size_t rep_sfixed64_count;
|
||||||
|
int64_t rep_sfixed64[5];
|
||||||
|
size_t rep_double_count;
|
||||||
|
double rep_double[5];
|
||||||
|
size_t rep_string_count;
|
||||||
|
char rep_string[5][16];
|
||||||
|
size_t rep_bytes_count;
|
||||||
|
AllTypes_rep_bytes_t rep_bytes[5];
|
||||||
|
size_t rep_submsg_count;
|
||||||
|
SubMessage rep_submsg[5];
|
||||||
|
size_t rep_enum_count;
|
||||||
|
MyEnum rep_enum[5];
|
||||||
|
bool has_opt_int32;
|
||||||
|
int32_t opt_int32;
|
||||||
|
bool has_opt_int64;
|
||||||
|
int64_t opt_int64;
|
||||||
|
bool has_opt_uint32;
|
||||||
|
uint32_t opt_uint32;
|
||||||
|
bool has_opt_uint64;
|
||||||
|
uint64_t opt_uint64;
|
||||||
|
bool has_opt_sint32;
|
||||||
|
int32_t opt_sint32;
|
||||||
|
bool has_opt_sint64;
|
||||||
|
int64_t opt_sint64;
|
||||||
|
bool has_opt_bool;
|
||||||
|
bool opt_bool;
|
||||||
|
bool has_opt_fixed32;
|
||||||
|
uint32_t opt_fixed32;
|
||||||
|
bool has_opt_sfixed32;
|
||||||
|
int32_t opt_sfixed32;
|
||||||
|
bool has_opt_float;
|
||||||
|
float opt_float;
|
||||||
|
bool has_opt_fixed64;
|
||||||
|
uint64_t opt_fixed64;
|
||||||
|
bool has_opt_sfixed64;
|
||||||
|
int64_t opt_sfixed64;
|
||||||
|
bool has_opt_double;
|
||||||
|
double opt_double;
|
||||||
|
bool has_opt_string;
|
||||||
|
char opt_string[16];
|
||||||
|
bool has_opt_bytes;
|
||||||
|
AllTypes_opt_bytes_t opt_bytes;
|
||||||
|
bool has_opt_submsg;
|
||||||
|
SubMessage opt_submsg;
|
||||||
|
bool has_opt_enum;
|
||||||
|
MyEnum opt_enum;
|
||||||
|
int32_t end;
|
||||||
|
} AllTypes;
|
||||||
|
|
||||||
|
/* Default values for struct fields */
|
||||||
|
extern const char SubMessage_substuff1_default[17];
|
||||||
|
extern const int32_t SubMessage_substuff2_default;
|
||||||
|
extern const uint32_t SubMessage_substuff3_default;
|
||||||
|
extern const int32_t AllTypes_opt_int32_default;
|
||||||
|
extern const int64_t AllTypes_opt_int64_default;
|
||||||
|
extern const uint32_t AllTypes_opt_uint32_default;
|
||||||
|
extern const uint64_t AllTypes_opt_uint64_default;
|
||||||
|
extern const int32_t AllTypes_opt_sint32_default;
|
||||||
|
extern const int64_t AllTypes_opt_sint64_default;
|
||||||
|
extern const bool AllTypes_opt_bool_default;
|
||||||
|
extern const uint32_t AllTypes_opt_fixed32_default;
|
||||||
|
extern const int32_t AllTypes_opt_sfixed32_default;
|
||||||
|
extern const float AllTypes_opt_float_default;
|
||||||
|
extern const uint64_t AllTypes_opt_fixed64_default;
|
||||||
|
extern const int64_t AllTypes_opt_sfixed64_default;
|
||||||
|
extern const double AllTypes_opt_double_default;
|
||||||
|
extern const char AllTypes_opt_string_default[17];
|
||||||
|
extern const AllTypes_opt_bytes_t AllTypes_opt_bytes_default;
|
||||||
|
extern const MyEnum AllTypes_opt_enum_default;
|
||||||
|
|
||||||
|
/* Struct field encoding specification for nanopb */
|
||||||
|
extern const pb_field_t SubMessage_fields[4];
|
||||||
|
extern const pb_field_t AllTypes_fields[53];
|
||||||
|
|
||||||
|
#endif
|
||||||
197
tests/bc_decode.c
Normal file
197
tests/bc_decode.c
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
/* Tests the decoding of all types.
|
||||||
|
* This is a backwards-compatibility test, using bc_alltypes.pb.h.
|
||||||
|
* It is similar to test_decode3, but duplicated in order to allow
|
||||||
|
* test_decode3 to test any new features introduced later.
|
||||||
|
*
|
||||||
|
* Run e.g. ./bc_encode | ./bc_decode
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pb_decode.h>
|
||||||
|
#include "bc_alltypes.pb.h"
|
||||||
|
|
||||||
|
#define TEST(x) if (!(x)) { \
|
||||||
|
printf("Test " #x " failed.\n"); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is called once from main(), it handles
|
||||||
|
the decoding and checks the fields. */
|
||||||
|
bool check_alltypes(pb_istream_t *stream, int mode)
|
||||||
|
{
|
||||||
|
AllTypes alltypes;
|
||||||
|
|
||||||
|
/* Fill with garbage to better detect initialization errors */
|
||||||
|
memset(&alltypes, 0xAA, sizeof(alltypes));
|
||||||
|
|
||||||
|
if (!pb_decode(stream, AllTypes_fields, &alltypes))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TEST(alltypes.req_int32 == -1001);
|
||||||
|
TEST(alltypes.req_int64 == -1002);
|
||||||
|
TEST(alltypes.req_uint32 == 1003);
|
||||||
|
TEST(alltypes.req_uint64 == 1004);
|
||||||
|
TEST(alltypes.req_sint32 == -1005);
|
||||||
|
TEST(alltypes.req_sint64 == -1006);
|
||||||
|
TEST(alltypes.req_bool == true);
|
||||||
|
|
||||||
|
TEST(alltypes.req_fixed32 == 1008);
|
||||||
|
TEST(alltypes.req_sfixed32 == -1009);
|
||||||
|
TEST(alltypes.req_float == 1010.0f);
|
||||||
|
|
||||||
|
TEST(alltypes.req_fixed64 == 1011);
|
||||||
|
TEST(alltypes.req_sfixed64 == -1012);
|
||||||
|
TEST(alltypes.req_double == 1013.0f);
|
||||||
|
|
||||||
|
TEST(strcmp(alltypes.req_string, "1014") == 0);
|
||||||
|
TEST(alltypes.req_bytes.size == 4);
|
||||||
|
TEST(memcmp(alltypes.req_bytes.bytes, "1015", 4) == 0);
|
||||||
|
TEST(strcmp(alltypes.req_submsg.substuff1, "1016") == 0);
|
||||||
|
TEST(alltypes.req_submsg.substuff2 == 1016);
|
||||||
|
TEST(alltypes.req_submsg.substuff3 == 3);
|
||||||
|
TEST(alltypes.req_enum == MyEnum_Truth);
|
||||||
|
|
||||||
|
TEST(alltypes.rep_int32_count == 5 && alltypes.rep_int32[4] == -2001 && alltypes.rep_int32[0] == 0);
|
||||||
|
TEST(alltypes.rep_int64_count == 5 && alltypes.rep_int64[4] == -2002 && alltypes.rep_int64[0] == 0);
|
||||||
|
TEST(alltypes.rep_uint32_count == 5 && alltypes.rep_uint32[4] == 2003 && alltypes.rep_uint32[0] == 0);
|
||||||
|
TEST(alltypes.rep_uint64_count == 5 && alltypes.rep_uint64[4] == 2004 && alltypes.rep_uint64[0] == 0);
|
||||||
|
TEST(alltypes.rep_sint32_count == 5 && alltypes.rep_sint32[4] == -2005 && alltypes.rep_sint32[0] == 0);
|
||||||
|
TEST(alltypes.rep_sint64_count == 5 && alltypes.rep_sint64[4] == -2006 && alltypes.rep_sint64[0] == 0);
|
||||||
|
TEST(alltypes.rep_bool_count == 5 && alltypes.rep_bool[4] == true && alltypes.rep_bool[0] == false);
|
||||||
|
|
||||||
|
TEST(alltypes.rep_fixed32_count == 5 && alltypes.rep_fixed32[4] == 2008 && alltypes.rep_fixed32[0] == 0);
|
||||||
|
TEST(alltypes.rep_sfixed32_count == 5 && alltypes.rep_sfixed32[4] == -2009 && alltypes.rep_sfixed32[0] == 0);
|
||||||
|
TEST(alltypes.rep_float_count == 5 && alltypes.rep_float[4] == 2010.0f && alltypes.rep_float[0] == 0.0f);
|
||||||
|
|
||||||
|
TEST(alltypes.rep_fixed64_count == 5 && alltypes.rep_fixed64[4] == 2011 && alltypes.rep_fixed64[0] == 0);
|
||||||
|
TEST(alltypes.rep_sfixed64_count == 5 && alltypes.rep_sfixed64[4] == -2012 && alltypes.rep_sfixed64[0] == 0);
|
||||||
|
TEST(alltypes.rep_double_count == 5 && alltypes.rep_double[4] == 2013.0 && alltypes.rep_double[0] == 0.0);
|
||||||
|
|
||||||
|
TEST(alltypes.rep_string_count == 5 && strcmp(alltypes.rep_string[4], "2014") == 0 && alltypes.rep_string[0][0] == '\0');
|
||||||
|
TEST(alltypes.rep_bytes_count == 5 && alltypes.rep_bytes[4].size == 4 && alltypes.rep_bytes[0].size == 0);
|
||||||
|
TEST(memcmp(alltypes.rep_bytes[4].bytes, "2015", 4) == 0);
|
||||||
|
|
||||||
|
TEST(alltypes.rep_submsg_count == 5);
|
||||||
|
TEST(strcmp(alltypes.rep_submsg[4].substuff1, "2016") == 0 && alltypes.rep_submsg[0].substuff1[0] == '\0');
|
||||||
|
TEST(alltypes.rep_submsg[4].substuff2 == 2016 && alltypes.rep_submsg[0].substuff2 == 0);
|
||||||
|
TEST(alltypes.rep_submsg[4].substuff3 == 2016 && alltypes.rep_submsg[0].substuff3 == 3);
|
||||||
|
|
||||||
|
TEST(alltypes.rep_enum_count == 5 && alltypes.rep_enum[4] == MyEnum_Truth && alltypes.rep_enum[0] == MyEnum_Zero);
|
||||||
|
|
||||||
|
if (mode == 0)
|
||||||
|
{
|
||||||
|
/* Expect default values */
|
||||||
|
TEST(alltypes.has_opt_int32 == false);
|
||||||
|
TEST(alltypes.opt_int32 == 4041);
|
||||||
|
TEST(alltypes.has_opt_int64 == false);
|
||||||
|
TEST(alltypes.opt_int64 == 4042);
|
||||||
|
TEST(alltypes.has_opt_uint32 == false);
|
||||||
|
TEST(alltypes.opt_uint32 == 4043);
|
||||||
|
TEST(alltypes.has_opt_uint64 == false);
|
||||||
|
TEST(alltypes.opt_uint64 == 4044);
|
||||||
|
TEST(alltypes.has_opt_sint32 == false);
|
||||||
|
TEST(alltypes.opt_sint32 == 4045);
|
||||||
|
TEST(alltypes.has_opt_sint64 == false);
|
||||||
|
TEST(alltypes.opt_sint64 == 4046);
|
||||||
|
TEST(alltypes.has_opt_bool == false);
|
||||||
|
TEST(alltypes.opt_bool == false);
|
||||||
|
|
||||||
|
TEST(alltypes.has_opt_fixed32 == false);
|
||||||
|
TEST(alltypes.opt_fixed32 == 4048);
|
||||||
|
TEST(alltypes.has_opt_sfixed32 == false);
|
||||||
|
TEST(alltypes.opt_sfixed32 == 4049);
|
||||||
|
TEST(alltypes.has_opt_float == false);
|
||||||
|
TEST(alltypes.opt_float == 4050.0f);
|
||||||
|
|
||||||
|
TEST(alltypes.has_opt_fixed64 == false);
|
||||||
|
TEST(alltypes.opt_fixed64 == 4051);
|
||||||
|
TEST(alltypes.has_opt_sfixed64 == false);
|
||||||
|
TEST(alltypes.opt_sfixed64 == 4052);
|
||||||
|
TEST(alltypes.has_opt_double == false);
|
||||||
|
TEST(alltypes.opt_double == 4053.0);
|
||||||
|
|
||||||
|
TEST(alltypes.has_opt_string == false);
|
||||||
|
TEST(strcmp(alltypes.opt_string, "4054") == 0);
|
||||||
|
TEST(alltypes.has_opt_bytes == false);
|
||||||
|
TEST(alltypes.opt_bytes.size == 4);
|
||||||
|
TEST(memcmp(alltypes.opt_bytes.bytes, "4055", 4) == 0);
|
||||||
|
TEST(alltypes.has_opt_submsg == false);
|
||||||
|
TEST(strcmp(alltypes.opt_submsg.substuff1, "1") == 0);
|
||||||
|
TEST(alltypes.opt_submsg.substuff2 == 2);
|
||||||
|
TEST(alltypes.opt_submsg.substuff3 == 3);
|
||||||
|
TEST(alltypes.has_opt_enum == false);
|
||||||
|
TEST(alltypes.opt_enum == MyEnum_Second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Expect filled-in values */
|
||||||
|
TEST(alltypes.has_opt_int32 == true);
|
||||||
|
TEST(alltypes.opt_int32 == 3041);
|
||||||
|
TEST(alltypes.has_opt_int64 == true);
|
||||||
|
TEST(alltypes.opt_int64 == 3042);
|
||||||
|
TEST(alltypes.has_opt_uint32 == true);
|
||||||
|
TEST(alltypes.opt_uint32 == 3043);
|
||||||
|
TEST(alltypes.has_opt_uint64 == true);
|
||||||
|
TEST(alltypes.opt_uint64 == 3044);
|
||||||
|
TEST(alltypes.has_opt_sint32 == true);
|
||||||
|
TEST(alltypes.opt_sint32 == 3045);
|
||||||
|
TEST(alltypes.has_opt_sint64 == true);
|
||||||
|
TEST(alltypes.opt_sint64 == 3046);
|
||||||
|
TEST(alltypes.has_opt_bool == true);
|
||||||
|
TEST(alltypes.opt_bool == true);
|
||||||
|
|
||||||
|
TEST(alltypes.has_opt_fixed32 == true);
|
||||||
|
TEST(alltypes.opt_fixed32 == 3048);
|
||||||
|
TEST(alltypes.has_opt_sfixed32 == true);
|
||||||
|
TEST(alltypes.opt_sfixed32 == 3049);
|
||||||
|
TEST(alltypes.has_opt_float == true);
|
||||||
|
TEST(alltypes.opt_float == 3050.0f);
|
||||||
|
|
||||||
|
TEST(alltypes.has_opt_fixed64 == true);
|
||||||
|
TEST(alltypes.opt_fixed64 == 3051);
|
||||||
|
TEST(alltypes.has_opt_sfixed64 == true);
|
||||||
|
TEST(alltypes.opt_sfixed64 == 3052);
|
||||||
|
TEST(alltypes.has_opt_double == true);
|
||||||
|
TEST(alltypes.opt_double == 3053.0);
|
||||||
|
|
||||||
|
TEST(alltypes.has_opt_string == true);
|
||||||
|
TEST(strcmp(alltypes.opt_string, "3054") == 0);
|
||||||
|
TEST(alltypes.has_opt_bytes == true);
|
||||||
|
TEST(alltypes.opt_bytes.size == 4);
|
||||||
|
TEST(memcmp(alltypes.opt_bytes.bytes, "3055", 4) == 0);
|
||||||
|
TEST(alltypes.has_opt_submsg == true);
|
||||||
|
TEST(strcmp(alltypes.opt_submsg.substuff1, "3056") == 0);
|
||||||
|
TEST(alltypes.opt_submsg.substuff2 == 3056);
|
||||||
|
TEST(alltypes.opt_submsg.substuff3 == 3);
|
||||||
|
TEST(alltypes.has_opt_enum == true);
|
||||||
|
TEST(alltypes.opt_enum == MyEnum_Truth);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(alltypes.end == 1099);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
/* Whether to expect the optional values or the default values. */
|
||||||
|
int mode = (argc > 1) ? atoi(argv[1]) : 0;
|
||||||
|
|
||||||
|
/* Read the data into buffer */
|
||||||
|
uint8_t buffer[1024];
|
||||||
|
size_t count = fread(buffer, 1, sizeof(buffer), stdin);
|
||||||
|
|
||||||
|
/* Construct a pb_istream_t for reading from the buffer */
|
||||||
|
pb_istream_t stream = pb_istream_from_buffer(buffer, count);
|
||||||
|
|
||||||
|
/* Decode and print out the stuff */
|
||||||
|
if (!check_alltypes(&stream, mode))
|
||||||
|
{
|
||||||
|
printf("Parsing failed: %s\n", PB_GET_ERROR(&stream));
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
131
tests/bc_encode.c
Normal file
131
tests/bc_encode.c
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/* Attempts to test all the datatypes supported by ProtoBuf.
|
||||||
|
* This is a backwards-compatibility test, using bc_alltypes.pb.h.
|
||||||
|
* It is similar to test_encode3, but duplicated in order to allow
|
||||||
|
* test_encode3 to test any new features introduced later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <pb_encode.h>
|
||||||
|
#include "bc_alltypes.pb.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int mode = (argc > 1) ? atoi(argv[1]) : 0;
|
||||||
|
|
||||||
|
/* Initialize the structure with constants */
|
||||||
|
AllTypes alltypes = {0};
|
||||||
|
|
||||||
|
alltypes.req_int32 = -1001;
|
||||||
|
alltypes.req_int64 = -1002;
|
||||||
|
alltypes.req_uint32 = 1003;
|
||||||
|
alltypes.req_uint64 = 1004;
|
||||||
|
alltypes.req_sint32 = -1005;
|
||||||
|
alltypes.req_sint64 = -1006;
|
||||||
|
alltypes.req_bool = true;
|
||||||
|
|
||||||
|
alltypes.req_fixed32 = 1008;
|
||||||
|
alltypes.req_sfixed32 = -1009;
|
||||||
|
alltypes.req_float = 1010.0f;
|
||||||
|
|
||||||
|
alltypes.req_fixed64 = 1011;
|
||||||
|
alltypes.req_sfixed64 = -1012;
|
||||||
|
alltypes.req_double = 1013.0;
|
||||||
|
|
||||||
|
strcpy(alltypes.req_string, "1014");
|
||||||
|
alltypes.req_bytes.size = 4;
|
||||||
|
memcpy(alltypes.req_bytes.bytes, "1015", 4);
|
||||||
|
strcpy(alltypes.req_submsg.substuff1, "1016");
|
||||||
|
alltypes.req_submsg.substuff2 = 1016;
|
||||||
|
alltypes.req_enum = MyEnum_Truth;
|
||||||
|
|
||||||
|
alltypes.rep_int32_count = 5; alltypes.rep_int32[4] = -2001;
|
||||||
|
alltypes.rep_int64_count = 5; alltypes.rep_int64[4] = -2002;
|
||||||
|
alltypes.rep_uint32_count = 5; alltypes.rep_uint32[4] = 2003;
|
||||||
|
alltypes.rep_uint64_count = 5; alltypes.rep_uint64[4] = 2004;
|
||||||
|
alltypes.rep_sint32_count = 5; alltypes.rep_sint32[4] = -2005;
|
||||||
|
alltypes.rep_sint64_count = 5; alltypes.rep_sint64[4] = -2006;
|
||||||
|
alltypes.rep_bool_count = 5; alltypes.rep_bool[4] = true;
|
||||||
|
|
||||||
|
alltypes.rep_fixed32_count = 5; alltypes.rep_fixed32[4] = 2008;
|
||||||
|
alltypes.rep_sfixed32_count = 5; alltypes.rep_sfixed32[4] = -2009;
|
||||||
|
alltypes.rep_float_count = 5; alltypes.rep_float[4] = 2010.0f;
|
||||||
|
|
||||||
|
alltypes.rep_fixed64_count = 5; alltypes.rep_fixed64[4] = 2011;
|
||||||
|
alltypes.rep_sfixed64_count = 5; alltypes.rep_sfixed64[4] = -2012;
|
||||||
|
alltypes.rep_double_count = 5; alltypes.rep_double[4] = 2013.0;
|
||||||
|
|
||||||
|
alltypes.rep_string_count = 5; strcpy(alltypes.rep_string[4], "2014");
|
||||||
|
alltypes.rep_bytes_count = 5; alltypes.rep_bytes[4].size = 4;
|
||||||
|
memcpy(alltypes.rep_bytes[4].bytes, "2015", 4);
|
||||||
|
|
||||||
|
alltypes.rep_submsg_count = 5;
|
||||||
|
strcpy(alltypes.rep_submsg[4].substuff1, "2016");
|
||||||
|
alltypes.rep_submsg[4].substuff2 = 2016;
|
||||||
|
alltypes.rep_submsg[4].has_substuff3 = true;
|
||||||
|
alltypes.rep_submsg[4].substuff3 = 2016;
|
||||||
|
|
||||||
|
alltypes.rep_enum_count = 5; alltypes.rep_enum[4] = MyEnum_Truth;
|
||||||
|
|
||||||
|
if (mode != 0)
|
||||||
|
{
|
||||||
|
/* Fill in values for optional fields */
|
||||||
|
alltypes.has_opt_int32 = true;
|
||||||
|
alltypes.opt_int32 = 3041;
|
||||||
|
alltypes.has_opt_int64 = true;
|
||||||
|
alltypes.opt_int64 = 3042;
|
||||||
|
alltypes.has_opt_uint32 = true;
|
||||||
|
alltypes.opt_uint32 = 3043;
|
||||||
|
alltypes.has_opt_uint64 = true;
|
||||||
|
alltypes.opt_uint64 = 3044;
|
||||||
|
alltypes.has_opt_sint32 = true;
|
||||||
|
alltypes.opt_sint32 = 3045;
|
||||||
|
alltypes.has_opt_sint64 = true;
|
||||||
|
alltypes.opt_sint64 = 3046;
|
||||||
|
alltypes.has_opt_bool = true;
|
||||||
|
alltypes.opt_bool = true;
|
||||||
|
|
||||||
|
alltypes.has_opt_fixed32 = true;
|
||||||
|
alltypes.opt_fixed32 = 3048;
|
||||||
|
alltypes.has_opt_sfixed32 = true;
|
||||||
|
alltypes.opt_sfixed32 = 3049;
|
||||||
|
alltypes.has_opt_float = true;
|
||||||
|
alltypes.opt_float = 3050.0f;
|
||||||
|
|
||||||
|
alltypes.has_opt_fixed64 = true;
|
||||||
|
alltypes.opt_fixed64 = 3051;
|
||||||
|
alltypes.has_opt_sfixed64 = true;
|
||||||
|
alltypes.opt_sfixed64 = 3052;
|
||||||
|
alltypes.has_opt_double = true;
|
||||||
|
alltypes.opt_double = 3053.0;
|
||||||
|
|
||||||
|
alltypes.has_opt_string = true;
|
||||||
|
strcpy(alltypes.opt_string, "3054");
|
||||||
|
alltypes.has_opt_bytes = true;
|
||||||
|
alltypes.opt_bytes.size = 4;
|
||||||
|
memcpy(alltypes.opt_bytes.bytes, "3055", 4);
|
||||||
|
alltypes.has_opt_submsg = true;
|
||||||
|
strcpy(alltypes.opt_submsg.substuff1, "3056");
|
||||||
|
alltypes.opt_submsg.substuff2 = 3056;
|
||||||
|
alltypes.has_opt_enum = true;
|
||||||
|
alltypes.opt_enum = MyEnum_Truth;
|
||||||
|
}
|
||||||
|
|
||||||
|
alltypes.end = 1099;
|
||||||
|
|
||||||
|
uint8_t buffer[1024];
|
||||||
|
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
/* Now encode it and check if we succeeded. */
|
||||||
|
if (pb_encode(&stream, AllTypes_fields, &alltypes))
|
||||||
|
{
|
||||||
|
fwrite(buffer, 1, stream.bytes_written, stdout);
|
||||||
|
return 0; /* Success */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Encoding failed!\n");
|
||||||
|
return 1; /* Failure */
|
||||||
|
}
|
||||||
|
}
|
||||||
0
tests/funny-proto+name.proto
Normal file
0
tests/funny-proto+name.proto
Normal file
@@ -4,3 +4,4 @@ char fieldsize\[40\];
|
|||||||
pb_callback_t int32_callback;
|
pb_callback_t int32_callback;
|
||||||
\sEnumValue1 = 1
|
\sEnumValue1 = 1
|
||||||
Message5_EnumValue1
|
Message5_EnumValue1
|
||||||
|
} pb_packed my_packed_struct;
|
||||||
|
|||||||
@@ -54,3 +54,20 @@ message Message5
|
|||||||
}
|
}
|
||||||
required Enum2 field = 1 [default = EnumValue1];
|
required Enum2 field = 1 [default = EnumValue1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Packed structure
|
||||||
|
message my_packed_struct
|
||||||
|
{
|
||||||
|
option (nanopb_msgopt).packed_struct = true;
|
||||||
|
optional int32 myfield = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message with ignored field
|
||||||
|
// Note: doesn't really test if the field is missing in the output,
|
||||||
|
// but atleast tests that the output compiles.
|
||||||
|
message Message6
|
||||||
|
{
|
||||||
|
required int32 field1 = 1;
|
||||||
|
optional int32 field2 = 2 [(nanopb).type = FT_IGNORE];
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user