Import of the watch repository from Pebble

This commit is contained in:
Matthieu Jeanson 2024-12-12 16:43:03 -08:00 committed by Katharine Berry
commit 3b92768480
10334 changed files with 2564465 additions and 0 deletions

View file

@ -0,0 +1,22 @@
# Test decoder callback support inside oneofs.
Import('env')
env.NanopbProto('oneof')
enc = env.Program(['encode_oneof.c',
'oneof.pb.c',
'$COMMON/pb_encode.o',
'$COMMON/pb_common.o'])
dec = env.Program(['decode_oneof.c',
'oneof.pb.c',
'$COMMON/pb_decode.o',
'$COMMON/pb_common.o'])
for i in range(1,7):
# Encode message, then decode with protoc and test program and compare.
e = env.RunTest("message%d.pb" % i, enc, ARGS = [str(i)])
d1 = env.Decode([e, "oneof.proto"], MESSAGE = "OneOfMessage")
d2 = env.RunTest("message%d.txt" % i, [dec, e])
env.Compare([d1, d2])

View file

@ -0,0 +1,174 @@
/* Decode a message using callbacks inside oneof fields */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pb_decode.h>
#include <assert.h>
#include "oneof.pb.h"
#include "test_helpers.h"
#include "unittests.h"
/* This is a nanopb-0.4 style global callback, that is referred by function name
* and does not have to be bound separately to the message. It also allows defining
* a custom data type for the field in the structure.
*/
bool SubMsg3_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
{
if (istream && field->tag == SubMsg3_strvalue_tag)
{
/* We could e.g. malloc some memory and assign it to our custom datatype
* in the message structure here, accessible by field->pData. But in
* this example we just print the string directly.
*/
uint8_t buffer[64];
int strlen = istream->bytes_left;
if (strlen > sizeof(buffer) - 1)
return false;
buffer[strlen] = '\0';
if (!pb_read(istream, buffer, strlen))
return false;
printf(" strvalue: \"%s\"\n", buffer);
}
return true;
}
/* The two callbacks below are traditional callbacks that use function pointers
* defined in pb_callback_t.
*/
bool print_int32(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint64_t value;
if (!pb_decode_varint(stream, &value))
return false;
printf((char*)*arg, (int)value);
return true;
}
bool print_string(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
uint8_t buffer[64];
int strlen = stream->bytes_left;
if (strlen > sizeof(buffer) - 1)
return false;
buffer[strlen] = '\0';
if (!pb_read(stream, buffer, strlen))
return false;
/* Print the string, in format comparable with protoc --decode.
* Format comes from the arg defined in main().
*/
printf((char*)*arg, buffer);
return true;
}
/* The callback below is a message-level callback which is called before each
* submessage is encoded. It is used to set the pb_callback_t callbacks inside
* the submessage. The reason we need this is that different submessages share
* storage inside oneof union, and before we know the message type we can't set
* the callbacks without overwriting each other.
*/
bool msg_callback(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
/* Print the prefix field before the submessages.
* This also demonstrates how to access the top level message fields
* from callbacks.
*/
OneOfMessage *topmsg = field->message;
printf("prefix: %d\n", (int)topmsg->prefix);
if (field->tag == OneOfMessage_submsg1_tag)
{
SubMsg1 *msg = field->pData;
printf("submsg1 {\n");
msg->array.funcs.decode = print_int32;
msg->array.arg = " array: %d\n";
}
else if (field->tag == OneOfMessage_submsg2_tag)
{
SubMsg2 *msg = field->pData;
printf("submsg2 {\n");
msg->strvalue.funcs.decode = print_string;
msg->strvalue.arg = " strvalue: \"%s\"\n";
}
else if (field->tag == OneOfMessage_submsg3_tag)
{
/* Because SubMsg3 callback is bound by function name, we do not
* need to initialize anything here. But we just print a string
* to get protoc-equivalent formatted output from the testcase.
*/
printf("submsg3 {\n");
}
/* Once we return true, pb_dec_submessage() will go on to decode the
* submessage contents. But if we want, we can also decode it ourselves
* above and leave stream->bytes_left at 0 value, inhibiting automatic
* decoding.
*/
return true;
}
int main(int argc, char **argv)
{
uint8_t buffer[256];
OneOfMessage msg = OneOfMessage_init_zero;
pb_istream_t stream;
size_t count;
SET_BINARY_MODE(stdin);
count = fread(buffer, 1, sizeof(buffer), stdin);
if (!feof(stdin))
{
fprintf(stderr, "Message does not fit in buffer\n");
return 1;
}
/* Set up the cb_values callback, which will in turn set up the callbacks
* for each oneof field once the field tag is known. */
msg.cb_values.funcs.decode = msg_callback;
stream = pb_istream_from_buffer(buffer, count);
if (!pb_decode(&stream, OneOfMessage_fields, &msg))
{
fprintf(stderr, "Decoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
/* This is just printing for the test case logic */
if (msg.which_values == OneOfMessage_intvalue_tag)
{
printf("prefix: %d\n", (int)msg.prefix);
printf("intvalue: %d\n", (int)msg.values.intvalue);
}
else if (msg.which_values == OneOfMessage_strvalue_tag)
{
printf("prefix: %d\n", (int)msg.prefix);
printf("strvalue: \"%s\"\n", msg.values.strvalue);
}
else if (msg.which_values == OneOfMessage_submsg3_tag &&
msg.values.submsg3.which_values == SubMsg3_intvalue_tag)
{
printf(" intvalue: %d\n", (int)msg.values.submsg3.values.intvalue);
printf("}\n");
}
else
{
printf("}\n");
}
printf("suffix: %d\n", (int)msg.suffix);
assert(msg.prefix == 123);
assert(msg.suffix == 321);
return 0;
}

View file

@ -0,0 +1,126 @@
/* Encode a message using callbacks inside oneof fields.
* For encoding, callbacks inside oneofs require nothing special
* so this is just normal callback usage.
*/
#include <stdio.h>
#include <stdlib.h>
#include <pb_encode.h>
#include "oneof.pb.h"
#include "test_helpers.h"
/* This is a nanopb-0.4 style global callback, that is referred by function name
* and does not have to be bound separately to the message. It also allows defining
* a custom data type for the field in the structure.
*/
bool SubMsg3_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
{
if (ostream && field->tag == SubMsg3_strvalue_tag)
{
/* Our custom data type is char* */
const char *str = *(const char**)field->pData;
if (!pb_encode_tag_for_field(ostream, field))
return false;
return pb_encode_string(ostream, (const uint8_t*)str, strlen(str));
}
return true;
}
/* The two callbacks below are traditional callbacks that use function pointers
* defined in pb_callback_t.
*/
bool encode_int32_array(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
int i;
for (i = 0; i < 15; i++)
{
if (!pb_encode_tag_for_field(stream, field))
return false;
if (!pb_encode_varint(stream, i))
return false;
}
return true;
}
bool encode_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
const char *str = "mystring";
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_string(stream, (const uint8_t*)str, strlen(str));
}
int main(int argc, char **argv)
{
uint8_t buffer[256];
OneOfMessage msg = OneOfMessage_init_zero;
pb_ostream_t stream;
int option;
if (argc != 2)
{
fprintf(stderr, "Usage: encode_oneof [number]\n");
return 1;
}
option = atoi(argv[1]);
/* Prefix and suffix are used to test that the union does not disturb
* other fields in the same message. */
msg.prefix = 123;
/* We encode one of the 'values' fields based on command line argument */
if (option == 1)
{
msg.which_values = OneOfMessage_intvalue_tag;
msg.values.intvalue = 999;
}
else if (option == 2)
{
msg.which_values = OneOfMessage_strvalue_tag;
strcpy(msg.values.strvalue, "abcd");
}
else if (option == 3)
{
msg.which_values = OneOfMessage_submsg1_tag;
msg.values.submsg1.array.funcs.encode = encode_int32_array;
}
else if (option == 4)
{
msg.which_values = OneOfMessage_submsg2_tag;
msg.values.submsg2.strvalue.funcs.encode = encode_string;
}
else if (option == 5)
{
msg.which_values = OneOfMessage_submsg3_tag;
msg.values.submsg3.which_values = SubMsg3_intvalue_tag;
msg.values.submsg3.values.intvalue = 1234;
}
else if (option == 6)
{
msg.which_values = OneOfMessage_submsg3_tag;
msg.values.submsg3.which_values = SubMsg3_strvalue_tag;
msg.values.submsg3.values.strvalue = "efgh";
}
msg.suffix = 321;
stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
if (pb_encode(&stream, OneOfMessage_fields, &msg))
{
SET_BINARY_MODE(stdout);
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0;
}
else
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
}

View file

@ -0,0 +1,41 @@
syntax = "proto3";
import 'nanopb.proto';
// Repeated callback inside submessage inside oneof
message SubMsg1
{
repeated int32 array = 1;
}
// String callback inside submessage inside oneof
message SubMsg2
{
string strvalue = 1;
}
// String callback directly inside oneof
message SubMsg3
{
oneof values
{
int32 intvalue = 1;
string strvalue = 2 [(nanopb).callback_datatype = "const char*"];
}
}
message OneOfMessage
{
option (nanopb_msgopt).submsg_callback = true;
int32 prefix = 1;
oneof values
{
int32 intvalue = 5;
string strvalue = 6 [(nanopb).max_size = 8];
SubMsg1 submsg1 = 7;
SubMsg2 submsg2 = 8;
SubMsg3 submsg3 = 9;
}
int32 suffix = 99;
}