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

116
third_party/nanopb/AUTHORS.txt vendored Normal file
View file

@ -0,0 +1,116 @@
Petteri Aimonen <jpa@npb.mail.kapsi.fi>
Michael Poole <mdpoole@troilus.org>
Daniel Kan <extremeblue99@gmail.com>
Stan Hu <stanhu@aclimalabs.com>
David Hotham <david.hotham@blueyonder.co.uk>
Steffen Siering <steffen siering gmail com>
Jens Steinhauser <jens.steinhauser@gmail.com>
Pavel Ilin <ilin.pa@gmail.com>
Kent Ryhorchuk <kryhorchuk@xeralux.com>
Martin Donath <scifish@gmail.com>
Oliver Lee <oliverzlee@gmail.com>
Michael Haberler <git@mah.priv.at>
Nicolas Colomer <ncolomer@viadeoteam.com>
Ivan Kravets <me@ikravets.com>
Kyle Manna <kyle@kylemanna.com>
Benjamin Kamath <ben.kamath@synapse.com>
Andrew Ruder <andrew.ruder@elecsyscorp.com>
Kenshi Kawaguchi <kenshi@recurse.ca>
isotes <isotes@gmail.com>
Maxim Khitrov <max@mxcrypt.com>
Yaniv Mordekhay <yanivmo@users.noreply.github.com>
Ming Zhao <mzhao@luminatewireless.com>
Google, Inc.
Tom Roeder <tmroeder@google.com>
Piotr Sikora <piotrsikora@google.com>
Bernhard Krämer <bdkrae@gmail.com>
Konstantin Podsvirov <konstantin@podsvirov.pro>
William A. Kennington III <wak@google.com>
Guillaume Lager <g.lager@innoseis.com>
Tobias Haegermarck <tobias.haegermarck@gmail.com>
Justin DeMartino <jdemarti@gmail.com>
Constantine Grantcharov <cgrantcharov@trustpointinnovation.com>
Nick Ewalt <nicholasewalt@google.com>
Harald Fernengel <harryf@gmx.com>
Alice Wang <aw@squareup.com>
Kevin Fitch <kfitch42@gmail.com>
Kamal Marhubi <kamal@marhubi.com>
Elco Jacobs <elco@brewpi.com>
Sébastien Morin <sebastien.morin@primerogames.com>
Dave Flogeras <dflogeras2@gmail.com>
Edward Z. Yang <ezyang@mit.edu>
Robbie Shade <rjshade@google.com>
Andrew Ballinger <andrewballinger@stratisopt.com>
Hamina, Juha-Pekka <Juha-Pekka.Hamina@nordicsemi.no>
Jason Bishop <jason.bishop@bigassfans.com>
matejcik <ja@matejcik.cz>
Tobias Müller <Tobias_Mueller@twam.info>
Jari Vetoniemi <mailroxas@gmail.com>
Gabriel Staples <ercaguy@gmail.com>
Amarnath <amarnath.h.96@gmail.com>
Michal Rostecki <mrostecki@suse.de>
Pei Wang <wangpei10@baidu.com>
Noah Pendleton <2538614+noahp@users.noreply.github.com>
Pavol Rusnak <pavol@rusnak.io>
der-imp <falkjan@msn.com>
Mark Hill <markleehill@gmail.com>
Torfinn Berset <torfinn@bloom-life.com>
Bo Langgaard Lind <bo.langgaard.lind@gmail.com>
Stephane Dorre <stephane.dorre@cobi.bike>
Phillip Cao <Phillip.Cao@fphcare.co.nz>
Melvin Wang <melvin.mc.wang@gmail.com>
Joshua Salzedo <thHunkn0WNd@gmail.com>
Adam Klama <klama.adam@gmail.com>
Anton Matosov <amatosov@roblox.com>
berni155 <bdkrae@gmail.com>
bolind <bolind@users.noreply.github.com>
David Lin <dtwlin@google.com>
dch <david.hotham@blueyonder.co.uk>
devjoa <devjoa@gmail.com>
Evan Fisher <schleb@gmail.com>
Fay <fay2003hiend@gmail.com>
Florian Märkl <info@florianmaerkl.de>
Franck <franck.sehedic@ledger.fr>
Ilya Averyanov <i.averyanov@geoscan.aero>
John Ullman <jrullman@google.com>
Ket3r <peter.kempter@gmail.com>
maciej <maciej.matuszak@gmail.com>
Marek Zukal <marek.zukal@gmail.com>
Paul Beusterien <paulbeusterien@google.com>
Rogers Guedes <rogers.guedes@smdautomacao.com>
Stefan R. Filipek <srfilipek@gmail.com>
T. Carl Beery <beeryt@users.noreply.github.com>
Vitali Lovich <vlovich@google.com>
Vojtěch Boček <vbocek@gmail.com>
Wael Nasreddine <wael.nasreddine@gmail.com>
wangli28 <wangli28@beyondsoft.com>
Zukaitis <gediminas.zukaitis@office.auriga.msk>
Alex Pacini <alexpacini90@gmail.com>
Cong <congusbongus@gmail.com>
kurddt <kurddt@users.noreply.github.com>
otopetrik <oto.petrik@gmail.com>
Psy-Kai <psykai1993@googlemail.com>
a1lu <a1lu@users.noreply.github.com>
L <46594312+WakandaO2@users.noreply.github.com>
Melvin Wang <mwang@sibros.tech>
Tim Gates <tim.gates@iress.com>
leabut <leabut@users.noreply.github.com>
Angel ILIEV <a.v.iliev13@gmail.com>
Jakub Tymejczyk <jakub@tymejczyk.pl>
Matthew Simmons <simmonmt@acm.org>
Anthony Pesch <inolen@gmail.com>
Avik De <avikde@gmail.com>
ConradWood <github@conradwood.net>
David Sabatie <david.sabatie@notrenet.com>
Sebastian Stockhammer <sebastian.stockhammer@rosenberger.de>
Gil Shapira <gil.shapira@intusurg.com>
Ian Frosst <ianjfrosst@gmail.com>
Ingo Kresse <ingo.kresse@kuka.com>
Ivan Zrno <ivan.zrno2@gmail.com>
Jonathan Seilkopf <j.seilkopf@isatech.de>
Karl Ljungkvist <k.ljungkvist@gmail.com>
Mathis Logemann <mathisloge@gmail.com>
Oleg Dolgy <60554929+odolgy@users.noreply.github.com>
Pavel Sokolov <pavel@sokolov.me>
Slavey Karadzhov <slav@attachix.com>
Tobias Nießen <tniessen@tnie.de>

21
third_party/nanopb/BUILD.bazel vendored Normal file
View file

@ -0,0 +1,21 @@
licenses(["notice"])
exports_files(["LICENSE.txt"])
package(default_visibility = ["//visibility:public"])
cc_library(
name = "nanopb",
srcs = [
"pb_common.c",
"pb_decode.c",
"pb_encode.c",
],
hdrs = [
"pb.h",
"pb_common.h",
"pb_decode.h",
"pb_encode.h",
],
visibility = ["//visibility:public"],
)

563
third_party/nanopb/CHANGELOG.txt vendored Normal file
View file

@ -0,0 +1,563 @@
nanopb-0.4.6 (2022-05-30)
Fix passing of error message from substream callback (#703)
Fix comments going to wrong member variables (#701)
Fix regression in 0.4.3 where generator did not find all dependencies (#720)
Fix FindNanopb.cmake not finding options file (#659)
Fix double-definition errors with size_union (#692)
Fix generator error with same inner message name (#746)
Fix infinite recursion in generator/protoc script (#762)
Fix unicode comment handling for Python 2 (#740)
Fix compiler warnings with PB_BUFFER_ONLY (#717)
Fix options dependency in nanopb.mk (#666)
Fix handling of filenames with dot in them in FindNanopb.cmake (#756)
Add fallback_type option (#772, #773)
Use C11 static assert mechanism by default (#761, #766)
Use 'static_assert' keyword for iar (#679)
Explicitly check for pItem == NULL to satisfy Xcode analyzer (#667, #674)
Support --proto-path as alias to -I (#749)
Refactor name mangling to separate class, improve error messages (#735)
Move PB_WT_PACKED definition to the header to fix compiler warnings (#671)
FindNanopb.cmake: use --nanopb_opt for option passing by default (#752)
FindNanopb.cmake: Add option NANOPB_GENERATE_CPP_STANDALONE (#741)
FindNanopb.cmake: Add PROTOC_OPTIONS variable (#768, #771)
CMakeLists: add build interface for using as a submodule (#669)
CMakeLists: fix error with nanopb_BUILD_GENERATOR=OFF (#764)
CMakeLists: make more uniform (#676)
CMakeLists: Fix uninitialized PYTHON_INSTDIR (#652)
Clean up CMake examples (#741)
Rebuild nanopb_pb2.py and print version numbers on import failure (#733, #742)
Use memcpy instead of iterating on buf_read/write (#751)
Add generator support for PlatformIO (#718)
Add clean target to generator/proto/Makefile (#681)
Windows .bats: use standard python invocation instead of py.exe launcher (#657)
Fix problems running tests with newer SCons version
Improve handling of varint overflows
Improve optimization for little-endian platforms
NOTE: During development, prereleases were published on platform.io registry
as versions 0.4.6 - 0.4.6.3. The version 0.4.6.4 on platform.io corresponds
to the real final 0.4.6 release.
nanopb-0.4.5 (2021-03-22)
Fix invalid free() with oneof (#647, GHSA-7mv5-5mxh-qg88)
Fix unordered field numbers inside oneof causing fields to be ignored (#617)
Fix pb_decode() not initializing fields inside oneof (#635
Fix compiler errors with complex oneof hierarchy and sizeof() (#610)
Fix descriptor width calculation for 64-bit types (#644)
Fix compiler error in generated initializer for submessage callback (#631)
Fix duplicate union definition in generated file (#637)
Fix test case build error on SCons 4.1.0
Pip package: include nanopb_pb2.py (#629)
Make generator consider dependencies recursively (#610)
Bazel build system updates (#633)
Add support for including comments from .proto file (#85, #645)
nanopb-0.4.4 (2020-11-25)
Fix memory leak with oneofs and PB_ENABLE_MALLOC (#615, GHSA-85rr-4rh9-hhwh)
Fix generator error when oneof contains a single unresolved field size (#610)
Fix unsigned enums not working correctly inside OneOf (#611)
Fix recursion depth exceeded error in generator (#493)
Add '--version' option to nanopb_generator.py (#607)
Add support for proto3 optional fields introduced in protoc 3.12 (#591)
Add better error message when enum type is not found (#592)
Allow specifying descriptorsize on field level also (#546)
Allow multiple targets to be created by calling NANOPB_GENERATE_CPP() (#596)
Conanfile: Add protobuf-nanopb library to cpp_info.libs (#605)
Include version number in generator verbose output
Convert documentation to markdown format (#587)
Remove outdated transitional generator/nanopb/options.proto.
Test case improvements
Documentation improvements
nanopb-0.4.3 (2020-09-21)
Fix generator error when output is in current directory (#553)
Fix issue with unknown message sizes being referred inside oneof encoded size calculation (#569)
Fix problem with [default=xxxx, (nanopb).proto3=true] field option combination (#558)
Fix cross compilation with Conan build system (#568)
Better support C++ types in generated structs (#577)
CMake rule improvements (#554, #555, #556, #561, #564)
Generator: fix compatibility bug with Python 3.1 and earlier
Make Linux and Mac packages use grpcio protoc
Make pb_decode_varint32() reject overlong varint encodings.
Performance optimizations
Test case improvements
Documentation improvements
NOTE: version 0.4.3 changes layout of pb_msgdesc_t. It requires recompiling .pb.c files and
thus breaks ABI compatibility. In general, ABI compatibility is not currently maintained
between any nanopb versions.
NOTE: There was an apparent false positive virus identification by Windows Defender of the
PyInstaller 3.6 based Windows package nanopb-0.4.3-windows-x86.zip. The package was replaced
by nanopb-0.4.3-p1-windows-x86.zip with rebuilt PyInstaller 4.0, which seems to avoid the problem.
Actual nanopb code is unchanged between the packages.
nanopb-0.4.2 (2020-06-23)
Fix buffer overflow when encoding bytes with size set to 65535 (#547, GHSA-3p39-mfxg-hrq4)
Fix segfault with pointer fields and proto3_singular_msgs = true. (#504,#505)
Fix Windows 10 temp file handling (#486)
Fix macro name conflicts (ATMEGA32U4 UENUM and more) (#522)
Fix generator error with nested messages and default values (#487)
Fix nanopb_generator exception on enums with aliases (#535)
Fix compile error when struct members are called X or a (#492)
Fix sizeof(union ...) fallback not compiling with C++ (#415, #494)
Fix "missing required field" error with submessage callback (#544)
Fix field descriptor sizing with submsg_callback option (#545)
Fix protoc calling on Python 2 (#503)
Fix handling of varying NaN representations in PB_CONVERT_DOUBLE_FLOAT (#543)
Fix clang undefined behavior sanitizer errors.
Change generator to use Python 3 by default (#441, #509)
Binary packages updated to use Python 3 and grpcio-tools
Add support for infinity and nan floating-point defaults (#530, #538)
Add generator option sort_by_tag (#542)
Add type_override option to override type defined in .proto (#497)
Set proto2 enum fields to first value when no default is given, even if nonzero (#532,#539)
Include protoc-gen-nanopb in path in protoc wrapper script
Properly pass error status from protoc wrapper when calling binary protoc
Generator: pass --include_imports when calling protoc (#494)
Create intermediate directories when writing files to relative path (#512)
Add current directory to include path for protoc (#499)
Update readme to use nanopb_generator.py directly
Regression test for proto3 incorrectly considered empty (#504)
CMake: change package name to Nanopb for cmake 3.17 compatibility (#506)
CMake: remove find_package(PythonInterp) (#508)
CMake: use split --nanopb_opt only on protoc >= 3.6 (#515)
CMake: Relax python version spec, allowing Python3. (#534)
Swift package manager (#549)
Rename BUILD as BUILD.bazel (#537)
Note: Windows binary packages in 0.4.2 and later require Windows 7 or newer.
nanopb-0.4.1 (2020-02-02)
Fix invalid free() after failed realloc() (GHSA-gcx3-7m76-287p)
Avoid overflows in allocation for packed fields.
Verify stream size before allocating string / bytes.
Add workaround for avr-libc realloc() bug (#475)
Fix bug with field numbers >255 (#407)
Fix compilation error on platforms without uint8_t (#485)
Fix warnings on Python3.8 (#399, #467)
Make fixed_count option work when combined with FT_POINTER.
Add missing #define for submsg callbacks, add regression test (#472)
Fix ImportError when using generator/protoc with Python 3
Remove accidental debug code in generator
Reduce stack usage (#484)
Remove PB_FIELDINFO_WIDTH option (#473)
Add nanopb-specific package name option (#422)
Add testcase for Any type (#163)
Add exclude option also from .proto/.options
Set default include path in the grpc_tools protoc wrapper.
Add workaround for python-protobuf 3.6.1 bug (#478)
Detect invalid wire type when decoding fields.
Improved fuzz testing
nanopb-0.4.0 (2019-12-20)
New field descriptor format.
Make nanopb_generator automatically compile .proto files (#462)
Allow installing as Python package from pip (#460)
Use protoc from grpcio-tools Python package if available (#463)
Change proto3 message types to be optional (#308, #452)
Add pb_decode_ex(), pb_encode_ex() functions.
Automatically rebuild nanopb_pb2.py
Use plugin.proto that comes with python-protobuf (#234)
Allow specifying a per-message callback. (#175)
Improve callback handling inside oneofs. (#175)
Introduce new compile time flag: PB_VALIDATE_UTF8 (#437)
Add TypenameMangling.M_PACKAGE_INITIALS (#394)
Introduce new compile time flag: PB_ENCODE_ARRAYS_UNPACKED (#427)
Add default_has option (#423)
Add option for including extra files from .pb.h
Add generator option to error out on unmatched options (#458)
Generator: Allow comma separated options in plugin mode (#343)
Allow comma-separated option parsing to handle `#include` (#450)
Remove timestamp from generated files by default, add -t to keep it.
Make --no-strip-path default (#326)
Fix .options file case sensitivity on Windows.
Fix generator error with mangle_names option (#380)
Take int_size setting into account in calculating message sizes (#373)
.gitignore: don't ignore generator-bin files (#419)
Cleanup .pb.h header format
Make tests run on AVR and STM32
Add PB_CONVERT_DOUBLE_FLOAT setting to convert doubles on AVR.
Store field descriptor constants in flash on AVR (#464)
Added "f" suffix to const float declarations. (#453)
Fix clang-tidy warnings about using signed integers in binary bitwise operations (#451)
Add C++ message descriptors helper (#384)
Implement conan recipe (#378)
CMake: Split nanopb_out command (#454)
CMake: install created shared library(dll) in windows to the binary folder (#447)
nanopb-0.3.9.8 (2021-03-22)
Fix invalid free() with oneof (#647, GHSA-7mv5-5mxh-qg88)
Don't generate lines with trailing spaces (#622)
Verify stream size before allocating string / bytes (#620)
nanopb-0.3.9.7 (2020-11-25)
Fix memory leak with oneofs and PB_ENABLE_MALLOC (#615, GHSA-85rr-4rh9-hhwh)
Fix unsigned enums not working correctly inside OneOf (#611)
Add '--version' option to nanopb_generator.py (#607)
SwiftPM rule updates (#567, #585)
nanopb-0.3.9.6 (2020-06-23)
Fix buffer overflow when encoding bytes with size set to 65535 (#547, GHSA-3p39-mfxg-hrq4)
Fix proto3 submessage improperly considered empty (#504)
Fix ImportError when using generator/protoc with Python 3
Add build rules for Swift package manager (#549)
nanopb-0.3.9.5 (2020-02-02)
Fix invalid free() after failed realloc() (GHSA-gcx3-7m76-287p)
Add workaround for avr-libc realloc() bug (#475)
Fix empty submessages getting encoded in proto3 mode (#395)
Avoid overflows in allocation for packed fields.
nanopb-0.3.9.4 (2019-10-13)
Fix undefined behavior with bool fields (#434)
Fix enum min/max defines when values are not in order (#405)
Fix network_server socket example with zero-length strings (#421)
Don't call stream read callback with count=0 (#421)
Add compile time flag PB_ENCODE_ARRAYS_UNPACKED (#427)
nanopb-0.3.9.3 (2019-03-08)
NOTE: nanopb-0.3.9.3.tar.gz before 2019-03-21 was accidentally from 0.4 branch (#388)
Fix fixed size and callback repeated fields inside proto3 submessages (#376, #382, #386)
Fix incorrect PB_STATIC_ASSERT for bytes inside oneof (#363)
Fix generator error with mangle_names option (#380)
Generator: Allow comma separated options in plugin mode (#343)
nanopb-0.3.9.2 (2018-11-10)
Erroneous free() when using callbacks combined with PB_ENABLE_MALLOC (#346)
Fix possible null-pointer dereference in decode_callback_field (#342)
Fix FindNanopb.cmake on Windows (#335)
Fix large generator memory usage with oneof fields (#338)
Fix error in splint test (#359)
Allow cmake to build as a shared library (#352, #353)
Add --no-strip-path command line option (#326)
Option for flattening nested protobuf names (#333)
Documentation fixes (#329, #350, #358)
Better error messages (#351)
nanopb-0.3.9.1 (2018-04-14)
Fix handling of special characters in string/bytes default values (issue #322)
Fix encoding of negative numbers with PB_WITHOUT_64BIT (#285)
Fix _zero initializer for enums that don't begin at 0. (#295)
Multiple CMake fixes (#296, #299, #304, #312, #320)
Fix compiler warnings (#305)
Fix scons rules for Python 3
Add check for large extension field number (issue #306)
Updated included descriptor.proto version (#314)
Resolve oneof sizes symbolically when needed (#311)
Add fixed_count option (#260)
Add some verbose prints in generator (issue #238)
Add test/example of using 'map' type. (#289)
nanopb-0.3.9 (2017-09-23)
Fix bugs in proto3 encoding of submessages (#256)
Fix message size calculation for arrays of size 1 (#253)
Fix segfault with FT_CALLBACK inside FT_POINTER (#259)
Properly detect truncated tags in corrupted messages (#277)
Make pb_decode_varint32 overflow checks exact (#258)
Add option to build without 64-bit support (#86)
Add options to define source and header file extensions (#264)
Add pb_en/decode_nullterminated() (part of #278)
Add pb_decode_delimited_noinit (#284)
CMake: add dependency for .options file (#265)
CMake: change use of relative paths (#250,#271,#273)
Better error message for missing max_size option (#281)
Travis-CI build fixes (#283)
Add Bazel build system file (#266)
nanopb-0.3.8 (2017-03-05)
Fix problems with multiple oneofs in same message (#229)
Zero-valued extension fields were mistakenly ignored by encoder (#242)
Multiple fixes related to proto3 mode (#242, #245, #247, #249)
Fix potential unaligned access (#226, #227)
Fix documentation for protoc --plugin argument (#239)
Extend inline / fixed length bytes array support (#244)
Add new option max_length for strings (#107)
Make string substream API more robust (#230)
Make pb_decode_varint32 public API (#231)
Allow overriding proto3 mode (#228)
Add optional enum->string mapping function (#223)
Add transitional options.proto file (#241)
Add better error message on Python library version incompatibility (#240)
Include version number in PlatformIO library.json (#222)
CMake build script changes (#236, #237)
Change download links to https
Improvements to test cases.
nanopb-0.3.7 (2016-10-30)
Add support for proto3-style singular fields (#182, #206, #216)
Updated binary package protoc to version 3.1.0
Add FT_INLINE allocation of bytes fields (#211)
Include package name in include guard (#207)
Fix missing warning with large bytes fields (issue #220)
Added CMake project (#208)
Add bazel BUILD file for nanopb (#209)
Added an AUTHORS file (#211)
Documentation updates
Improvements to test cases.
nanopb-0.3.6 (2016-06-19)
Protect against corrupted _count fields in pb_release (#205)
Fix error in STATIC_ASSERT with multiple files (#203)
Add -D option to specify output directory (#193)
Generate MIN/MAX/ARRAYSIZE defines for enums (#194)
Generate comments about uncalculable message sizes (#195)
Documentation updates (#196, #201)
Improvements to test cases.
nanopb-0.3.5 (2016-02-13)
NOTE: If you are using pb_syshdr.h, you will need to add uint_least8_t
definition. See docs/migration.rst for details.
Fix generator crash with Enum inside Oneof (#188)
Fix some generator regressions related to .options file path (#172)
Add support for platforms without uint8_t (#191)
Allow const parameter to pb_istream_from_buffer (#152)
Ignore null pointers in pb_release() (#183)
Add support for anonymous unions (#184)
Add Python3 support to the generator (#169)
Add code generator insertion points to generated files (#178)
Improvements to CMake script (#181)
Improvements to test cases.
nanopb-0.3.4 (2015-09-26)
Fix handling of unsigned 8- and 16-bit enums (issue 164)
Fix generator on systems where python = python3. (issue 155)
Fix compiler warning on GCC 5.x (issue 171)
Make the generator better handle imported .protos (issue 165)
Add packed_enum option to generator.
Add syntax= line to .proto files (issue 167)
Add PlatformIO registry manifest file. (pr 156)
nanopb-0.3.3 (2015-04-10)
Fix missing files in Linux binary package (issue 146)
Fix generator bug when oneof is first field in a message. (issue 142)
Fix generator error when long_names:false is combined with Oneofs. (issue 147)
Fix oneof submessage initialization bug. (issue 149)
Fix problem with plugin options on Python 2.7.2 and older. (issue 153)
Fix crash when callback is inside oneof field. (issue 148)
Switch to .tar.gz format for Mac OS X packages. (issue 154)
Always define enum long names so that cross-file references work. (issue 118)
Add msgid generator option. (issue 151)
Improve comment support in .options files. (issue 145)
Updates for the CMake rule file, add cmake example.
Better error messages for syntax errors in .options file
nanopb-0.3.2 (2015-01-24)
Fix memory leaks with PB_ENABLE_MALLOC with some submessage hierarchies (issue 138)
Implement support for oneofs (C unions). (issues 131, 141)
Add int_size option for generator (issue 139)
Add compilation option to disable struct packing. (issue 136)
Change PB_RETURN_ERROR() macro to avoid compiler warnings (issue 140)
Fix build problems with protoc 3.0.0
Add support for POINTER type in extensions
Initialize also extension fields to defaults in pb_decode().
Detect too large varint values when decoding.
nanopb-0.3.1 (2014-09-11)
Fix security issue due to size_t overflows. (issue 132)
Fix memory leak with duplicated fields and PB_ENABLE_MALLOC
Fix crash if pb_release() is called twice.
Fix cyclic message support (issue 130)
Fix error in generated initializers for repeated pointer fields.
Improve tests (issues 113, 126)
nanopb-0.3.0 (2014-08-26)
NOTE: See docs/migration.html or online at
http://koti.kapsi.fi/~jpa/nanopb/docs/migration.html
for changes in this version. Most importantly, you need to add
pb_common.c to the list of files to compile.
Separated field iterator logic to pb_common.c (issue 128)
Change the _count fields to use pb_size_t datatype (issue 82)
Added PB_ prefix to macro names (issue 106)
Added #if version guard to generated files (issue 129)
Added migration document
nanopb-0.2.9.5 (2020-06-23)
Fix buffer overflow when encoding bytes with size set to 65535 (#547, GHSA-3p39-mfxg-hrq4)
Backport Python 3 and protoc 3.x fixes to test cases
nanopb-0.2.9.4 (2020-02-02)
Fix invalid free() after failed realloc() (GHSA-gcx3-7m76-287p)
Add workaround for avr-libc realloc() bug (#475)
nanopb-0.2.9.3 (2016-06-19)
Protect against corrupted _count fields in pb_release (#205)
nanopb-0.2.9.2 (2015-01-24)
Fix memory leaks with PB_ENABLE_MALLOC with some submessage hierarchies (issue 138)
Fix compilation error with generated initializers for repeated pointer fields
nanopb-0.2.9.1 (2014-09-11)
Fix security issue due to size_t overflows. (issue 132)
Fix memory leak with duplicated fields and PB_ENABLE_MALLOC
Fix crash if pb_release() is called twice.
nanopb-0.2.9 (2014-08-09)
NOTE: If you are using the -e option with the generator, you have
to prepend . to the argument to get the same behaviour as before.
Do not automatically add a dot with generator -e option. (issue 122)
Fix problem with .options file and extension fields. (issue 125)
Don't use SIZE_MAX macro, as it is not in C89. (issue 120)
Generate #defines for initializing message structures. (issue 79)
Add skip_message option to generator. (issue 121)
Add PB_PACKED_STRUCT support for Keil MDK-ARM toolchain (issue 119)
Give better messages about the .options file path. (issue 124)
Improved tests
nanopb-0.2.8 (2014-05-20)
Fix security issue with PB_ENABLE_MALLOC. (issue 117)
Add option to not add timestamps to .pb.h and .pb.c preambles. (issue 115)
Documentation updates
Improved tests
nanopb-0.2.7 (2014-04-07)
Fix bug with default values for extension fields (issue 111)
Fix some MISRA-C warnings (issue 91)
Implemented optional malloc() support (issue 80)
Changed pointer-type bytes field datatype
Add a "found" field to pb_extension_t (issue 112)
Add convenience function pb_get_encoded_size() (issue 16)
nanopb-0.2.6 (2014-02-15)
Fix generator error with bytes callback fields (issue 99)
Fix warnings about large integer constants (issue 102)
Add comments to where STATIC_ASSERT is used (issue 96)
Add warning about unknown field names on .options (issue 105)
Move descriptor.proto to google/protobuf subdirectory (issue 104)
Improved tests
nanopb-0.2.5 (2014-01-01)
Fix a bug with encoding negative values in int32 fields (issue 97)
Create binary packages of the generator + dependencies (issue 47)
Add support for pointer-type fields to the encoder (part of issue 80)
Fixed path in FindNanopb.cmake (issue 94)
Improved tests
nanopb-0.2.4 (2013-11-07)
Remove the deprecated NANOPB_INTERNALS functions from public API.
Document the security model.
Check array and bytes max sizes when encoding (issue 90)
Add #defines for maximum encoded message size (issue 89)
Add #define tags for extension fields (issue 93)
Fix MISRA C violations (issue 91)
Clean up pb_field_t definition with typedefs.
nanopb-0.2.3 (2013-09-18)
Improve compatibility by removing ternary operator from initializations (issue 88)
Fix build error on Visual C++ (issue 84, patch by Markus Schwarzenberg)
Don't stop on unsupported extension fields (issue 83)
Add an example pb_syshdr.h file for non-C99 compilers
Reorganize tests and examples into subfolders (issue 63)
Switch from Makefiles to scons for building the tests
Make the tests buildable on Windows
nanopb-0.2.2 (2013-08-18)
Add support for extension fields (issue 17)
Fix unknown fields in empty message (issue 78)
Include the field tags in the generated .pb.h file.
Add pb_decode_delimited and pb_encode_delimited wrapper functions (issue 74)
Add a section in top of pb.h for changing compilation settings (issue 76)
Documentation improvements (issues 12, 77 and others)
Improved tests
nanopb-0.2.1 (2013-04-14)
NOTE: The default callback function signature has changed.
If you don't want to update your code, define PB_OLD_CALLBACK_STYLE.
Change the callback function to use void** (issue 69)
Add support for defining the nanopb options in a separate file (issue 12)
Add support for packed structs in IAR and MSVC (in addition to GCC) (issue 66)
Implement error message support for the encoder side (issue 7)
Handle unterminated strings when encoding (issue 68)
Fix bug with empty strings in repeated string callbacks (issue 73)
Fix regression in 0.2.0 with optional callback fields (issue 70)
Fix bugs with empty message types (issues 64, 65)
Fix some compiler warnings on clang (issue 67)
Some portability improvements (issues 60, 62)
Various new generator options
Improved tests
nanopb-0.2.0 (2013-03-02)
NOTE: This release requires you to regenerate all .pb.c
files. Files generated by older versions will not
compile anymore.
Reformat generated .pb.c files using macros (issue 58)
Rename PB_HTYPE_ARRAY -> PB_HTYPE_REPEATED
Separate PB_HTYPE to PB_ATYPE and PB_HTYPE
Move STATIC_ASSERTs to .pb.c file
Added CMake file (by Pavel Ilin)
Add option to give file extension to generator (by Michael Haberler)
Documentation updates
nanopb-0.1.9 (2013-02-13)
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 (2012-12-13)
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 missing initialization of istream.errmsg
Make tests/Makefile work for non-gcc compilers (issue 40)
nanopb-0.1.7 (2012-11-11)
Remove "skip" mode from pb_istream_t callbacks. Example implementation had a bug. (issue 37)
Add option to use shorter names for enum values (issue 38)
Improve options support in generator (issues 12, 30)
Add nanopb version number to generated files (issue 36)
Add extern "C" to generated headers (issue 35)
Add names for structs to allow forward declaration (issue 39)
Add buffer size check in example (issue 34)
Fix build warnings on MS compilers (issue 33)
nanopb-0.1.6 (2012-09-02)
Reorganize the field decoder interface (issue 2)
Improve performance in submessage decoding (issue 28)
Implement error messages in the decoder side (issue 7)
Extended testcases (alltypes test is now complete).
Fix some compiler warnings (issues 25, 26, 27, 32).
nanopb-0.1.5 (2012-08-04)
Fix bug in decoder with packed arrays (issue 23).
Extended testcases.
Fix some compiler warnings.
nanopb-0.1.4 (2012-07-05)
Add compile-time options for easy-to-use >255 field support.
Improve the detection of missing required fields.
Added example on how to handle union messages.
Fix generator error with .proto without messages.
Fix problems that stopped the code from compiling with some compilers.
Fix some compiler warnings.
nanopb-0.1.3 (2012-06-12)
Refactor the field encoder interface.
Improve generator error messages (issue 5)
Add descriptor.proto into the #include exclusion list
Fix some compiler warnings.
nanopb-0.1.2 (2012-02-15)
Make the generator to generate include for other .proto files (issue 4).
Fixed generator not working on Windows (issue 3)
nanopb-0.1.1 (2012-01-14)
Fixed bug in encoder with 'bytes' fields (issue 1).
Fixed a bug in the generator that caused a compiler error on sfixed32 and sfixed64 fields.
Extended testcases.
nanopb-0.1.0 (2012-01-06)
First stable release.

32
third_party/nanopb/CONTRIBUTING.md vendored Normal file
View file

@ -0,0 +1,32 @@
Contributing to Nanopb development
==================================
Reporting issues and requesting features
----------------------------------------
Feel free to report any issues you see or features you would like
to see in the future to the Github issue tracker. Using the templates
below is preferred:
* [Report a bug](https://github.com/nanopb/nanopb/issues/new?body=**Steps%20to%20reproduce%20the%20issue**%0a%0a1.%0a2.%0a3.%0a%0a**What%20happens?**%0A%0A**What%20should%20happen?**&labels=Type-Defect)
* [Request a feature](https://github.com/nanopb/nanopb/issues/new?body=**What%20should%20the%20feature%20do?**%0A%0A**In%20what%20situation%20would%20the%20feature%20be%20useful?**&labels=Type-Enhancement)
Requesting help
---------------
If there is something strange going on, but you do not know if
it is actually a bug in nanopb, try asking first on the
[discussion forum](https://groups.google.com/forum/#!forum/nanopb).
Pull requests
-------------
Pull requests are welcome!
If it is not obvious from the commit message, please indicate the
same information as you would for an issue report:
* What functionality it fixes/adds.
* How can the problem be reproduced / when would the feature be useful.

79
third_party/nanopb/LICENSE.txt vendored Normal file
View file

@ -0,0 +1,79 @@
Copyright (c) 2011 Petteri Aimonen <jpa at nanopb.mail.kapsi.fi>
This software is provided 'as-is', without any express or
implied warranty. In no event will the authors be held liable
for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
The function generator/nanopb_generator.py:toposort2 is licensed under the MIT
License:
MIT License
Copyright (c) 2010 Paddy McCarthy
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The function pb_common.c:pb_validate_utf8 is licensed under the following terms:
Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> -- 2005-03-30
License: http://www.cl.cam.ac.uk/~mgk25/short-license.html
Short code license
If you have reached this web page because you found its URL included as a license-reference comment in a short piece of published computer software source code by its author(s), next to their name, as in, for example,
Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> -- 1999-12-31
License: https://www.cl.cam.ac.uk/~mgk25/short-license.html
then you can assume the following:
This code was published by its author(s) as an easily reusable piece of free software, for example to demonstrate some particular programming practice. It is likely too short or obvious to skilled programmers to fall under, or deserve, the protection of copyright legislation. It is also likely to be useless on its own, unless verified and integrated into a larger program by an experienced software engineer, and therefore no consumer protection, warranty or liability rights apply either. Therefore, its author(s) refused to disfigure its appearance with a lengthy copyright license text.
Nevertheless, overly cautious lawyers (possibly as part of a “due diligence exercise”) occasionally contact authors of such short code snippets for a formal copyright license.
Therefore, the author(s) agree(s) to clarify that, at the users choice, the code can be used under any of the following licenses, or any compatible with them:
Apache License, 2.0
BSD license
GNU General Public License (GPL)
GNU Library or "Lesser" General Public License (LGPL)
MIT license
Mozilla Public License 1.1 (MPL)
Common Development and Distribution License
Eclipse Public License
CC0
Markus Kuhn

63
third_party/nanopb/Package.swift vendored Normal file
View file

@ -0,0 +1,63 @@
// swift-tools-version:5.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "nanopb",
products: [
.library(
name: "nanopb",
targets: ["nanopb"]
)
],
targets: [
.target(
name: "nanopb",
path: ".",
sources: [
"pb.h",
"pb_common.h",
"pb_common.c",
"pb_decode.h",
"pb_decode.c",
"pb_encode.h",
"pb_encode.c"
],
publicHeadersPath: "spm_headers",
cSettings: [
.define("PB_FIELD_32BIT", to: "1"),
.define("PB_NO_PACKED_STRUCTS", to: "1"),
.define("PB_ENABLE_MALLOC", to: "1"),
]
),
.testTarget(
name: "swift-test",
dependencies: [
"nanopb",
],
path: "spm-test/swift",
cSettings: [
.headerSearchPath("../"),
.define("PB_FIELD_32BIT", to: "1"),
.define("PB_NO_PACKED_STRUCTS", to: "1"),
.define("PB_ENABLE_MALLOC", to: "1"),
]
),
.testTarget(
name: "objc-test",
dependencies: [
"nanopb",
],
path: "spm-test/objc",
cSettings: [
.headerSearchPath("../"),
.define("PB_FIELD_32BIT", to: "1"),
.define("PB_NO_PACKED_STRUCTS", to: "1"),
.define("PB_ENABLE_MALLOC", to: "1"),
]
)
]
)

99
third_party/nanopb/README.md vendored Normal file
View file

@ -0,0 +1,99 @@
Nanopb - Protocol Buffers for Embedded Systems
==============================================
![Latest change](https://github.com/nanopb/nanopb/actions/workflows/trigger_on_code_change.yml/badge.svg)
![Weekly build](https://github.com/nanopb/nanopb/actions/workflows/trigger_on_schedule.yml/badge.svg)
Nanopb is a small code-size Protocol Buffers implementation in ansi C. It is
especially suitable for use in microcontrollers, but fits any memory
restricted system.
* **Homepage:** https://jpa.kapsi.fi/nanopb/
* **Git repository:** https://github.com/nanopb/nanopb/
* **Documentation:** https://jpa.kapsi.fi/nanopb/docs/
* **Forum:** https://groups.google.com/forum/#!forum/nanopb
* **Stable version downloads:** https://jpa.kapsi.fi/nanopb/download/
* **Pre-release binary packages:** https://github.com/nanopb/nanopb/actions/workflows/binary_packages.yml
Using the nanopb library
------------------------
To use the nanopb library, you need to do two things:
1. Compile your .proto files for nanopb, using `protoc`.
2. Include *pb_encode.c*, *pb_decode.c* and *pb_common.c* in your project.
The easiest way to get started is to study the project in "examples/simple".
It contains a Makefile, which should work directly under most Linux systems.
However, for any other kind of build system, see the manual steps in
README.txt in that folder.
Generating the headers
----------------------
Protocol Buffers messages are defined in a `.proto` file, which follows a standard
format that is compatible with all Protocol Buffers libraries. To use it with nanopb,
you need to generate `.pb.c` and `.pb.h` files from it:
python generator/nanopb_generator.py myprotocol.proto # For source checkout
generator-bin/nanopb_generator myprotocol.proto # For binary package
(Note: For instructions for nanopb-0.3.9.x and older, see the documentation
of that particular version [here](https://github.com/nanopb/nanopb/blob/maintenance_0.3/README.md))
The binary packages for Windows, Linux and Mac OS X should contain all necessary
dependencies, including Python, python-protobuf library and protoc. If you are
using a git checkout or a plain source distribution, you will need to install
Python separately. Once you have Python, you can install the other dependencies
with `pip install --upgrade protobuf grpcio-tools`.
You can further customize the header generation by creating an `.options` file.
See [documentation](https://jpa.kapsi.fi/nanopb/docs/concepts.html#modifying-generator-behaviour) for details.
Running the tests
-----------------
If you want to perform further development of the nanopb core, or to verify
its functionality using your compiler and platform, you'll want to run the
test suite. The build rules for the test suite are implemented using Scons,
so you need to have that installed (ex: `sudo apt install scons` or `pip install scons`).
To run the tests:
cd tests
scons
This will show the progress of various test cases. If the output does not
end in an error, the test cases were successful.
Note: Mac OS X by default aliases 'clang' as 'gcc', while not actually
supporting the same command line options as gcc does. To run tests on
Mac OS X, use: `scons CC=clang CXX=clang`. Same way can be used to run
tests with different compilers on any platform.
For embedded platforms, there is currently support for running the tests
on STM32 discovery board and [simavr](https://github.com/buserror/simavr)
AVR simulator. Use `scons PLATFORM=STM32` and `scons PLATFORM=AVR` to run
these tests.
Build systems and integration
-----------------------------
Nanopb C code itself is designed to be portable and easy to build
on any platform. Often the bigger hurdle is running the generator which
takes in the `.proto` files and outputs `.pb.c` definitions.
There exist build rules for several systems:
* **Makefiles**: `extra/nanopb.mk`, see `examples/simple`
* **CMake**: `extra/FindNanopb.cmake`, see `examples/cmake`
* **SCons**: `tests/site_scons` (generator only)
* **Bazel**: `BUILD` in source root
* **Conan**: `conanfile.py` in source root
* **PlatformIO**: https://platformio.org/lib/show/431/Nanopb
* **PyPI/pip**: https://pypi.org/project/nanopb/
* **vcpkg**: https://vcpkg.info/port/nanopb
And also integration to platform interfaces:
* **Arduino**: http://platformio.org/lib/show/1385/nanopb-arduino

1
third_party/nanopb/WORKSPACE vendored Normal file
View file

@ -0,0 +1 @@
workspace(name = "com_github_nanopb_nanopb")

6
third_party/nanopb/build.py vendored Normal file
View file

@ -0,0 +1,6 @@
from conan.packager import ConanMultiPackager
if __name__ == "__main__":
builder = ConanMultiPackager(build_policy="outdated")
builder.add_common_builds(shared_option_name=None)
builder.run()

33
third_party/nanopb/conanfile.py vendored Normal file
View file

@ -0,0 +1,33 @@
from conans import ConanFile, CMake, tools
from os import path
class NanoPbConan(ConanFile):
name = "nanopb"
version = "0.4.6"
license = "zlib"
url = "https://jpa.kapsi.fi/nanopb/"
description = "Protocol Buffers with small code size"
settings = "os_build", "compiler", "build_type", "arch"
generators = "cmake"
exports = '*'
options = {
"fPIC": [True, False],
}
default_options = {
"fPIC": True,
}
def configure(self):
if self.settings.os_build == "Windows" and self.settings.compiler == "Visual Studio":
del self.options.fPIC
def build(self):
cmake = CMake(self)
cmake.configure(source_folder=path.join(self.source_folder, "conan-wrapper"))
cmake.build()
cmake.install()
def package_info(self):
self.cpp_info.includedirs = ["include"]
self.cpp_info.libdirs = ["lib"]
self.cpp_info.libs = ["protobuf-nanopb"]

23
third_party/nanopb/docs/Makefile vendored Normal file
View file

@ -0,0 +1,23 @@
INPUTS = index.md concepts.md reference.md security.md migration.md whats_new.md
all: $(INPUTS:.md=.html)
tmp_menu.html: $(INPUTS)
echo '<div id="index">' > $@
(echo '<h2>Documentation index</h2>'; \
for file in $^; do echo -n '1. ['; sed -n '1 s!^# Nanopb: !! p' $$file; \
echo -n "]("; echo $$file | sed 's/.md/.html)/' ; done;) | \
pandoc -f markdown -t html5 >> $@
echo '</div>' >> $@
%.html: %.md tmp_menu.html
sed '1 s!#!%!' $< | \
pandoc -s -f markdown -t html5 -c lsr.css --toc --toc-depth=4 \
--variable 'header-includes=<link href="favicon.ico" type="image/x-icon" rel="shortcut icon" />' \
--indented-code-classes=c \
-o $@
sed -i '/<nav/e cat feedback.html' $@
sed -i 's/doc_page_name_placeholder/$</' $@
sed -i 's!<nav[^>]*>!\0<b>Contents:</b>!' $@
sed -i '/<nav/e cat tmp_menu.html' $@

621
third_party/nanopb/docs/concepts.md vendored Normal file
View file

@ -0,0 +1,621 @@
# Nanopb: Basic concepts
The things outlined here are the underlying concepts of the nanopb
design.
## Proto files
All Protocol Buffers implementations use .proto files to describe the
message format. The point of these files is to be a portable interface
description language.
### Compiling .proto files for nanopb
Nanopb comes with a Python script to generate `.pb.c` and
`.pb.h` files from the `.proto` definition:
user@host:~$ nanopb/generator/nanopb_generator.py message.proto
Writing to message.pb.h and message.pb.c
Internally this script uses Google `protoc` to parse the
input file. If you do not have it available, you may receive an error
message. You can install either `grpcio-tools` Python
package using `pip`, or the `protoc` compiler
itself from `protobuf-compiler` distribution package.
Generally the Python package is recommended, because nanopb requires
protoc version 3.6 or newer to support all features, and some distributions come with an older
version.
### Modifying generator behaviour
Using generator options, you can set maximum sizes for fields in order
to allocate them statically. The preferred way to do this is to create
an .options file with the same name as your .proto file:
# Foo.proto
message Foo {
required string name = 1;
}
# Foo.options
Foo.name max_size:16
For more information on this, see the [Proto file
options](reference.html#proto-file-options) section in the reference
manual.
## Streams
Nanopb uses streams for accessing the data in encoded format. The stream
abstraction is very lightweight, and consists of a structure
(`pb_ostream_t` or `pb_istream_t`) which contains a pointer to a
callback function.
There are a few generic rules for callback functions:
1) Return false on IO errors. The encoding or decoding process will
abort immediately.
2) Use state to store your own data, such as a file descriptor.
3) `bytes_written` and `bytes_left` are updated by pb_write and
pb_read.
4) Your callback may be used with substreams. In this case
`bytes_left`, `bytes_written` and `max_size` have smaller values
than the original stream. Don't use these values to calculate
pointers.
5) Always read or write the full requested length of data. For example,
POSIX `recv()` needs the `MSG_WAITALL` parameter to accomplish
this.
### Output streams
struct _pb_ostream_t
{
bool (*callback)(pb_ostream_t *stream, const uint8_t *buf, size_t count);
void *state;
size_t max_size;
size_t bytes_written;
};
The `callback` for output stream may be NULL, in which case the stream
simply counts the number of bytes written. In this case, `max_size` is
ignored.
Otherwise, if `bytes_written` + bytes_to_be_written is larger than
`max_size`, pb_write returns false before doing anything else. If you
don\'t want to limit the size of the stream, pass SIZE_MAX.
**Example 1:**
This is the way to get the size of the message without storing it
anywhere:
Person myperson = ...;
pb_ostream_t sizestream = {0};
pb_encode(&sizestream, Person_fields, &myperson);
printf("Encoded size is %d\n", sizestream.bytes_written);
**Example 2:**
Writing to stdout:
bool callback(pb_ostream_t `stream, const uint8_t `buf, size_t count)
{
FILE *file = (FILE*) stream->state;
return fwrite(buf, 1, count, file) == count;
}
pb_ostream_t stdoutstream = {&callback, stdout, SIZE_MAX, 0};
### Input streams
For input streams, there is one extra rule:
6) You don't need to know the length of the message in advance. After
getting EOF error when reading, set `bytes_left` to 0 and return
`false`. `pb_decode()` will detect this and if the EOF was in a proper
position, it will return true.
Here is the structure:
struct _pb_istream_t
{
bool (*callback)(pb_istream_t *stream, uint8_t *buf, size_t count);
void *state;
size_t bytes_left;
};
The `callback` must always be a function pointer. `Bytes_left` is an
upper limit on the number of bytes that will be read. You can use
SIZE_MAX if your callback handles EOF as described above.
**Example:**
This function binds an input stream to stdin:
bool callback(pb_istream_t *stream, uint8_t *buf, size_t count)
{
FILE *file = (FILE*)stream->state;
bool status;
if (buf == NULL)
{
while (count-- && fgetc(file) != EOF);
return count == 0;
}
status = (fread(buf, 1, count, file) == count);
if (feof(file))
stream->bytes_left = 0;
return status;
}
pb_istream_t stdinstream = {&callback, stdin, SIZE_MAX};
## Data types
Most Protocol Buffers datatypes have directly corresponding C datatypes,
such as `int32` is `int32_t`, `float` is `float` and `bool` is `bool`. However, the
variable-length datatypes are more complex:
1) Strings, bytes and repeated fields of any type map to callback
functions by default.
2) If there is a special option `(nanopb).max_size` specified in the
.proto file, string maps to null-terminated char array and bytes map
to a structure containing a char array and a size field.
3) If `(nanopb).fixed_length` is set to `true` and
`(nanopb).max_size` is also set, then bytes map to an inline byte
array of fixed size.
4) If there is a special option `(nanopb).max_count` specified on a
repeated field, it maps to an array of whatever type is being
repeated. Another field will be created for the actual number of
entries stored.
5) If `(nanopb).fixed_count` is set to `true` and
`(nanopb).max_count` is also set, the field for the actual number
of entries will not by created as the count is always assumed to be
max count.
### Examples of .proto specifications vs. generated structure
**Simple integer field:**\
.proto: `int32 age = 1;`\
.pb.h: `int32_t age;`
**String with unknown length:**\
.proto: `string name = 1;`\
.pb.h: `pb_callback_t name;`
**String with known maximum length:**\
.proto: `string name = 1 [(nanopb).max_length = 40];`\
.pb.h: `char name[41];`
**Repeated string with unknown count:**\
.proto: `repeated string names = 1;`\
.pb.h: `pb_callback_t names;`
**Repeated string with known maximum count and size:**\
.proto: `repeated string names = 1 [(nanopb).max_length = 40, (nanopb).max_count = 5];`\
.pb.h: `size_t names_count;` `char names[5][41];`
**Bytes field with known maximum size:**\
.proto: `bytes data = 1 [(nanopb).max_size = 16];`\
.pb.h: `PB_BYTES_ARRAY_T(16) data;`, where the struct contains `{pb_size_t size; pb_byte_t bytes[n];}`
**Bytes field with fixed length:**\
.proto: `bytes data = 1 [(nanopb).max_size = 16, (nanopb).fixed_length = true];`\
.pb.h: `pb_byte_t data[16];`
**Repeated integer array with known maximum size:**\
.proto: `repeated int32 numbers = 1 [(nanopb).max_count = 5];`\
.pb.h: `pb_size_t numbers_count;` `int32_t numbers[5];`
**Repeated integer array with fixed count:**\
.proto: `repeated int32 numbers = 1 [(nanopb).max_count = 5, (nanopb).fixed_count = true];`\
.pb.h: `int32_t numbers[5];`
The maximum lengths are checked in runtime. If string/bytes/array
exceeds the allocated length, `pb_decode()` will return false.
> **Note:** For the `bytes` datatype, the field length checking may not be
exact. The compiler may add some padding to the `pb_bytes_t`
structure, and the nanopb runtime doesn't know how much of the
structure size is padding. Therefore it uses the whole length of the
structure for storing data, which is not very smart but shouldn't cause
problems. In practise, this means that if you specify
`(nanopb).max_size=5` on a `bytes` field, you may be able to store 6
bytes there. For the `string` field type, the length limit is exact.
> **Note:** The decoder only keeps track of one `fixed_count` repeated field at a time. Usually this it not an issue because all elements of a repeated field occur end-to-end. Interleaved array elements of several `fixed_count` repeated fields would be a valid protobuf message, but would get rejected by nanopb decoder with error `"wrong size for fixed count field"`.
## Field callbacks
When a field has dynamic length, nanopb cannot statically allocate
storage for it. Instead, it allows you to handle the field in whatever
way you want, using a callback function.
The [pb_callback_t](reference.html#pb-callback-t) structure contains a
function pointer and a `void` pointer called `arg` you can use for
passing data to the callback. If the function pointer is NULL, the field
will be skipped. A pointer to the `arg` is passed to the function, so
that it can modify it and retrieve the value.
The actual behavior of the callback function is different in encoding
and decoding modes. In encoding mode, the callback is called once and
should write out everything, including field tags. In decoding mode, the
callback is called repeatedly for every data item.
To write more complex field callbacks, it is recommended to read the
[Google Protobuf Encoding Specification](https://developers.google.com/protocol-buffers/docs/encoding).
### Encoding callbacks
bool (*encode)(pb_ostream_t *stream, const pb_field_iter_t *field, void * const *arg);
| | |
| ---------- | ------------------------------------------------------------------ |
| `stream` | Output stream to write to |
| `field` | Iterator for the field currently being encoded or decoded. |
| `arg` | Pointer to the `arg` field in the `pb_callback_t` structure. |
When encoding, the callback should write out complete fields, including
the wire type and field number tag. It can write as many or as few
fields as it likes. For example, if you want to write out an array as
`repeated` field, you should do it all in a single call.
Usually you can use [pb_encode_tag_for_field](reference.html#pb-encode-tag-for-field) to
encode the wire type and tag number of the field. However, if you want
to encode a repeated field as a packed array, you must call
[pb_encode_tag](reference.html#pb-encode-tag) instead to specify a
wire type of `PB_WT_STRING`.
If the callback is used in a submessage, it will be called multiple
times during a single call to [pb_encode](reference.html#pb-encode). In
this case, it must produce the same amount of data every time. If the
callback is directly in the main message, it is called only once.
This callback writes out a dynamically sized string:
bool write_string(pb_ostream_t *stream, const pb_field_iter_t *field, void * const *arg)
{
char *str = get_string_from_somewhere();
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_string(stream, (uint8_t*)str, strlen(str));
}
### Decoding callbacks
bool (*decode)(pb_istream_t *stream, const pb_field_iter_t *field, void **arg);
| | |
| ---------- | ------------------------------------------------------------------ |
| `stream` | Input stream to read from |
| `field` | Iterator for the field currently being encoded or decoded. |
| `arg` | Pointer to the `arg` field in the `pb_callback_t` structure. |
When decoding, the callback receives a length-limited substring that
reads the contents of a single field. The field tag has already been
read. For `string` and `bytes`, the length value has already been
parsed, and is available at `stream->bytes_left`.
The callback will be called multiple times for repeated fields. For
packed fields, you can either read multiple values until the stream
ends, or leave it to [pb_decode](reference.html#pb-decode) to call your
function over and over until all values have been read.
This callback reads multiple integers and prints them:
bool read_ints(pb_istream_t *stream, const pb_field_iter_t *field, void **arg)
{
while (stream->bytes_left)
{
uint64_t value;
if (!pb_decode_varint(stream, &value))
return false;
printf("%lld\n", value);
}
return true;
}
### Function name bound callbacks
bool MyMessage_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field);
| | |
| ---------- | ------------------------------------------------------------------ |
| `istream` | Input stream to read from, or NULL if called in encoding context. |
| `ostream` | Output stream to write to, or NULL if called in decoding context. |
| `field` | Iterator for the field currently being encoded or decoded. |
Storing function pointer in `pb_callback_t` fields inside
the message requires extra storage space and is often cumbersome. As an
alternative, the generator options `callback_function` and
`callback_datatype` can be used to bind a callback function
based on its name.
Typically this feature is used by setting
`callback_datatype` to e.g. `void\*` or other
data type used for callback state. Then the generator will automatically
set `callback_function` to
`MessageName_callback` and produce a prototype for it in
generated `.pb.h`. By implementing this function in your own
code, you will receive callbacks for fields without having to separately
set function pointers.
If you want to use function name bound callbacks for some fields and
`pb_callback_t` for other fields, you can call
`pb_default_field_callback` from the message-level
callback. It will then read a function pointer from
`pb_callback_t` and call it.
## Message descriptor
For using the `pb_encode()` and `pb_decode()` functions, you need a
description of all the fields contained in a message. This description
is usually autogenerated from .proto file.
For example this submessage in the Person.proto file:
~~~~ protobuf
message Person {
message PhoneNumber {
required string number = 1 [(nanopb).max_size = 40];
optional PhoneType type = 2 [default = HOME];
}
}
~~~~
This in turn generates a macro list in the `.pb.h` file:
#define Person_PhoneNumber_FIELDLIST(X, a) \
X(a, STATIC, REQUIRED, STRING, number, 1) \
X(a, STATIC, OPTIONAL, UENUM, type, 2)
Inside the `.pb.c` file there is a macro call to
`PB_BIND`:
PB_BIND(Person_PhoneNumber, Person_PhoneNumber, AUTO)
These macros will in combination generate `pb_msgdesc_t`
structure and associated lists:
const uint32_t Person_PhoneNumber_field_info[] = { ... };
const pb_msgdesc_t * const Person_PhoneNumber_submsg_info[] = { ... };
const pb_msgdesc_t Person_PhoneNumber_msg = {
2,
Person_PhoneNumber_field_info,
Person_PhoneNumber_submsg_info,
Person_PhoneNumber_DEFAULT,
NULL,
};
The encoding and decoding functions take a pointer to this structure and
use it to process each field in the message.
## Oneof
Protocol Buffers supports
[oneof](https://developers.google.com/protocol-buffers/docs/reference/proto2-spec#oneof_and_oneof_field)
sections, where only one of the fields contained within can be present. Here is an example of `oneof` usage:
~~~~ protobuf
message MsgType1 {
required int32 value = 1;
}
message MsgType2 {
required bool value = 1;
}
message MsgType3 {
required int32 value1 = 1;
required int32 value2 = 2;
}
message MyMessage {
required uint32 uid = 1;
required uint32 pid = 2;
required uint32 utime = 3;
oneof payload {
MsgType1 msg1 = 4;
MsgType2 msg2 = 5;
MsgType3 msg3 = 6;
}
}
~~~~
Nanopb will generate `payload` as a C union and add an additional field
`which_payload`:
typedef struct _MyMessage {
uint32_t uid;
uint32_t pid;
uint32_t utime;
pb_size_t which_payload;
union {
MsgType1 msg1;
MsgType2 msg2;
MsgType3 msg3;
} payload;
} MyMessage;
`which_payload` indicates which of the `oneof` fields is actually set.
The user is expected to set the field manually using the correct field
tag:
MyMessage msg = MyMessage_init_zero;
msg.payload.msg2.value = true;
msg.which_payload = MyMessage_msg2_tag;
Notice that neither `which_payload` field nor the unused fields in
`payload` will consume any space in the resulting encoded message.
When a field inside `oneof` contains `pb_callback_t`
fields, the callback values cannot be set before decoding. This is
because the different fields share the same storage space in C
`union`. Instead either function name bound callbacks or a
separate message level callback can be used. See
[tests/oneof_callback](https://github.com/nanopb/nanopb/tree/master/tests/oneof_callback)
for an example on this.
## Extension fields
Protocol Buffers supports a concept of [extension
fields](https://developers.google.com/protocol-buffers/docs/proto#extensions),
which are additional fields to a message, but defined outside the actual
message. The definition can even be in a completely separate .proto
file.
The base message is declared as extensible by keyword `extensions` in
the .proto file:
~~~~ protobuf
message MyMessage {
.. fields ..
extensions 100 to 199;
}
~~~~
For each extensible message, `nanopb_generator.py` declares an
additional callback field called `extensions`. The field and associated
datatype `pb_extension_t` forms a linked list of handlers. When an
unknown field is encountered, the decoder calls each handler in turn
until either one of them handles the field, or the list is exhausted.
The actual extensions are declared using the `extend` keyword in the
.proto, and are in the global namespace:
~~~~ protobuf
extend MyMessage {
optional int32 myextension = 100;
}
~~~~
For each extension, `nanopb_generator.py` creates a constant of type
`pb_extension_type_t`. To link together the base message and the
extension, you have to:
1. Allocate storage for your field, matching the datatype in the
.proto. For example, for a `int32` field, you need a `int32_t`
variable to store the value.
2. Create a `pb_extension_t` constant, with pointers to your variable
and to the generated `pb_extension_type_t`.
3. Set the `message.extensions` pointer to point to the
`pb_extension_t`.
An example of this is available in `tests/test_encode_extensions.c`
and `tests/test_decode_extensions.c`.
## Default values
Protobuf has two syntax variants, proto2 and proto3. Of these proto2 has
user definable default values that can be given in .proto file:
~~~~ protobuf
message MyMessage {
optional bytes foo = 1 [default = "ABC\x01\x02\x03"];
optional string bar = 2 [default = "åäö"];
}
~~~~
Nanopb will generate both static and runtime initialization for the
default values. In `myproto.pb.h` there will be a
`#define MyMessage_init_default {...}` that can be used to initialize
whole message into default values:
MyMessage msg = MyMessage_init_default;
In addition to this, `pb_decode()` will initialize message
fields to defaults at runtime. If this is not desired,
`pb_decode_ex()` can be used instead.
## Message framing
Protocol Buffers does not specify a method of framing the messages for
transmission. This is something that must be provided by the library
user, as there is no one-size-fits-all solution. Typical needs for a
framing format are to:
1. Encode the message length.
2. Encode the message type.
3. Perform any synchronization and error checking that may be needed
depending on application.
For example UDP packets already fulfill all the requirements, and TCP
streams typically only need a way to identify the message length and
type. Lower level interfaces such as serial ports may need a more robust
frame format, such as HDLC (high-level data link control).
Nanopb provides a few helpers to facilitate implementing framing
formats:
1. Functions `pb_encode_ex` and `pb_decode_ex` prefix the message
data with a varint-encoded length.
2. Union messages and oneofs are supported in order to implement
top-level container messages.
3. Message IDs can be specified using the `(nanopb_msgopt).msgid`
option and can then be accessed from the header.
## Return values and error handling
Most functions in nanopb return bool: `true` means success, `false`
means failure. There is also support for error messages for
debugging purposes: the error messages go in `stream->errmsg`.
The error messages help in guessing what is the underlying cause of the
error. The most common error conditions are:
1) Invalid protocol buffers binary message.
2) Mismatch between binary message and .proto message type.
3) Unterminated message (incorrect message length).
4) Exceeding the max_size or bytes_left of a stream.
5) Exceeding the max_size/max_count of a string or array field
6) IO errors in your own stream callbacks.
7) Errors that happen in your callback functions.
8) Running out of memory, i.e. stack overflow.
9) Invalid field descriptors (would usually mean a bug in the generator).
## Static assertions
Nanopb code uses static assertions to check size of structures at the compile
time. The `PB_STATIC_ASSERT` macro is defined in `pb.h`. If ISO C11 standard
is available, the C standard `_Static_assert` keyword is used, otherwise a
negative sized array definition trick is used.
Common reasons for static assertion errors are:
1. `FIELDINFO_DOES_NOT_FIT_width2` with `width1` or `width2`:
Message that is larger than 256 bytes, but nanopb generator does not detect
it for some reason. Often resolved by giving all `.proto` files as argument
to `nanopb_generator.py` at the same time, to ensure submessage definitions
are found. Alternatively `(nanopb).descriptorsize = DS_4` option can be
given manually.
2. `FIELDINFO_DOES_NOT_FIT_width4` with `width4`:
Message that is larger than 64 kilobytes. There will be a better error
message for this in a future nanopb version, but currently it asserts here.
The compile time option `PB_FIELD_32BIT` should be specified either on
C compiler command line or by editing `pb.h`. This will increase the sizes
of integer types used internally in nanopb code.
3. `DOUBLE_MUST_BE_8_BYTES`:
Some platforms, most notably AVR, do not support the 64-bit `double` type,
only 32-bit `float`. The compile time option `PB_CONVERT_DOUBLE_FLOAT` can
be defined to convert between the types automatically. The conversion
results in small rounding errors and takes unnecessary space in transmission,
so changing the `.proto` to use `float` type is often better.
4. `INT64_T_WRONG_SIZE`:
The `stdint.h` system header is incorrect for the C compiler being used.
This can result from erroneous compiler include path.
If the compiler actually does not support 64-bit types, the compile time
option `PB_WITHOUT_64BIT` can be used.
5. `variably modified array size`:
The compiler used has problems resolving the array-based static assert at
compile time. Try setting the compiler to C11 standard mode if possible.
If static assertions cannot be made to work on the compiler used, the
compile-time option `PB_NO_STATIC_ASSERT` can be specified to turn them off.

2869
third_party/nanopb/docs/generator_flow.svg vendored Normal file

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 112 KiB

158
third_party/nanopb/docs/index.md vendored Normal file
View file

@ -0,0 +1,158 @@
# Nanopb: Overview
Nanopb is an ANSI-C library for encoding and decoding messages in
Google's [Protocol Buffers](https://developers.google.com/protocol-buffers/docs/reference/overview)
format with minimal requirements for RAM and code space. It is primarily
suitable for 32-bit microcontrollers.
Documentation version
---------------------
This documentation applies for nanopb 0.4.0 and later versions. For
documentation of older releases,
[see here](https://github.com/nanopb/nanopb/blob/maintenance_0.3/docs/index.rst).
Overall structure
-----------------
For the runtime program, you always need `pb.h` for type declarations
and `pb_common.h/c` for base functions. Depending on whether you want
to encode, decode, or both, you also need `pb_encode.h/c` or
`pb_decode.h/c`.
The high-level encoding and decoding functions take a pointer to
`pb_msgdesc_t` structure, which describes the fields of a message
structure. Usually you want these autogenerated from a `.proto` file.
The tool script `nanopb_generator.py` accomplishes this.
![Image: Nanopb generator flow](generator_flow.svg)
So a typical project might include these files:
1. Nanopb runtime library:
- pb.h
- pb_common.h and pb_common.c (always needed)
- pb_decode.h and pb_decode.c (needed for decoding messages)
- pb_encode.h and pb_encode.c (needed for encoding messages)
2. Protocol description (you can have many):
- person.proto (just an example)
- person.pb.c (autogenerated, contains message descriptors)
- person.pb.h (autogenerated, contains type declarations and macros)
Features and limitations
------------------------
**Features**
1) Pure C runtime
2) Small code size (5--10 kB depending on processor and compilation options, plus any message definitions)
3) Small ram usage (typically \~300 bytes stack, plus any message structs)
4) Allows specifying maximum size for strings and arrays, so that they can be allocated statically.
5) No malloc needed: everything can be allocated statically or on the stack. Optional malloc support available.
6) You can use either encoder or decoder alone to cut the code size in half.
7) Support for most protobuf features, including: all data types,
nested submessages, default values, repeated and optional fields,
oneofs, packed arrays, extension fields.
8) Callback mechanism for handling messages larger than can fit in available RAM.
9) Extensive set of tests.
**Limitations**
1) Some speed has been sacrificed for code size.
2) Encoding is focused on writing to streams. For memory buffers only it could be made more efficient.
3) The deprecated Protocol Buffers feature called "groups" is not supported.
4) Fields in the generated structs are ordered by the tag number, instead of the natural ordering in .proto file.
5) Unknown fields are not preserved when decoding and re-encoding a message.
6) Reflection (runtime introspection) is not supported. E.g. you can't request a field by giving its name in a string.
7) Numeric arrays are always encoded as packed, even if not marked as packed in .proto.
8) Cyclic references between messages are supported only in callback and malloc mode.
9) Nanopb doesn't have a stable ABI (application binary interface)
between versions, so using it as a shared library (.so / .dll)
requires extra care.
Getting started
---------------
For starters, consider this simple message:
~~~~ protobuf
message Example {
required int32 value = 1;
}
~~~~
Save this in `message.proto` and compile it:
user@host:~$ python nanopb/generator/nanopb_generator.py message.proto
You should now have in `message.pb.h`:
typedef struct {
int32_t value;
} Example;
extern const pb_msgdesc_t Example_msg;
#define Example_fields &Example_msg
Then you have to include the nanopb headers and the generated header:
#include <pb_encode.h>
#include "message.pb.h"
Now in your main program do this to encode a message:
Example mymessage = {42};
uint8_t buffer[10];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
pb_encode(&stream, Example_fields, &mymessage);
After that, buffer will contain the encoded message. The number of bytes
in the message is stored in `stream.bytes_written`. You can feed the
message to `protoc --decode=Example message.proto` to verify its
validity.
For a complete example of the simple case, see [examples/simple/simple.c](https://github.com/nanopb/nanopb/blob/master/examples/simple/simple.c).
For a more complex example with network interface, see the [examples/network_server](https://github.com/nanopb/nanopb/tree/master/examples/network_server) subdirectory.
Compiler requirements
---------------------
Nanopb should compile with most ansi-C compatible compilers. It however
requires a few header files to be available:
1) `string.h`, with these functions: `strlen`, `memcpy`, `memset`
2) `stdint.h`, for definitions of `int32_t` etc.
3) `stddef.h`, for definition of `size_t`
4) `stdbool.h`, for definition of `bool`
5) `limits.h`, for definition of `CHAR_BIT`
If these header files do not come with your compiler, you can use the
file `extra/pb_syshdr.h` instead. It contains an example of how to
provide the dependencies. You may have to edit it a bit to suit your
custom platform.
To use the pb_syshdr.h, define `PB_SYSTEM_HEADER` as
`"pb_syshdr.h"` (including the quotes). Similarly, you can provide a
custom include file, which should provide all the dependencies listed
above.
Running the test cases
----------------------
Extensive unittests and test cases are included under the `tests`
folder.
To build the tests, you will need the [scons](http://www.scons.org/)
build system. The tests should be runnable on most platforms. Windows
and Linux builds are regularly tested. The tests also support embedded
targets: STM32 (ARM Cortex-M) and AVR builds are regularly tested.
In addition to the build system, you will also need a working Google
Protocol Buffers `protoc` compiler, and the Python bindings for Protocol
Buffers.
Easiest way to install dependencies is to use the Python package manager
[pip](https://pypi.org/project/pip/), which works on all platforms supported by Python:
pip3 install scons protobuf grpcio-tools

BIN
third_party/nanopb/docs/logo/logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

1470
third_party/nanopb/docs/logo/logo.svg vendored Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

233
third_party/nanopb/docs/lsr.css vendored Normal file
View file

@ -0,0 +1,233 @@
/*
Original author: Peter Parente
Date: 2008/01/22
Version: 1.0 (modified)
Copyright: This stylesheet has been placed in the public domain - free to edit and use for all uses.
--
Heavily modified for use in nanopb documentation.
2011-2020 Petteri Aimonen
*/
body {
font: 100% sans-serif;
background: #ffffff;
color: black;
margin: 2em;
padding: 0em 2em;
max-width: 1200px;
}
p.topic-title {
font-weight: bold;
}
table.docinfo {
text-align: left;
margin: 2em 0em;
}
a[href] {
color: #436976;
background-color: transparent;
}
a.toc-backref {
text-decoration: none;
}
h1 a[href] {
color: #003a6b;
text-decoration: none;
background-color: transparent;
}
a.strong {
font-weight: bold;
}
img {
margin: 0;
border: 0;
}
blockquote {
border-left: 3px solid black;
background-color: #f6f6f6;
padding: 0.5em 1em 0.2em 1em;
}
li {
margin-bottom: 0.5em;
}
p {
margin: 0.5em 0 1em 0;
line-height: 1.5em;
}
p a:visited {
color: purple;
background-color: transparent;
}
p a:active {
color: red;
background-color: transparent;
}
a:hover {
text-decoration: none;
}
p img {
border: 0;
margin: 0;
}
p.rubric {
font-weight: bold;
font-style: italic;
}
em, cite {
font-style: normal;
font-family: monospace;
font-weight: bold;
}
pre {
border-left: 3px double #aaa;
padding: 5px 10px;
background-color: #f6f6f6;
}
code {
border: 1px solid rgba(128, 128, 128, 0.1);
padding: 1px 5px;
border-radius: 5px;
background-color: rgba(128, 128, 128, 0.05);
white-space: nowrap;
}
pre code {
border: none;
background-color: transparent;
padding: 0px;
}
h1, h2, h3, h4, h5, h6 {
color: #000;
background-color: transparent;
margin: 0em;
padding-top: 0.5em;
}
h1 {
color: #003a6b;
font-size: 180%;
margin-bottom: 0.5em;
border-bottom: 2px solid #aaa;
}
h2 {
color: #003a6b;
font-size: 130%;
margin-bottom: 0.5em;
border-bottom: 1px solid #aaa;
margin-top: 1.5em;
}
h3 {
font-size: 120%;
margin-bottom: 0.5em;
margin-top: 1.0em;
}
h4 {
font-size: 110%;
font-weight: bold;
margin-bottom: 0.5em;
margin-top: 0.5em;
}
h5 {
font-size: 105%;
font-weight: bold;
margin-bottom: 0.5em;
}
h6 {
font-size: 100%;
font-weight: bold;
margin-bottom: 0.5em;
}
dt {
font-style: italic;
}
dd {
margin-bottom: 1.5em;
}
table {
text-align: left;
border-collapse: collapse;
margin: 1.5em 0em;
}
table td, table th {
padding: 0.25em 1em;
border-top: 1px solid gray;
border-bottom: 1px solid gray;
}
#index {
margin: 2em 2em 2em 0em;
padding: 0em 1em;
border-top: 1px solid #aaa;
border-left: 1px solid #aaa;
border-bottom: 2px solid #555;
border-right: 2px solid #555;
max-width: 20em;
}
#index h2 {
margin-bottom: 0em;
margin-top: 0em;
color: #003a6b;
font-size: 100%;
border-bottom: 1px solid #aaa;
font-weight: bold;
}
#feedback_link {
float: right;
}
#feedback {
visibility: hidden;
padding: 1em;
border-radius: 5px;
position: fixed;
top: 10em;
right: 10em;
background: white;
border-top: 1px solid #aaa;
border-left: 1px solid #aaa;
border-bottom: 2px solid #555;
border-right: 2px solid #555;
}
#feedback:target {
visibility: visible;
}
#feedback .cancel {
color: #666;
padding-left: 2em;
}

648
third_party/nanopb/docs/migration.md vendored Normal file
View file

@ -0,0 +1,648 @@
# Nanopb: Migration from older versions
This document details all the breaking changes that have been made to
nanopb since its initial release. For each change, the rationale and
required modifications of user applications are explained. Also any
error indications are included, in order to make it easier to find this
document.
Nanopb-0.4.6 (2022-05-30)
-------------------------
### NANOPB_VERSION define is now a string
**Changes:** To ease `NANOPB_VERSION` macro usage, the value is directly a string.
**Required actions:** Most nanopb users probably never used that macro. If so,
you certainly use the `#` preprocessor to convert it as string. You, now,
only have to call it directly, like this for example:
`strcpy(myvar, NANOPB_VERSION);`
### FindNanopb.cmake now requires protoc 3.6.0 or newer by default
**Changes:** The default options passing method now uses `--plugin-opt` which
is supported by protoc 3.6.0 and newer (released in 2018).
**Required actions:** Update `protoc` if needed, or alternatively install
`grpcio-tools` package from `pip`. If neither is possible, the
`NANOPB_PROTOC_OLDER_THAN_3_6_0` cmake option can be used to restore the old
style option passing. Note that it has problems with special characters such
as `:`.
**Error indications:** "`protoc: Unknown flag: --nanopb_opt`"
### pb.h uses C11 _Static_assert keyword by default
**Rationale:** The nanopb generated headers use static assertions to catch
errors at compile time. There are several mechanisms to implement this.
The most widely supported is C11 `_Static_assert` keyword.
Previously the code used negative size array definition trick, which is
supported already in C99 but does not work with every compiler and can
produce confusing error messages.
**Changes:** Now `_Static_assert` is used by default.
**Required actions:** If the keyword is not recognized, set the compiler to
C11 standard mode if available. If it is not available, define either `PB_C99_STATIC_ASSERT`
or `PB_NO_STATIC_ASSERT` in `pb.h` or on compiler command line.
**Error indications:** `Undefined identifier _Static_assert`
Nanopb-0.4.4 (2020-11-25)
-------------------------
### Remove outdated generator/nanopb/options.proto
**Changes:** Back in 2018, it was considered in pull request #241 to
move nanopb generator options to a separate namespace. For this reason,
a transitional file was added. It was later abandoned and is now removed
to avoid confusion.
**Required actions:** Most nanopb users probably never used that transitional
file at all. If your `.proto` files import it, change to using `generator/proto/nanopb.proto`.
**Error indications:** Errors about missing file `options.proto` when running
the generator.
Nanopb-0.4.3 (2020-09-21)
-------------------------
### pb_msgdesc_t struct has new fields
**Changes:** New fields `required_field_count` and
`largest_tag` were added to `pb_msgdesc_t`
and existing fields were reordered.
**Required actions:** All `.pb.c` files must be recompiled.
Regeneration is not needed.
**Error indications:** Messages may fail to encode or decode, or the
code can crash inside `load_descriptor_values()` in
`pb_common.c`.
Nanopb-0.4.2 (2020-06-23)
-------------------------
### Generator now uses Python 3 by default
**Rationale:** Previously `nanopb-generator.py` had hashbang
of `#!/usr/bin/env python`, which would execute with Python
2 on most systems. Python 2 is now deprecated and many libraries are
dropping support for it, which makes installing dependencies difficult.
While `nanopb_generator.py` has worked with Python 3 for
years now, and overriding the python version was possible with
virtualenv, that was an extra complication.
**Changes:** Hashbang now uses `#!/usr/bin/env python3`.
New file `nanopb_generator.py2` can be used to run with
Python 2, if necessary.
**Required actions:** If possible, just verify Python 3 is installed and
necessary dependencies are installed for it. For example `pip3 install protobuf grpcio-tools`
should take care of it. If this is not possible, call `nanopb_generator.py2` from your build
scripts instead.
**Error indications:** `python3: command not found` if
Python 3 is not installed.
`Could not import the Google protobuf Python libraries` if dependencies are only installed for Python 2.
Nanopb-0.4.0 (2019-12-20)
-------------------------
### New field descriptor format
**Rationale:** Previously information about struct fields was stored as
an array of `pb_field_t` structures. This was a
straightforward method, but required allocating space for e.g.
submessage type and array size for all fields, even though most fields
are not submessages nor arrays.
**Changes:** Now field information is encoded more efficiently in
`uint32_t` array in a variable-length format. Old
`pb_field_t` structure has been removed and it is now a
typedef for `pb_field_iter_t`. This retains compatibility
with most old callback definitions. The field definitions in
`.pb.h` files are now of type `pb_msgdesc_t`.
**Required actions:** If your own code accesses the low-level field
information in `pb_field_t`, it must be modified to do so
only through the functions declared in `pb_common.h`.
**Error indications:** `incompatible pointer type` errors
relating to `pb_field_t`
### Changes to generator default options
**Rationale:** Previously nanopb_generator added a timestamp header to
generated files and used only basename of files in
`#include` directives. This is different than what the
`protoc` C++ backend does.
**Changes:** Now default options are `--no-timestamp` and
`--no-strip-path`.
**Required actions:** If old behaviour is desired, add
`--timestamp` and `--strip-path` options to
`nanopb_generator.py` or on `protoc` command
line as `--nanopb_out=--timestamp,--strip-path:outdir`.
**Error indications:** Compiler error: cannot find include file
`mymessage.pb.h` when compiling
`mymessage.pb.c`.
### Removal of bundled plugin.proto
**Rationale:** Google's Python protobuf library, which is used in
nanopb generator, has included `plugin_pb2` with it since
version 3.1.0. It is not necessary to bundle it with nanopb anymore.
**Required actions:** Update `python-protobuf` to version
3.1.0 or newer.
**Error indications:** `ImportError: No module named compiler.plugin_pb2`
### .options file is now always case-sensitive
**Rationale:** Previously field names in `.options` file
were case-sensitive on Linux and case-insensitive on Windows. This was
by accident. Because `.proto` files are case-sensitive,
`.options` files should be too.
**Changes:** Now field names in `.options` are always
case-sensitive, and matched by `fnmatchcase()` instead of
`fnmatch()`.
**Required actions:** If field names in `.options` are not
capitalized the same as in `.proto`, they must be updated.
### `CHAR_BIT` define is now needed
**Rationale:** To check whether the platform has 8-bit or larger chars,
the C standard `CHAR_BIT` macro is needed.
**Changes:** `pb.h` now includes `limits.h` for this macro.
**Required actions:** If your platform doesn't have `limits.h`
available, you can define the macro in `pb_syshdr.h`. There is an
example in `extra` directory.
**Error indications:** `"Cannot find include file <limits.h>."` or
`"Undefined identifier: CHAR_BIT."`
### Strings must now always be null-terminated
**Rationale:** Previously `pb_encode()` would accept non-terminated
strings and assume that they are the full length of the defined array.
However, `pb_decode()` would reject such messages because null
terminator wouldn't fit in the array.
**Changes:** `pb_encode()` will now return an error if null terminator
is missing. Maximum encoded message size calculation is changed
accordingly so that at most `max_size-1` strings are assumed. New field
option `max_length` can be used to define the maximum string length,
instead of the array size.
**Required actions:** If your strings were previously filling the whole
allocated array, increase the size of the field by 1.
**Error indications:** `pb_encode()` returns error `unterminated string`.
### Removal of per-field default value constants
**Rationale:** Previously nanopb declared a
`fieldname_default` constant variable for each field with a
default value, and used these internally to initialize messages. This
however used unnecessarily large amount of storage for the values. The
variables were mostly for internal usage, but were available in the
header file.
**Changes:** Default values are now stored as an encoded protobuf
message.
**Required actions:** If your code previously used default constants, it
will have to be adapted to take the default value in some other way,
such as by defining
`static const MyMessage msg_default = MyMessage_init_default;` and accessing
`msg_default.fieldname`.
**Error indications:** Compiler error about `fieldname_default` being undeclared.
### Zero tag in message now raises error by default
**Rationale:** Previously nanopb has allowed messages to be terminated
by a null byte, which is read as zero tag value. Most other protobuf
implementations don't support this, so it is not very useful feature.
It has also been noted that this can complicate debugging issues with
corrupted messages.
**Changes:** `pb_decode()` now gives error when it
encounters zero tag value. A new function `pb_decode_ex()`
supports flag `PB_DECODE_NULLTERMINATED` that supports
decoding null terminated messages.
**Required actions:** If application uses null termination for messages,
switch it to use `pb_decode_ex()` and
`pb_encode_ex()`. If compatibility with 0.3.9.x is needed,
there are also `pb_decode_nullterminated()` and
`pb_encode_nullterminated()` macros, which work both in
0.4.0 and 0.3.9.
**Error indications:** Error message from `pb_decode()`: `zero_tag`.
### Submessages now have has_field in proto3 mode
**Rationale:** Previously nanopb considered proto3 submessages as
present only when their contents was non-zero. Most other protobuf
libraries allow explicit null state for submessages.
**Changes:** Submessages now have separate `has_field` in
proto3 mode also.
**Required actions:** When using submessages in proto3 mode, user code
must now set `mymsg.has_submsg = true` for each submessage
that is present. Alternatively, the field option
`proto3_singular_msgs` can be used to restore the old
behavior.
**Error indications:** Submessages do not get encoded.
### PB_OLD_CALLBACK_STYLE option has been removed
**Rationale:** Back in 2013, function signature for callbacks was
changed. The `PB_OLD_CALLBACK_STYLE` option allowed
compatibility with old code, but complicated code and testing because of
the different options.
**Changes:** `PB_OLD_CALLBACK_STYLE` option no-longer has
any effect.
**Required actions:** If `PB_OLD_CALLBACK_STYLE` option
was in use previously, function signatures must be updated to use double
pointers (`void**` and `void * const *`).
**Error indications:** Assignment from incompatible pointer type.
### protoc insertion points are no longer included by default
**Rationale:** Protoc allows including comments in form
`@@protoc_insertion_point` to identify locations for
other plugins to insert their own extra content. Previously these were
included by default, but they clutter the generated files and are rarely
used.
**Changes:** Insertion points are now included only when
`--protoc-insertion-points` option is passed to the
generator.
Nanopb-0.3.9.4, 0.4.0 (2019-10-13)
----------------------------------
### Fix generation of min/max defines for enum types
**Rationale:** Nanopb generator makes \#defines for enum minimum and
maximum value. Previously these defines incorrectly had the first and
last enum value, instead of the actual minimum and maximum. (issue
#405)
**Changes:** Minimum define now always has the smallest value, and
maximum define always has the largest value.
**Required actions:** If these defines are used and enum values in
.proto file are not defined in ascending order, user code behaviour may
change. Check that user code doesn\'t expect the old, incorrect
first/last behaviour.
### Fix undefined behavior related to bool fields
**Rationale:** In C99, `bool` variables are not allowed to
have other values than `true` and `false`.
Compilers use this fact in optimization, and constructs like
`int foo = msg.has_field ? 100 : 0;` will give unexpected results
otherwise. Previously nanopb didn\'t enforce that decoded bool fields
had valid values.
**Changes:** Bool fields are now handled separately as
`PB_LTYPE_BOOL`. The `LTYPE` descriptor
numbers for other field types were renumbered.
**Required actions:** Source code files must be recompiled, but
regenerating `.pb.h`/`.pb.c` files from
`.proto` is not required. If user code directly uses the
nanopb internal field representation (search for
`PB_LTYPE_VARINT` in source), it may need updating.
Nanopb-0.3.9.1, 0.4.0 (2018-04-14)
----------------------------------
### Fix handling of string and bytes default values
**Rationale:** Previously nanopb didn't properly decode special
character escapes like `\200` emitted by protoc. This caused these
escapes to end up verbatim in the default values in .pb.c file.
**Changes:** Escapes are now decoded, and e.g. `\200` or `\x80`
results in {0x80} for bytes field and `"\x80"` for string field.
**Required actions:** If code has previously relied on `\` in default
value being passed through verbatim, it must now be changed to `\\`.
Nanopb-0.3.8 (2017-03-05)
-------------------------
### Fully drain substreams before closing
**Rationale:** If the substream functions were called directly and the
caller did not completely empty the substring before closing it, the
parent stream would be put into an incorrect state.
**Changes:** `pb_close_string_substream` can now error and returns a
boolean.
**Required actions:** Add error checking onto any call to
`pb_close_string_substream`.
### Change oneof format in .pb.c files
**Rationale:** Previously two oneofs in a single message would be
erroneously handled as part of the same union.
**Changes:** Oneofs fields now use special `PB_DATAOFFSET_UNION`
offset type in generated .pb.c files to distinguish whether they are the
first or following field inside an union.
**Required actions:** Regenerate `.pb.c/.pb.h` files with new nanopb
version if oneofs are used.
Nanopb-0.3.5 (2016-02-13)
-------------------------
### Add support for platforms without uint8_t
**Rationale:** Some platforms cannot access 8-bit sized values directly,
and do not define `uint8_t`. Nanopb previously didn\'t support these
platforms.
**Changes:** References to `uint8_t` were replaced with several
alternatives, one of them being a new `pb_byte_t` typedef. This in
turn uses `uint_least8_t` which means the smallest available type.
**Required actions:** If your platform does not have a
standards-compliant `stdint.h`, it may lack the definition for
`[u]int_least8_t`. This must be added manually, example can be found
in `extra/pb_syshdr.h`.
**Error indications:** Compiler error: `"unknown type name 'uint_least8_t'"`.
Nanopb-0.3.2 (2015-01-24)
-------------------------
### Add support for OneOfs
**Rationale:** Previously nanopb did not support the `oneof` construct
in `.proto` files. Those fields were generated as regular `optional`
fields.
**Changes:** OneOfs are now generated as C unions. Callback fields are
not supported inside oneof and generator gives an error.
**Required actions:** The generator option `no_unions` can be used to
restore old behaviour and to allow callbacks to be used. To use unions,
one change is needed: use `which_xxxx` field to detect which field is
present, instead of `has_xxxx`. Compare the value against
`MyStruct_myfield_tag`.
**Error indications:** Generator error: `"Callback fields inside of
oneof are not supported"`. Compiler error: `"Message"` has no member
named `"has_xxxx"`.
Nanopb-0.3.0 (2014-08-26)
-------------------------
### Separate field iterator logic to pb_common.c
**Rationale:** Originally, the field iteration logic was simple enough
to be duplicated in `pb_decode.c` and `pb_encode.c`. New field types
have made the logic more complex, which required the creation of a new
file to contain the common functionality.
**Changes:** There is a new file, `pb_common.c`, which must be included
in builds.
**Required actions:** Add `pb_common.c` to build rules. This file is
always required. Either `pb_decode.c` or `pb_encode.c` can still be
left out if some functionality is not needed.
**Error indications:** Linker error: undefined reference to
`pb_field_iter_begin`, `pb_field_iter_next` or similar.
### Change data type of field counts to pb_size_t
**Rationale:** Often nanopb is used with small arrays, such as 255 items
or less. Using a full `size_t` field to store the array count wastes
memory if there are many arrays. There already exists parameters
`PB_FIELD_16BIT` and `PB_FIELD_32BIT` which tell nanopb what is the
maximum size of arrays in use.
**Changes:** Generator will now use `pb_size_t` for the array
`_count` fields. The size of the type will be controlled by the
`PB_FIELD_16BIT` and `PB_FIELD_32BIT` compilation time options.
**Required actions:** Regenerate all `.pb.h` files. In some cases casts
to the `pb_size_t` type may need to be added in the user code when
accessing the `_count` fields.
**Error indications:** Incorrect data at runtime, crashes. But note that
other changes in the same version already require regenerating the files
and have better indications of errors, so this is only an issue for
development versions.
### Renamed some macros and identifiers
**Rationale:** Some names in nanopb core were badly chosen and
conflicted with ISO C99 reserved names or lacked a prefix. While they
haven\'t caused trouble so far, it is reasonable to switch to
non-conflicting names as these are rarely used from user code.
**Changes:** The following identifier names have changed:
- Macros:
- STATIC_ASSERT(x) -> PB_STATIC_ASSERT(x)
- UNUSED(x) -> PB_UNUSED(x)
- Include guards:
- PB_filename -> PB_filename_INCLUDED
- Structure forward declaration tags:
- _pb_field_t -> pb_field_s
- _pb_bytes_array_t -> pb_bytes_array_s
- _pb_callback_t -> pb_callback_s
- _pb_extension_type_t -> pb_extension_type_s
- _pb_extension_t -> pb_extension_s
- _pb_istream_t -> pb_istream_s
- _pb_ostream_t -> pb_ostream_s
**Required actions:** Regenerate all `.pb.c` files. If you use any of
the above identifiers in your application code, perform search-replace
to the new name.
**Error indications:** Compiler errors on lines with the macro/type
names.
Nanopb-0.2.9 (2014-08-09)
-------------------------
### Change semantics of generator -e option
**Rationale:** Some compilers do not accept filenames with two dots
(like in default extension .pb.c). The `-e` option to the generator
allowed changing the extension, but not skipping the extra dot.
**Changes:** The `-e` option in generator will no longer add the
prepending dot. The default value has been adjusted accordingly to
`.pb.c` to keep the default behaviour the same as before.
**Required actions:** Only if using the generator -e option. Add dot
before the parameter value on the command line.
**Error indications:** File not found when trying to compile generated
files.
Nanopb-0.2.7 (2014-04-07)
-------------------------
### Changed pointer-type bytes field datatype
**Rationale:** In the initial pointer encoding support since
nanopb-0.2.5, the bytes type used a separate `pb_bytes_ptr_t` type to
represent `bytes` fields. This made it easy to encode data from a
separate, user-allocated buffer. However, it made the internal logic
more complex and was inconsistent with the other types.
**Changes:** Dynamically allocated bytes fields now have the
`pb_bytes_array_t` type, just like statically allocated ones.
**Required actions:** Only if using pointer-type fields with the bytes
datatype. Change any access to `msg->field.size` to
`msg->field->size`. Change any allocation to reserve space of amount
`PB_BYTES_ARRAY_T_ALLOCSIZE(n)`. If the data pointer was begin
assigned from external source, implement the field using a callback
function instead.
**Error indications:** Compiler error: unknown type name
`pb_bytes_ptr_t`.
Nanopb-0.2.4 (2013-11-07)
-------------------------
### Remove the NANOPB_INTERNALS compilation option
**Rationale:** Having the option in the headers required the functions
to be non-static, even if the option is not used. This caused errors on
some static analysis tools.
**Changes:** The `\#ifdef` and associated functions were removed from
the header.
**Required actions:** Only if the `NANOPB_INTERNALS` option was
previously used. Actions are as listed under nanopb-0.1.3 and
nanopb-0.1.6.
**Error indications:** Compiler warning: implicit declaration of
function `pb_dec_string`, `pb_enc_string`, or similar.
Nanopb-0.2.1 (2013-04-14)
-------------------------
### Callback function signature
**Rationale:** Previously the auxiliary data to field callbacks was
passed as `void*`. This allowed passing of any data, but made it
unnecessarily complex to return a pointer from callback.
**Changes:** The callback function parameter was changed to `void**`.
**Required actions:** You can continue using the old callback style by
defining `PB_OLD_CALLBACK_STYLE`. Recommended action is to:
- Change the callback signatures to contain `void**` for decoders and `void * const *` for encoders.
- Change the callback function body to use **arg` instead of `arg`.
**Error indications:** Compiler warning: assignment from incompatible
pointer type, when initializing `funcs.encode` or `funcs.decode`.
Nanopb-0.2.0 (2013-03-02)
-------------------------
### Reformatted generated .pb.c file using macros
**Rationale:** Previously the generator made a list of C `pb_field_t`
initializers in the .pb.c file. This led to a need to regenerate all
.pb.c files after even small changes to the `pb_field_t` definition.
**Changes:** Macros were added to pb.h which allow for cleaner
definition of the .pb.c contents. By changing the macro definitions,
changes to the field structure are possible without breaking
compatibility with old .pb.c files.
**Required actions:** Regenerate all .pb.c files from the .proto
sources.
**Error indications:** Compiler warning: implicit declaration of
function `pb_delta_end`.
### Changed pb_type_t definitions
**Rationale:** The `pb_type_t` was previously an enumeration type.
This caused warnings on some compilers when using bitwise operations to
set flags inside the values.
**Changes:** The `pb_type_t` was changed to *typedef uint8_t*. The
values were changed to `#define`. Some value names were changed for
consistency.
**Required actions:** Only if you directly access the
`pb_field_t` contents in your own code, something which is
not usually done. Needed changes:
- Change `PB_HTYPE_ARRAY` to `PB_HTYPE_REPEATED`.
- Change `PB_HTYPE_CALLBACK` to `PB_ATYPE()` and `PB_ATYPE_CALLBACK`.
**Error indications:** Compiler error: `PB_HTYPE_ARRAY` or
`PB_HTYPE_CALLBACK` undeclared.
Nanopb-0.1.6 (2012-09-02)
-------------------------
### Refactored field decoder interface
**Rationale:** Similarly to field encoders in nanopb-0.1.3.
**Changes:** New functions with names `pb_decode_*` were added.
**Required actions:** By defining NANOPB_INTERNALS, you can still keep
using the old functions. Recommended action is to replace any calls with
the newer `pb_decode_*` equivalents.
**Error indications:** Compiler warning: implicit declaration of
function `pb_dec_string`, `pb_dec_varint`, `pb_dec_submessage` or
similar.
Nanopb-0.1.3 (2012-06-12)
-------------------------
### Refactored field encoder interface
**Rationale:** The old `pb_enc_*` functions were designed mostly for
the internal use by the core. Because they are internally accessed
through function pointers, their signatures had to be common. This led
to a confusing interface for external users.
**Changes:** New functions with names `pb_encode_*` were added. These
have easier to use interfaces. The old functions are now only thin
wrappers for the new interface.
**Required actions:** By defining NANOPB_INTERNALS, you can still keep
using the old functions. Recommended action is to replace any calls with
the newer `pb_encode_*` equivalents.
**Error indications:** Compiler warning: implicit declaration of
function `pb_enc_string`, *pb_enc_varint,`pb_enc_submessage\` or
similar.

1036
third_party/nanopb/docs/reference.md vendored Normal file

File diff suppressed because it is too large Load diff

92
third_party/nanopb/docs/security.md vendored Normal file
View file

@ -0,0 +1,92 @@
# Nanopb: Security model
Importance of security in a Protocol Buffers library
----------------------------------------------------
In the context of protocol buffers, security comes into play when
decoding untrusted data. Naturally, if the attacker can modify the
contents of a protocol buffers message, he can feed the application any
values possible. Therefore the application itself must be prepared to
receive untrusted values.
Where nanopb plays a part is preventing the attacker from running
arbitrary code on the target system. Mostly this means that there must
not be any possibility to cause buffer overruns, memory corruption or
invalid pointers by the means of crafting a malicious message.
Division of trusted and untrusted data
--------------------------------------
The following data is regarded as **trusted**. It must be under the
control of the application writer. Malicious data in these structures
could cause security issues, such as execution of arbitrary code:
1. Callback, pointer and extension fields in message structures given
to pb_encode() and pb_decode(). These fields are memory pointers,
and are generated depending on the message definition in the .proto
file.
2. The automatically generated field definitions, i.e.
`pb_msgdesc_t`.
3. Contents of the `pb_istream_t` and `pb_ostream_t` structures
(this does not mean the contents of the stream itself, just the
stream definition).
The following data is regarded as **untrusted**. Invalid/malicious data
in these will cause "garbage in, garbage out" behaviour. It will not
cause buffer overflows, information disclosure or other security
problems:
1. All data read from `pb_istream_t`.
2. All fields in message structures, except:
- callbacks (`pb_callback_t` structures)
- pointer fields and `_count` fields for pointers
- extensions (`pb_extension_t` structures)
Invariants
----------
The following invariants are maintained during operation, even if the
untrusted data has been maliciously crafted:
1. Nanopb will never read more than `bytes_left` bytes from
`pb_istream_t`.
2. Nanopb will never write more than `max_size` bytes to
`pb_ostream_t`.
3. Nanopb will never access memory out of bounds of the message
structure.
4. After `pb_decode()` returns successfully, the message structure will
be internally consistent:
- The `count` fields of arrays will not exceed the array size.
- The `size` field of bytes will not exceed the allocated size.
- All string fields will have null terminator.
- bool fields will have valid true/false values (since
nanopb-0.3.9.4)
- pointer fields will be either `NULL` or point to valid data
5. After `pb_encode()` returns successfully, the resulting message is a
valid protocol buffers message. (Except if user-defined callbacks
write incorrect data.)
6. All memory allocated by `pb_decode()` will be released by a subsequent
call to `pb_release()` on the same message.
Further considerations
----------------------
Even if the nanopb library is free of any security issues, there are
still several possible attack vectors that the application author must
consider. The following list is not comprehensive:
1. Stack usage may depend on the contents of the message. The message
definition places an upper bound on how much stack will be used.
Tests should be run with all fields present, to record the maximum
possible stack usage.
2. Callbacks can do anything. The code for the callbacks must be
carefully checked if they are used with untrusted data.
3. If using stream input, a maximum size should be set in
`pb_istream_t` to stop a denial of service attack from using an
infinite message.
4. If using network sockets as streams, a timeout should be set to stop
denial of service attacks.
5. If using `malloc()` support, some method of limiting memory use
should be employed. This can be done by defining custom
`pb_realloc()` function. Nanopb will properly detect and handle
failed memory allocations.

173
third_party/nanopb/docs/whats_new.md vendored Normal file
View file

@ -0,0 +1,173 @@
# Nanopb: New features in nanopb 0.4
## What's new in nanopb 0.4
Long in the making, nanopb 0.4 has seen some wide reaching improvements
in reaction to the development of the rest of the protobuf ecosystem.
This document showcases features that are not immediately visible, but
that you may want to take advantage of.
A lot of effort has been spent in retaining backwards and forwards
compatibility with previous nanopb versions. For a list of breaking
changes, see [migration document](migration.html)
### New field descriptor format
The basic design of nanopb has always been that the information about
messages is stored in a compact descriptor format, which is iterated in
runtime. Initially it was very tightly tied with encoder and decoder
logic.
In nanopb-0.3.0 the field iteration logic was separated to
`pb_common.c`. Already at that point it was clear that the old format
was getting too limited, but it wasn't extended at that time.
Now in 0.4, the descriptor format was completely decoupled from the
encoder and decoder logic, and redesigned to meet new demands.
Previously each field was stored as `pb_field_t` struct, which was
between 8 and 32 bytes in size, depending on compilation options and
platform. Now information about fields is stored as a variable length
sequence of `uint32_t` data words. There are 1, 2, 4 and 8 word formats,
with the 8 word format containing plenty of space for future
extensibility.
One benefit of the variable length format is that most messages now take
less storage space. Most fields use 2 words, while simple fields in
small messages require only 1 word. Benefit is larger if code previously
required `PB_FIELD_16BIT` or `PB_FIELD_32BIT` options. In
the `AllTypes` test case, 0.3 had data size of 1008 bytes in
8-bit configuration and 1408 bytes in 16-bit configuration. New format
in 0.4 takes 896 bytes for either of these.
In addition, the new decoupling has allowed moving most of the field
descriptor data into FLASH on Harvard architectures, such as AVR.
Previously nanopb was quite RAM-heavy on AVR, which cannot put normal
constants in flash like most other platforms do.
### Python packaging for generator
Nanopb generator is now available as a Python package, installable using
`pip` package manager. This will reduce the need for binary
packages, as if you have Python already installed you can just
`pip install nanopb` and have the generator available on path as
`nanopb_generator`.
The generator can also take advantage of the Python-based `protoc`
available in `grpcio-tools` Python package. If you also install that,
there is no longer a need to have binary `protoc` available.
### Generator now automatically calls protoc
Initially, nanopb generator was used in two steps: first calling
`protoc` to parse the `.proto` file into `.pb` binary
format, and then calling `nanopb_generator.py` to output the
`.pb.h` and `.pb.c` files.
Nanopb 0.2.3 added support for running as a `protoc` plugin, which
allowed single-step generation using `--nanopb_out` parameter. However,
the plugin mode has two complications: passing options to nanopb
generator itself becomes more difficult, and the generator does not know
the actual path of input files. The second limitation has been
particularly problematic for locating `.options` files.
Both of these older methods still work and will remain supported.
However, now `nanopb_generator` can also take `.proto` files
directly and it will transparently call `protoc` in the background.
### Callbacks bound by function name
Since its very beginnings, nanopb has supported field callbacks to allow
processing structures that are larger than what could fit in memory at
once. So far the callback functions have been stored in the message
structure in a `pb_callback_t` struct.
Storing pointers along with user data is somewhat risky from a security
point of view. In addition it has caused problems with `oneof` fields,
which reuse the same storage space for multiple submessages. Because
there is no separate area for each submessage, there is no space to
store the callback pointers either.
Nanopb-0.4.0 introduces callbacks that are referenced by the function
name instead of setting the pointers separately. This should work well
for most applications that have a single callback function for each
message type. For more complex needs, `pb_callback_t` will also remain
supported.
Function name callbacks also allow specifying custom data types for
inclusion in the message structure. For example, you could have
`MyObject*` pointer along with other message fields, and then process
that object in custom way in your callback.
This feature is demonstrated in
[tests/oneof_callback](https://github.com/nanopb/nanopb/tree/master/tests/oneof_callback) test case and
[examples/network_server](https://github.com/nanopb/nanopb/tree/master/examples/network_server) example.
### Message level callback for oneofs
As mentioned above, callbacks inside submessages inside oneofs have been
problematic to use. To make using `pb_callback_t`-style callbacks there
possible, a new generator option `submsg_callback` was added.
Setting this option to true will cause a new message level callback to
be added before the `which_field` of the oneof. This callback will be
called when the submessage tag number is known, but before the actual
message is decoded. The callback can either choose to set callback
pointers inside the submessage, or just completely decode the submessage
there and then. If any unread data remains after the callback returns,
normal submessage decoding will continue.
There is an example of this in [tests/oneof_callback](https://github.com/nanopb/nanopb/tree/master/tests/oneof_callback) test case.
### Binding message types to custom structures
It is often said that good C code is chock full of macros. Or maybe I
got it wrong. But since nanopb 0.2, the field descriptor generation has
heavily relied on macros. This allows it to automatically adapt to
differences in type alignment on different platforms, and to decouple
the Python generation logic from how the message descriptors are
implemented on the C side.
Now in 0.4.0, I've made the macros even more abstract. Time will tell
whether this was such a great idea that I think it is, but now the
complete list of fields in each message is available in `.pb.h` file.
This allows a kind of metaprogramming using [X-macros]()
One feature that this can be used for is binding the message descriptor
to a custom structure or C++ class type. You could have a bunch of other
fields in the structure and even the datatypes can be different to an
extent, and nanopb will automatically detect the size and position of
each field. The generated `.pb.c` files now just have calls of
`PB_BIND(msgname, structname, width)`. Adding a similar
call to your own code will bind the message to your own structure.
### UTF-8 validation
Protobuf format defines that strings should consist of valid UTF-8
codepoints. Previously nanopb has not enforced this, requiring extra
care in the user code. Now optional UTF-8 validation is available with
compilation option `PB_VALIDATE_UTF8`.
### Double to float conversion
Some platforms such as `AVR` do not support the `double`
datatype, instead making it an alias for `float`. This has resulted in
problems when trying to process message types containing `double` fields
generated on other machines. There has been an example on how to
manually perform the conversion between `double` and
`float`.
Now that example is integrated as an optional feature in nanopb core. By
defining `PB_CONVERT_DOUBLE_FLOAT`, the required conversion between 32-
and 64-bit floating point formats happens automatically on decoding and
encoding.
### Improved testing
Testing on embedded platforms has been integrated in the continuous
testing environment. Now all of the 80+ test cases are automatically run
on STM32 and AVR targets. Previously only a few specialized test cases
were manually tested on embedded systems.
Nanopb fuzzer has also been integrated in Google's [OSSFuzz](https://google.github.io/oss-fuzz/)
platform, giving a huge boost in the CPU power available for randomized
testing.

View file

@ -0,0 +1,18 @@
Nanopb example "simple" using CMake
=======================
This example is the same as the simple nanopb example but built using CMake.
Example usage
-------------
On Linux, create a build directory and then call cmake:
nanopb/examples/cmake_simple$ mkdir build
nanopb/examples/cmake_simple$ cd build/
nanopb/examples/cmake_simple/build$ cmake ..
nanopb/examples/cmake_simple/build$ make
After that, you can run it with the command: ./simple
On other platforms supported by CMake, refer to CMake instructions.

View file

@ -0,0 +1,11 @@
// A very simple protocol definition, consisting of only
// one message.
syntax = "proto2";
import "sub/unlucky.proto";
message SimpleMessage {
required int32 lucky_number = 1;
required UnluckyNumber unlucky = 2;
}

View file

@ -0,0 +1,5 @@
syntax = "proto2";
message UnluckyNumber {
required uint32 number = 1;
}

View file

@ -0,0 +1,73 @@
#include <stdio.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include "simple.pb.h"
int main()
{
/* This is the buffer where we will store our message. */
uint8_t buffer[128];
size_t message_length;
bool status;
/* Encode our message */
{
/* Allocate space on the stack to store the message data.
*
* Nanopb generates simple struct definitions for all the messages.
* - check out the contents of simple.pb.h!
* It is a good idea to always initialize your structures
* so that you do not have garbage data from RAM in there.
*/
SimpleMessage message = SimpleMessage_init_zero;
/* Create a stream that will write to our buffer. */
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Fill in the lucky number */
message.lucky_number = 13;
message.unlucky.number = 42;
/* Now we are ready to encode the message! */
status = pb_encode(&stream, SimpleMessage_fields, &message);
message_length = stream.bytes_written;
/* Then just check for any errors.. */
if (!status)
{
printf("Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
}
/* Now we could transmit the message over network, store it in a file or
* wrap it to a pigeon's leg.
*/
/* But because we are lazy, we will just decode it immediately. */
{
/* Allocate space for the decoded message. */
SimpleMessage message = SimpleMessage_init_zero;
/* Create a stream that reads from the buffer. */
pb_istream_t stream = pb_istream_from_buffer(buffer, message_length);
/* Now we are ready to decode the message. */
status = pb_decode(&stream, SimpleMessage_fields, &message);
/* Check for errors... */
if (!status)
{
printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
/* Print the data contained in the message. */
printf("Your lucky number was %d!\n", message.lucky_number);
printf("Your unlucky number was %u!\n", message.unlucky.number);
}
return 0;
}

View file

@ -0,0 +1,18 @@
Nanopb example "simple" using CMake
=======================
This example is the same as the simple nanopb example but built using CMake.
Example usage
-------------
On Linux, create a build directory and then call cmake:
nanopb/examples/cmake_simple$ mkdir build
nanopb/examples/cmake_simple$ cd build/
nanopb/examples/cmake_simple/build$ cmake ..
nanopb/examples/cmake_simple/build$ make
After that, you can run it with the command: ./simple
On other platforms supported by CMake, refer to CMake instructions.

View file

@ -0,0 +1,71 @@
#include <stdio.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include "simple.pb.h"
int main()
{
/* This is the buffer where we will store our message. */
uint8_t buffer[128];
size_t message_length;
bool status;
/* Encode our message */
{
/* Allocate space on the stack to store the message data.
*
* Nanopb generates simple struct definitions for all the messages.
* - check out the contents of simple.pb.h!
* It is a good idea to always initialize your structures
* so that you do not have garbage data from RAM in there.
*/
SimpleMessage message = SimpleMessage_init_zero;
/* Create a stream that will write to our buffer. */
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Fill in the lucky number */
message.lucky_number = 13;
/* Now we are ready to encode the message! */
status = pb_encode(&stream, SimpleMessage_fields, &message);
message_length = stream.bytes_written;
/* Then just check for any errors.. */
if (!status)
{
printf("Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
}
/* Now we could transmit the message over network, store it in a file or
* wrap it to a pigeon's leg.
*/
/* But because we are lazy, we will just decode it immediately. */
{
/* Allocate space for the decoded message. */
SimpleMessage message = SimpleMessage_init_zero;
/* Create a stream that reads from the buffer. */
pb_istream_t stream = pb_istream_from_buffer(buffer, message_length);
/* Now we are ready to decode the message. */
status = pb_decode(&stream, SimpleMessage_fields, &message);
/* Check for errors... */
if (!status)
{
printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
/* Print the data contained in the message. */
printf("Your lucky number was %d!\n", message.lucky_number);
}
return 0;
}

View file

@ -0,0 +1,9 @@
// A very simple protocol definition, consisting of only
// one message.
syntax = "proto2";
message SimpleMessage {
required int32 lucky_number = 1;
}

View file

@ -0,0 +1,17 @@
# Include the nanopb provided Makefile rules
include ../../extra/nanopb.mk
# Compiler flags to enable all warnings & debug info
CFLAGS = -ansi -Wall -Werror -g -O0
CFLAGS += -I$(NANOPB_DIR)
all: server client
.SUFFIXES:
clean:
rm -f server client fileproto.pb.c fileproto.pb.h
%: %.c common.c fileproto.pb.c
$(CC) $(CFLAGS) -o $@ $^ $(NANOPB_CORE)

View file

@ -0,0 +1,60 @@
Nanopb example "network_server"
===============================
This example demonstrates the use of nanopb to communicate over network
connections. It consists of a server that sends file listings, and of
a client that requests the file list from the server.
Example usage
-------------
user@host:~/nanopb/examples/network_server$ make # Build the example
protoc -ofileproto.pb fileproto.proto
python ../../generator/nanopb_generator.py fileproto.pb
Writing to fileproto.pb.h and fileproto.pb.c
cc -ansi -Wall -Werror -I .. -g -O0 -I../.. -o server server.c
../../pb_decode.c ../../pb_encode.c fileproto.pb.c common.c
cc -ansi -Wall -Werror -I .. -g -O0 -I../.. -o client client.c
../../pb_decode.c ../../pb_encode.c fileproto.pb.c common.c
user@host:~/nanopb/examples/network_server$ ./server & # Start the server on background
[1] 24462
petteri@oddish:~/nanopb/examples/network_server$ ./client /bin # Request the server to list /bin
Got connection.
Listing directory: /bin
1327119 bzdiff
1327126 bzless
1327147 ps
1327178 ntfsmove
1327271 mv
1327187 mount
1327259 false
1327266 tempfile
1327285 zfgrep
1327165 gzexe
1327204 nc.openbsd
1327260 uname
Details of implementation
-------------------------
fileproto.proto contains the portable Google Protocol Buffers protocol definition.
It could be used as-is to implement a server or a client in any other language, for
example Python or Java.
fileproto.options contains the nanopb-specific options for the protocol file. This
sets the amount of space allocated for file names when decoding messages.
common.c/h contains functions that allow nanopb to read and write directly from
network socket. This way there is no need to allocate a separate buffer to store
the message.
server.c contains the code to open a listening socket, to respond to clients and
to list directory contents.
client.c contains the code to connect to a server, to send a request and to print
the response message.
The code is implemented using the POSIX socket api, but it should be easy enough
to port into any other socket api, such as lwip.

View file

@ -0,0 +1,138 @@
/* This is a simple TCP client that connects to port 1234 and prints a list
* of files in a given directory.
*
* It directly deserializes and serializes messages from network, minimizing
* memory use.
*
* For flexibility, this example is implemented using posix api.
* In a real embedded system you would typically use some other kind of
* a communication and filesystem layer.
*/
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include "fileproto.pb.h"
#include "common.h"
/* This callback function will be called once for each filename received
* from the server. The filenames will be printed out immediately, so that
* no memory has to be allocated for them.
*/
bool ListFilesResponse_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
{
PB_UNUSED(ostream);
if (istream != NULL && field->tag == ListFilesResponse_file_tag)
{
FileInfo fileinfo = {};
if (!pb_decode(istream, FileInfo_fields, &fileinfo))
return false;
printf("%-10lld %s\n", (long long)fileinfo.inode, fileinfo.name);
}
return true;
}
/* This function sends a request to socket 'fd' to list the files in
* directory given in 'path'. The results received from server will
* be printed to stdout.
*/
bool listdir(int fd, char *path)
{
/* Construct and send the request to server */
{
ListFilesRequest request = {};
pb_ostream_t output = pb_ostream_from_socket(fd);
/* In our protocol, path is optional. If it is not given,
* the server will list the root directory. */
if (path == NULL)
{
request.has_path = false;
}
else
{
request.has_path = true;
if (strlen(path) + 1 > sizeof(request.path))
{
fprintf(stderr, "Too long path.\n");
return false;
}
strcpy(request.path, path);
}
/* Encode the request. It is written to the socket immediately
* through our custom stream. */
if (!pb_encode_delimited(&output, ListFilesRequest_fields, &request))
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&output));
return false;
}
}
/* Read back the response from server */
{
ListFilesResponse response = {};
pb_istream_t input = pb_istream_from_socket(fd);
if (!pb_decode_delimited(&input, ListFilesResponse_fields, &response))
{
fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&input));
return false;
}
/* If the message from server decodes properly, but directory was
* not found on server side, we get path_error == true. */
if (response.path_error)
{
fprintf(stderr, "Server reported error.\n");
return false;
}
}
return true;
}
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
char *path = NULL;
if (argc > 1)
path = argv[1];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
/* Connect to server running on localhost:1234 */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
servaddr.sin_port = htons(1234);
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
{
perror("connect");
return 1;
}
/* Send the directory listing request */
if (!listdir(sockfd, path))
return 2;
/* Close connection */
close(sockfd);
return 0;
}

View file

@ -0,0 +1,43 @@
/* Simple binding of nanopb streams to TCP sockets.
*/
#include <sys/socket.h>
#include <sys/types.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include "common.h"
static bool write_callback(pb_ostream_t *stream, const uint8_t *buf, size_t count)
{
int fd = (intptr_t)stream->state;
return send(fd, buf, count, 0) == count;
}
static bool read_callback(pb_istream_t *stream, uint8_t *buf, size_t count)
{
int fd = (intptr_t)stream->state;
int result;
if (count == 0)
return true;
result = recv(fd, buf, count, MSG_WAITALL);
if (result == 0)
stream->bytes_left = 0; /* EOF */
return result == count;
}
pb_ostream_t pb_ostream_from_socket(int fd)
{
pb_ostream_t stream = {&write_callback, (void*)(intptr_t)fd, SIZE_MAX, 0};
return stream;
}
pb_istream_t pb_istream_from_socket(int fd)
{
pb_istream_t stream = {&read_callback, (void*)(intptr_t)fd, SIZE_MAX};
return stream;
}

View file

@ -0,0 +1,9 @@
#ifndef _PB_EXAMPLE_COMMON_H_
#define _PB_EXAMPLE_COMMON_H_
#include <pb.h>
pb_ostream_t pb_ostream_from_socket(int fd);
pb_istream_t pb_istream_from_socket(int fd);
#endif

View file

@ -0,0 +1,16 @@
# This file defines the nanopb-specific options for the messages defined
# in fileproto.proto.
#
# If you come from high-level programming background, the hardcoded
# maximum lengths may disgust you. However, if your microcontroller only
# has a few kB of ram to begin with, setting reasonable limits for
# filenames is ok.
#
# On the other hand, using the callback interface, it is not necessary
# to set a limit on the number of files in the response.
* include:"sys/types.h"
* include:"dirent.h"
ListFilesResponse.file type:FT_CALLBACK, callback_datatype:"DIR*"
ListFilesRequest.path max_size:128
FileInfo.name max_size:128

View file

@ -0,0 +1,20 @@
// This defines protocol for a simple server that lists files.
//
// See also the nanopb-specific options in fileproto.options.
syntax = "proto2";
message ListFilesRequest {
optional string path = 1 [default = "/"];
}
message FileInfo {
required uint64 inode = 1;
required string name = 2;
}
message ListFilesResponse {
optional bool path_error = 1 [default = false];
repeated FileInfo file = 2;
}

View file

@ -0,0 +1,164 @@
/* This is a simple TCP server that listens on port 1234 and provides lists
* of files to clients, using a protocol defined in file_server.proto.
*
* It directly deserializes and serializes messages from network, minimizing
* memory use.
*
* For flexibility, this example is implemented using posix api.
* In a real embedded system you would typically use some other kind of
* a communication and filesystem layer.
*/
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include "fileproto.pb.h"
#include "common.h"
/* This callback function will be called during the encoding.
* It will write out any number of FileInfo entries, without consuming unnecessary memory.
* This is accomplished by fetching the filenames one at a time and encoding them
* immediately.
*/
bool ListFilesResponse_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
{
PB_UNUSED(istream);
if (ostream != NULL && field->tag == ListFilesResponse_file_tag)
{
DIR *dir = *(DIR**)field->pData;
struct dirent *file;
FileInfo fileinfo = {};
while ((file = readdir(dir)) != NULL)
{
fileinfo.inode = file->d_ino;
strncpy(fileinfo.name, file->d_name, sizeof(fileinfo.name));
fileinfo.name[sizeof(fileinfo.name) - 1] = '\0';
/* This encodes the header for the field, based on the constant info
* from pb_field_t. */
if (!pb_encode_tag_for_field(ostream, field))
return false;
/* This encodes the data for the field, based on our FileInfo structure. */
if (!pb_encode_submessage(ostream, FileInfo_fields, &fileinfo))
return false;
}
/* Because the main program uses pb_encode_delimited(), this callback will be
* called twice. Rewind the directory for the next call. */
rewinddir(dir);
}
return true;
}
/* Handle one arriving client connection.
* Clients are expected to send a ListFilesRequest, terminated by a '0'.
* Server will respond with a ListFilesResponse message.
*/
void handle_connection(int connfd)
{
DIR *directory = NULL;
/* Decode the message from the client and open the requested directory. */
{
ListFilesRequest request = {};
pb_istream_t input = pb_istream_from_socket(connfd);
if (!pb_decode_delimited(&input, ListFilesRequest_fields, &request))
{
printf("Decode failed: %s\n", PB_GET_ERROR(&input));
return;
}
directory = opendir(request.path);
printf("Listing directory: %s\n", request.path);
}
/* List the files in the directory and transmit the response to client */
{
ListFilesResponse response = {};
pb_ostream_t output = pb_ostream_from_socket(connfd);
if (directory == NULL)
{
perror("opendir");
/* Directory was not found, transmit error status */
response.has_path_error = true;
response.path_error = true;
}
else
{
/* Directory was found, transmit filenames */
response.has_path_error = false;
response.file = directory;
}
if (!pb_encode_delimited(&output, ListFilesResponse_fields, &response))
{
printf("Encoding failed: %s\n", PB_GET_ERROR(&output));
}
}
if (directory != NULL)
closedir(directory);
}
int main(int argc, char **argv)
{
int listenfd, connfd;
struct sockaddr_in servaddr;
int reuse = 1;
/* Listen on localhost:1234 for TCP connections */
listenfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
servaddr.sin_port = htons(1234);
if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0)
{
perror("bind");
return 1;
}
if (listen(listenfd, 5) != 0)
{
perror("listen");
return 1;
}
for(;;)
{
/* Wait for a client */
connfd = accept(listenfd, NULL, NULL);
if (connfd < 0)
{
perror("accept");
return 1;
}
printf("Got connection.\n");
handle_connection(connfd);
printf("Closing connection.\n");
close(connfd);
}
return 0;
}

View file

@ -0,0 +1,5 @@
.pio/
.idea/
cmake-build-*/
/CMakeLists.txt
CMakeListsPrivate.txt

View file

@ -0,0 +1,48 @@
;
; You can setup `custom_nanopb_protos` `nanopb_options` vars to generate code from proto files
;
; Generator will use next folders:
;
; `$BUILD_DIR/nanopb/generated-src` - `*.pb.h` and `*.pb.c` files
; `$BUILD_DIR/nanopb/md5` - MD5 files to track changes in source .proto/.options
;
; Compiled `.pb.o` files will be located under `$BUILD_DIR/nanopb/generated-build`
;
; Example:
[env:pio_with_options]
platform = native
lib_deps = Nanopb
src_filter =
+<pio_with_options.c>
; All path are relative to the `$PROJECT_DIR`
custom_nanopb_protos =
+<proto/pio_with_options.proto>
custom_nanopb_options =
--error-on-unmatched
[env:pio_without_options]
platform = native
lib_deps = Nanopb
src_filter =
+<pio_without_options.c>
; All path are relative to the `$PROJECT_DIR`
custom_nanopb_protos =
+<proto/pio_without_options.proto>
[env:pio_esp32_idf]
platform = espressif32
board = firebeetle32
framework = espidf
lib_deps = Nanopb
; Warning: the 'src_filter' option cannot be used with ESP-IDF. Select source files to build in the project CMakeLists.txt file.
; So, we specified source files in src/CMakeLists.txt
custom_nanopb_protos =
+<proto/pio_without_options.proto>

View file

@ -0,0 +1 @@
TestMessageWithOptions.str max_size:16

View file

@ -0,0 +1,5 @@
syntax = "proto3";
message TestMessageWithOptions {
string str = 1;
}

View file

@ -0,0 +1,5 @@
syntax = "proto3";
message TestMessageWithoutOptions {
int32 number = 1;
}

View file

@ -0,0 +1,34 @@
#include "pb_encode.h"
#include "pb_decode.h"
#include "test.h"
#include "pio_without_options.pb.h"
void app_main() {
int status = 0;
uint8_t buffer[256];
pb_ostream_t ostream;
pb_istream_t istream;
size_t written;
TestMessageWithoutOptions original = TestMessageWithoutOptions_init_zero;
original.number = 45;
ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
TEST(pb_encode(&ostream, &TestMessageWithoutOptions_msg, &original));
written = ostream.bytes_written;
istream = pb_istream_from_buffer(buffer, written);
TestMessageWithoutOptions decoded = TestMessageWithoutOptions_init_zero;
TEST(pb_decode(&istream, &TestMessageWithoutOptions_msg, &decoded));
TEST(decoded.number == 45);
return status;
}

View file

@ -0,0 +1,35 @@
#include "pb_encode.h"
#include "pb_decode.h"
#include "test.h"
#include "pio_with_options.pb.h"
int main(int argc, char *argv[]) {
int status = 0;
uint8_t buffer[256];
pb_ostream_t ostream;
pb_istream_t istream;
size_t written;
TestMessageWithOptions original = TestMessageWithOptions_init_zero;
strcpy(original.str,"Hello");
ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
TEST(pb_encode(&ostream, &TestMessageWithOptions_msg, &original));
written = ostream.bytes_written;
istream = pb_istream_from_buffer(buffer, written);
TestMessageWithOptions decoded = TestMessageWithOptions_init_zero;
TEST(pb_decode(&istream, &TestMessageWithOptions_msg, &decoded));
TEST(strcmp(decoded.str,"Hello") == 0);
return status;
}

View file

@ -0,0 +1,35 @@
#include "pb_encode.h"
#include "pb_decode.h"
#include "test.h"
#include "pio_without_options.pb.h"
int main(int argc, char *argv[]) {
int status = 0;
uint8_t buffer[256];
pb_ostream_t ostream;
pb_istream_t istream;
size_t written;
TestMessageWithoutOptions original = TestMessageWithoutOptions_init_zero;
original.number = 45;
ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
TEST(pb_encode(&ostream, &TestMessageWithoutOptions_msg, &original));
written = ostream.bytes_written;
istream = pb_istream_from_buffer(buffer, written);
TestMessageWithoutOptions decoded = TestMessageWithoutOptions_init_zero;
TEST(pb_decode(&istream, &TestMessageWithoutOptions_msg, &decoded));
TEST(decoded.number == 45);
return status;
}

View file

@ -0,0 +1,9 @@
#include <stdio.h>
#define TEST(x) \
if (!(x)) { \
fprintf(stderr, "\033[31;1mFAILED:\033[22;39m %s:%d %s\n", __FILE__, __LINE__, #x); \
status = 1; \
} else { \
printf("\033[32;1mOK:\033[22;39m %s\n", #x); \
}

View file

@ -0,0 +1,22 @@
# Include the nanopb provided Makefile rules
include ../../extra/nanopb.mk
# Compiler flags to enable all warnings & debug info
CFLAGS = -Wall -Werror -g -O0
CFLAGS += "-I$(NANOPB_DIR)"
# C source code files that are required
CSRC = simple.c # The main program
CSRC += simple.pb.c # The compiled protocol definition
CSRC += $(NANOPB_DIR)/pb_encode.c # The nanopb encoder
CSRC += $(NANOPB_DIR)/pb_decode.c # The nanopb decoder
CSRC += $(NANOPB_DIR)/pb_common.c # The nanopb common parts
# Build rule for the main program
simple: $(CSRC)
$(CC) $(CFLAGS) -osimple $(CSRC)
# Build rule for the protocol
simple.pb.c: simple.proto
$(PROTOC) $(PROTOC_OPTS) --nanopb_out=. simple.proto

View file

@ -0,0 +1,29 @@
Nanopb example "simple"
=======================
This example demonstrates the very basic use of nanopb. It encodes and
decodes a simple message.
The code uses four different API functions:
* pb_ostream_from_buffer() to declare the output buffer that is to be used
* pb_encode() to encode a message
* pb_istream_from_buffer() to declare the input buffer that is to be used
* pb_decode() to decode a message
Example usage
-------------
On Linux, simply type "make" to build the example. After that, you can
run it with the command: ./simple
On other platforms, you first have to compile the protocol definition using
the following command::
../../generator-bin/protoc --nanopb_out=. simple.proto
After that, add the following five files to your project and compile:
simple.c simple.pb.c pb_encode.c pb_decode.c pb_common.c

View file

@ -0,0 +1,71 @@
#include <stdio.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include "simple.pb.h"
int main()
{
/* This is the buffer where we will store our message. */
uint8_t buffer[128];
size_t message_length;
bool status;
/* Encode our message */
{
/* Allocate space on the stack to store the message data.
*
* Nanopb generates simple struct definitions for all the messages.
* - check out the contents of simple.pb.h!
* It is a good idea to always initialize your structures
* so that you do not have garbage data from RAM in there.
*/
SimpleMessage message = SimpleMessage_init_zero;
/* Create a stream that will write to our buffer. */
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/* Fill in the lucky number */
message.lucky_number = 13;
/* Now we are ready to encode the message! */
status = pb_encode(&stream, SimpleMessage_fields, &message);
message_length = stream.bytes_written;
/* Then just check for any errors.. */
if (!status)
{
printf("Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
}
/* Now we could transmit the message over network, store it in a file or
* wrap it to a pigeon's leg.
*/
/* But because we are lazy, we will just decode it immediately. */
{
/* Allocate space for the decoded message. */
SimpleMessage message = SimpleMessage_init_zero;
/* Create a stream that reads from the buffer. */
pb_istream_t stream = pb_istream_from_buffer(buffer, message_length);
/* Now we are ready to decode the message. */
status = pb_decode(&stream, SimpleMessage_fields, &message);
/* Check for errors... */
if (!status)
{
printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
/* Print the data contained in the message. */
printf("Your lucky number was %d!\n", (int)message.lucky_number);
}
return 0;
}

View file

@ -0,0 +1,9 @@
// A very simple protocol definition, consisting of only
// one message.
syntax = "proto2";
message SimpleMessage {
required int32 lucky_number = 1;
}

View file

@ -0,0 +1,20 @@
# Include the nanopb provided Makefile rules
include ../../extra/nanopb.mk
# Compiler flags to enable all warnings & debug info
CFLAGS = -ansi -Wall -Werror -g -O0
CFLAGS += -I$(NANOPB_DIR)
all: encode decode
./encode 1 | ./decode
./encode 2 | ./decode
./encode 3 | ./decode
.SUFFIXES:
clean:
rm -f encode unionproto.pb.h unionproto.pb.c
%: %.c unionproto.pb.c
$(CC) $(CFLAGS) -o $@ $^ $(NANOPB_CORE)

View file

@ -0,0 +1,55 @@
Nanopb example "using_union_messages"
=====================================
Union messages is a common technique in Google Protocol Buffers used to
represent a group of messages, only one of which is passed at a time.
It is described in Google's documentation:
https://developers.google.com/protocol-buffers/docs/techniques#union
This directory contains an example on how to encode and decode union messages
with minimal memory usage. Usually, nanopb would allocate space to store
all of the possible messages at the same time, even though at most one of
them will be used at a time.
By using some of the lower level nanopb APIs, we can manually generate the
top level message, so that we only need to allocate the one submessage that
we actually want. Similarly when decoding, we can manually read the tag of
the top level message, and only then allocate the memory for the submessage
after we already know its type.
NOTE: There is a newer protobuf feature called `oneof` that is also supported
by nanopb. It might be a better option for new code.
Example usage
-------------
Type `make` to run the example. It will build it and run commands like
following:
./encode 1 | ./decode
Got MsgType1: 42
./encode 2 | ./decode
Got MsgType2: true
./encode 3 | ./decode
Got MsgType3: 3 1415
This simply demonstrates that the "decode" program has correctly identified
the type of the received message, and managed to decode it.
Details of implementation
-------------------------
unionproto.proto contains the protocol used in the example. It consists of
three messages: MsgType1, MsgType2 and MsgType3, which are collected together
into UnionMessage.
encode.c takes one command line argument, which should be a number 1-3. It
then fills in and encodes the corresponding message, and writes it to stdout.
decode.c reads a UnionMessage from stdin. Then it calls the function
decode_unionmessage_type() to determine the type of the message. After that,
the corresponding message is decoded and the contents of it printed to the
screen.

View file

@ -0,0 +1,95 @@
/* This program reads a message from stdin, detects its type and decodes it.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pb_decode.h>
#include <pb_common.h>
#include "unionproto.pb.h"
/* This function reads manually the first tag from the stream and finds the
* corresponding message type. It doesn't yet decode the actual message.
*
* Returns a pointer to the MsgType_fields array, as an identifier for the
* message type. Returns null if the tag is of unknown type or an error occurs.
*/
const pb_msgdesc_t* decode_unionmessage_type(pb_istream_t *stream)
{
pb_wire_type_t wire_type;
uint32_t tag;
bool eof;
while (pb_decode_tag(stream, &wire_type, &tag, &eof))
{
if (wire_type == PB_WT_STRING)
{
pb_field_iter_t iter;
if (pb_field_iter_begin(&iter, UnionMessage_fields, NULL) &&
pb_field_iter_find(&iter, tag))
{
/* Found our field. */
return iter.submsg_desc;
}
}
/* Wasn't our field.. */
pb_skip_field(stream, wire_type);
}
return NULL;
}
bool decode_unionmessage_contents(pb_istream_t *stream, const pb_msgdesc_t *messagetype, void *dest_struct)
{
pb_istream_t substream;
bool status;
if (!pb_make_string_substream(stream, &substream))
return false;
status = pb_decode(&substream, messagetype, dest_struct);
pb_close_string_substream(stream, &substream);
return status;
}
int main()
{
/* Read the data into buffer */
uint8_t buffer[512];
size_t count = fread(buffer, 1, sizeof(buffer), stdin);
pb_istream_t stream = pb_istream_from_buffer(buffer, count);
const pb_msgdesc_t *type = decode_unionmessage_type(&stream);
bool status = false;
if (type == MsgType1_fields)
{
MsgType1 msg = {};
status = decode_unionmessage_contents(&stream, MsgType1_fields, &msg);
printf("Got MsgType1: %d\n", msg.value);
}
else if (type == MsgType2_fields)
{
MsgType2 msg = {};
status = decode_unionmessage_contents(&stream, MsgType2_fields, &msg);
printf("Got MsgType2: %s\n", msg.value ? "true" : "false");
}
else if (type == MsgType3_fields)
{
MsgType3 msg = {};
status = decode_unionmessage_contents(&stream, MsgType3_fields, &msg);
printf("Got MsgType3: %d %d\n", msg.value1, msg.value2);
}
if (!status)
{
printf("Decode failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
return 0;
}

View file

@ -0,0 +1,90 @@
/* This program takes a command line argument and encodes a message in
* one of MsgType1, MsgType2 or MsgType3.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pb_encode.h>
#include <pb_common.h>
#include "unionproto.pb.h"
/* This function is the core of the union encoding process. It handles
* the top-level pb_field_t array manually, in order to encode a correct
* field tag before the message. The pointer to MsgType_fields array is
* used as an unique identifier for the message type.
*/
bool encode_unionmessage(pb_ostream_t *stream, const pb_msgdesc_t *messagetype, void *message)
{
pb_field_iter_t iter;
if (!pb_field_iter_begin(&iter, UnionMessage_fields, message))
return false;
do
{
if (iter.submsg_desc == messagetype)
{
/* This is our field, encode the message using it. */
if (!pb_encode_tag_for_field(stream, &iter))
return false;
return pb_encode_submessage(stream, messagetype, message);
}
} while (pb_field_iter_next(&iter));
/* Didn't find the field for messagetype */
return false;
}
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s (1|2|3)\n", argv[0]);
return 1;
}
uint8_t buffer[512];
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
bool status = false;
int msgtype = atoi(argv[1]);
if (msgtype == 1)
{
/* Send message of type 1 */
MsgType1 msg = {42};
status = encode_unionmessage(&stream, MsgType1_fields, &msg);
}
else if (msgtype == 2)
{
/* Send message of type 2 */
MsgType2 msg = {true};
status = encode_unionmessage(&stream, MsgType2_fields, &msg);
}
else if (msgtype == 3)
{
/* Send message of type 3 */
MsgType3 msg = {3, 1415};
status = encode_unionmessage(&stream, MsgType3_fields, &msg);
}
else
{
fprintf(stderr, "Unknown message type: %d\n", msgtype);
return 2;
}
if (!status)
{
fprintf(stderr, "Encoding failed!\n");
return 3;
}
else
{
fwrite(buffer, 1, stream.bytes_written, stdout);
return 0; /* Success */
}
}

View file

@ -0,0 +1,32 @@
// This is an example of how to handle 'union' style messages
// with nanopb, without allocating memory for all the message types.
//
// There is no official type in Protocol Buffers for describing unions,
// but they are commonly implemented by filling out exactly one of
// several optional fields.
syntax = "proto2";
message MsgType1
{
required int32 value = 1;
}
message MsgType2
{
required bool value = 1;
}
message MsgType3
{
required int32 value1 = 1;
required int32 value2 = 2;
}
message UnionMessage
{
optional MsgType1 msg1 = 1;
optional MsgType2 msg2 = 2;
optional MsgType3 msg3 = 3;
}

View file

@ -0,0 +1,11 @@
set(PACKAGE_VERSION "@nanopb_VERSION@")
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()

View file

@ -0,0 +1 @@
include(${CMAKE_CURRENT_LIST_DIR}/nanopb-targets.cmake)

40
third_party/nanopb/extra/nanopb.mk vendored Normal file
View file

@ -0,0 +1,40 @@
# This is an include file for Makefiles. It provides rules for building
# .pb.c and .pb.h files out of .proto, as well the path to nanopb core.
# Path to the nanopb root directory
NANOPB_DIR := $(patsubst %/,%,$(dir $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))))
# Files for the nanopb core
NANOPB_CORE = $(NANOPB_DIR)/pb_encode.c $(NANOPB_DIR)/pb_decode.c $(NANOPB_DIR)/pb_common.c
# Check if we are running on Windows
ifdef windir
WINDOWS = 1
endif
ifdef WINDIR
WINDOWS = 1
endif
# Check whether to use binary version of nanopb_generator or the
# system-supplied python interpreter.
ifneq "$(wildcard $(NANOPB_DIR)/generator-bin)" ""
# Binary package
PROTOC = $(NANOPB_DIR)/generator-bin/protoc
PROTOC_OPTS =
else
# Source only or git checkout
PROTOC_OPTS =
ifdef WINDOWS
PROTOC = python $(NANOPB_DIR)/generator/protoc
else
PROTOC = $(NANOPB_DIR)/generator/protoc
endif
endif
# Rule for building .pb.c and .pb.h
%.pb.c %.pb.h: %.proto %.options
$(PROTOC) $(PROTOC_OPTS) --nanopb_out=. $<
%.pb.c %.pb.h: %.proto
$(PROTOC) $(PROTOC_OPTS) --nanopb_out=. $<

120
third_party/nanopb/extra/pb_syshdr.h vendored Normal file
View file

@ -0,0 +1,120 @@
/* This is an example of a header file for platforms/compilers that do
* not come with stdint.h/stddef.h/stdbool.h/string.h. To use it, define
* PB_SYSTEM_HEADER as "pb_syshdr.h", including the quotes, and add the
* extra folder to your include path.
*
* It is very likely that you will need to customize this file to suit
* your platform. For any compiler that supports C99, this file should
* not be necessary.
*/
#ifndef _PB_SYSHDR_H_
#define _PB_SYSHDR_H_
/* stdint.h subset */
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
/* You will need to modify these to match the word size of your platform. */
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
/* These are ok for most platforms, unless uint8_t is actually not available,
* in which case you should give the smallest available type. */
typedef int8_t int_least8_t;
typedef uint8_t uint_least8_t;
typedef uint8_t uint_fast8_t;
typedef int16_t int_least16_t;
typedef uint16_t uint_least16_t;
#endif
/* stddef.h subset */
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#else
typedef uint32_t size_t;
#define offsetof(st, m) ((size_t)(&((st *)0)->m))
#ifndef NULL
#define NULL 0
#endif
#endif
/* stdbool.h subset */
#ifdef HAVE_STDBOOL_H
#include <stdbool.h>
#else
#ifndef __cplusplus
typedef int bool;
#define false 0
#define true 1
#endif
#endif
/* stdlib.h subset */
#ifdef PB_ENABLE_MALLOC
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
void *realloc(void *ptr, size_t size);
void free(void *ptr);
#endif
#endif
/* string.h subset */
#ifdef HAVE_STRING_H
#include <string.h>
#else
/* Implementations are from the Public Domain C Library (PDCLib). */
static size_t strlen( const char * s )
{
size_t rc = 0;
while ( s[rc] )
{
++rc;
}
return rc;
}
static void * memcpy( void *s1, const void *s2, size_t n )
{
char * dest = (char *) s1;
const char * src = (const char *) s2;
while ( n-- )
{
*dest++ = *src++;
}
return s1;
}
static void * memset( void * s, int c, size_t n )
{
unsigned char * p = (unsigned char *) s;
while ( n-- )
{
*p++ = (unsigned char) c;
}
return s;
}
#endif
/* limits.h subset */
#ifdef HAVE_LIMITS_H
#include <limits.h>
#else
#define CHAR_BIT 8
#endif
#endif

View file

@ -0,0 +1,20 @@
#!/bin/bash
set -ex
rm -rf build
mkdir build
mkdir -p dist
(cd "$(git rev-parse --show-toplevel)"; git archive HEAD) > build/tmp.tar
cd build
ln -s ../dist .
mkdir nanopb
tar xf tmp.tar README.md generator
mv generator nanopb/
touch nanopb/__init__.py nanopb/generator/__init__.py
make -C nanopb/generator/proto
cp ../pyproject.toml .
sed -i -e 's/\(version =.*\)-dev.*/\1-dev'$(git rev-list HEAD --count)'"/' pyproject.toml
poetry build

View file

@ -0,0 +1,31 @@
[tool.poetry]
name = "nanopb"
version = "0.4.6"
description = "Nanopb is a small code-size Protocol Buffers implementation in ansi C. It is especially suitable for use in microcontrollers, but fits any memory restricted system."
authors = ["Petteri Aimonen <jpa@npb.mail.kapsi.fi>"]
license = "Zlib"
repository = "https://github.com/nanopb/nanopb/"
readme = "README.md"
homepage = "https://jpa.kapsi.fi/nanopb/"
documentation = "https://jpa.kapsi.fi/nanopb/docs/index.html"
keywords = ["protobuf", "protoc"]
classifiers = ["Topic :: Software Development :: Build Tools"]
include = ["nanopb/**/*", "nanopb/__init__.py"]
[tool.poetry.scripts]
nanopb_generator = "nanopb.generator.nanopb_generator:main_cli"
protoc-gen-nanopb = "nanopb.generator.nanopb_generator:main_plugin"
[tool.poetry.dependencies]
python = ">=2.7"
protobuf = ">=3.19"
grpcio-tools = ">=1.46.0"
[tool.poetry.dev-dependencies]
[tool.poetry.extras]
grpcio-tools = ["grpcio-tools"]
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

2384
third_party/nanopb/generator/nanopb_generator.py vendored Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,13 @@
#!/usr/bin/env python2
# This file is a wrapper around nanopb_generator.py in case you want to run
# it with Python 2 instead of default Python 3. This only exists for backwards
# compatibility, do not use for new projects.
from nanopb_generator import *
if __name__ == '__main__':
# Check if we are running as a plugin under protoc
if 'protoc-gen-' in sys.argv[0] or '--protoc-plugin' in sys.argv:
main_plugin()
else:
main_cli()

View file

@ -0,0 +1,154 @@
import os
import hashlib
import pathlib
from platformio import fs
Import("env")
try:
import protobuf
except ImportError:
env.Execute(
env.VerboseAction(
# We need to speicify protobuf version. In other case got next (on Ubuntu 20.04):
# Requirement already satisfied: protobuf in /usr/lib/python3/dist-packages (3.6.1)
'$PYTHONEXE -m pip install "protobuf>=3.19.1"',
"Installing Protocol Buffers dependencies",
)
)
try:
import grpc_tools.protoc
except ImportError:
env.Execute(
env.VerboseAction(
'$PYTHONEXE -m pip install "grpcio-tools>=1.43.0"',
"Installing GRPC dependencies",
)
)
nanopb_root = os.path.join(os.getcwd(), '..')
project_dir = env.subst("$PROJECT_DIR")
build_dir = env.subst("$BUILD_DIR")
generated_src_dir = os.path.join(build_dir, 'nanopb', 'generated-src')
generated_build_dir = os.path.join(build_dir, 'nanopb', 'generated-build')
md5_dir = os.path.join(build_dir, 'nanopb', 'md5')
nanopb_protos = env.GetProjectOption("custom_nanopb_protos", "")
nanopb_plugin_options = env.GetProjectOption("custom_nanopb_options", "")
if not nanopb_protos:
print("[nanopb] No generation needed.")
else:
if isinstance(nanopb_plugin_options, (list, tuple)):
nanopb_plugin_options = " ".join(nanopb_plugin_options)
nanopb_plugin_options = nanopb_plugin_options.split()
protos_files = fs.match_src_files(project_dir, nanopb_protos)
if not len(protos_files):
print("[nanopb] ERROR: No files matched pattern:")
print(f"custom_nanopb_protos: {nanopb_protos}")
exit(1)
protoc_generator = os.path.join(nanopb_root, 'generator', 'protoc')
nanopb_options = ""
nanopb_options += f" --nanopb_out={generated_src_dir}"
for opt in nanopb_plugin_options:
nanopb_options += (" --nanopb_opt=" + opt)
try:
os.makedirs(generated_src_dir)
except FileExistsError:
pass
try:
os.makedirs(md5_dir)
except FileExistsError:
pass
# Collect include dirs based on
proto_include_dirs = set()
for proto_file in protos_files:
proto_file_abs = os.path.join(project_dir, proto_file)
proto_dir = os.path.dirname(proto_file_abs)
proto_include_dirs.add(proto_dir)
for proto_include_dir in proto_include_dirs:
nanopb_options += (" --proto_path=" + proto_include_dir)
nanopb_options += (" --nanopb_opt=-I" + proto_include_dir)
for proto_file in protos_files:
proto_file_abs = os.path.join(project_dir, proto_file)
proto_file_path_abs = os.path.dirname(proto_file_abs)
proto_file_basename = os.path.basename(proto_file_abs)
proto_file_without_ext = os.path.splitext(proto_file_basename)[0]
proto_file_md5_abs = os.path.join(md5_dir, proto_file_basename + '.md5')
proto_file_current_md5 = hashlib.md5(pathlib.Path(proto_file_abs).read_bytes()).hexdigest()
options_file = proto_file_without_ext + ".options"
options_file_abs = os.path.join(proto_file_path_abs, options_file)
options_file_md5_abs = None
options_file_current_md5 = None
if pathlib.Path(options_file_abs).exists():
options_file_md5_abs = os.path.join(md5_dir, options_file + '.md5')
options_file_current_md5 = hashlib.md5(pathlib.Path(options_file_abs).read_bytes()).hexdigest()
else:
options_file = None
header_file = proto_file_without_ext + ".pb.h"
source_file = proto_file_without_ext + ".pb.c"
header_file_abs = os.path.join(generated_src_dir, source_file)
source_file_abs = os.path.join(generated_src_dir, header_file)
need_generate = False
# Check proto file md5
try:
last_md5 = pathlib.Path(proto_file_md5_abs).read_text()
if last_md5 != proto_file_current_md5:
need_generate = True
except FileNotFoundError:
need_generate = True
if options_file:
# Check options file md5
try:
last_md5 = pathlib.Path(options_file_md5_abs).read_text()
if last_md5 != options_file_current_md5:
need_generate = True
except FileNotFoundError:
need_generate = True
options_info = f"{options_file}" if options_file else "no options"
if not need_generate:
print(f"[nanopb] Skipping '{proto_file}' ({options_info})")
else:
print(f"[nanopb] Processing '{proto_file}' ({options_info})")
cmd = protoc_generator + " " + nanopb_options + " " + proto_file_basename
result = env.Execute(cmd)
if result != 0:
print(f"[nanopb] ERROR: ({result}) processing cmd: '{cmd}'")
exit(1)
pathlib.Path(proto_file_md5_abs).write_text(proto_file_current_md5)
if options_file:
pathlib.Path(options_file_md5_abs).write_text(options_file_current_md5)
#
# Add generated includes and sources to build environment
#
env.Append(CPPPATH=[generated_src_dir])
# Fix for ESP32 ESP-IDF https://github.com/nanopb/nanopb/issues/734#issuecomment-1001544447
global_env = DefaultEnvironment()
already_called_env_name = "_PROTOBUF_GENERATOR_ALREADY_CALLED_" + env['PIOENV'].replace("-", "_")
if not global_env.get(already_called_env_name, False):
env.BuildSources(generated_build_dir, generated_src_dir)
global_env[already_called_env_name] = True

View file

@ -0,0 +1,10 @@
PROTOC?=../protoc
all: nanopb_pb2.py
%_pb2.py: %.proto
$(PROTOC) --python_out=. $<
.PHONY: clean
clean:
rm nanopb_pb2.py

View file

@ -0,0 +1,50 @@
'''This file automatically rebuilds the proto definitions for Python.'''
from __future__ import absolute_import
import os.path
import sys
import pkg_resources
from ._utils import has_grpcio_protoc, invoke_protoc, print_versions
dirname = os.path.dirname(__file__)
protosrc = os.path.join(dirname, "nanopb.proto")
protodst = os.path.join(dirname, "nanopb_pb2.py")
rebuild = False
if os.path.isfile(protosrc):
src_date = os.path.getmtime(protosrc)
if not os.path.isfile(protodst) or os.path.getmtime(protodst) < src_date:
rebuild = True
if not rebuild:
try:
from . import nanopb_pb2
except AttributeError as e:
rebuild = True
sys.stderr.write("Failed to import nanopb_pb2.py: " + str(e) + "\n"
"Will automatically attempt to rebuild this.\n"
"Verify that python-protobuf and protoc versions match.\n")
print_versions()
if rebuild:
cmd = [
"protoc",
"--python_out={}".format(dirname),
protosrc,
"-I={}".format(dirname),
]
if has_grpcio_protoc():
# grpcio-tools has an extra CLI argument
# from grpc.tools.protoc __main__ invocation.
_builtin_proto_include = pkg_resources.resource_filename('grpc_tools', '_proto')
cmd.append("-I={}".format(_builtin_proto_include))
try:
invoke_protoc(argv=cmd)
except:
sys.stderr.write("Failed to build nanopb_pb2.py: " + ' '.join(cmd) + "\n")
raise

View file

@ -0,0 +1,66 @@
import sys
import subprocess
import os.path
def has_grpcio_protoc():
# type: () -> bool
""" checks if grpcio-tools protoc is installed"""
try:
import grpc_tools.protoc
except ImportError:
return False
return True
def invoke_protoc(argv):
# type: (list) -> typing.Any
"""
Invoke protoc.
This routine will use grpcio-provided protoc if it exists,
using system-installed protoc as a fallback.
Args:
argv: protoc CLI invocation, first item must be 'protoc'
"""
# Add current directory to include path if nothing else is specified
if not [x for x in argv if x.startswith('-I')]:
argv.append("-I.")
# Add default protoc include paths
nanopb_include = os.path.dirname(os.path.abspath(__file__))
argv.append('-I' + nanopb_include)
if has_grpcio_protoc():
import grpc_tools.protoc as protoc
import pkg_resources
proto_include = pkg_resources.resource_filename('grpc_tools', '_proto')
argv.append('-I' + proto_include)
return protoc.main(argv)
else:
return subprocess.call(argv)
def print_versions():
try:
if has_grpcio_protoc():
import grpc_tools.protoc
sys.stderr.write("Using grpcio-tools protoc from " + grpc_tools.protoc.__file__ + "\n")
else:
sys.stderr.write("Using protoc from system path\n")
invoke_protoc(['protoc', '--version'])
except Exception as e:
sys.stderr.write("Failed to determine protoc version: " + str(e) + "\n")
try:
import google.protobuf
sys.stderr.write("Using python-protobuf from " + google.protobuf.__file__ + "\n")
sys.stderr.write("Python-protobuf version: " + google.protobuf.__version__ + "\n")
except Exception as e:
sys.stderr.write("Failed to determine python-protobuf version: " + str(e) + "\n")
if __name__ == '__main__':
print_versions()

View file

@ -0,0 +1,185 @@
// Custom options for defining:
// - Maximum size of string/bytes
// - Maximum number of elements in array
//
// These are used by nanopb to generate statically allocable structures
// for memory-limited environments.
syntax = "proto2";
import "google/protobuf/descriptor.proto";
option java_package = "fi.kapsi.koti.jpa.nanopb";
enum FieldType {
FT_DEFAULT = 0; // Automatically decide field type, generate static field if possible.
FT_CALLBACK = 1; // Always generate a callback field.
FT_POINTER = 4; // Always generate a dynamically allocated field.
FT_STATIC = 2; // Generate a static field or raise an exception if not possible.
FT_IGNORE = 3; // Ignore the field completely.
FT_INLINE = 5; // Legacy option, use the separate 'fixed_length' option instead
}
enum IntSize {
IS_DEFAULT = 0; // Default, 32/64bit based on type in .proto
IS_8 = 8;
IS_16 = 16;
IS_32 = 32;
IS_64 = 64;
}
enum TypenameMangling {
M_NONE = 0; // Default, no typename mangling
M_STRIP_PACKAGE = 1; // Strip current package name
M_FLATTEN = 2; // Only use last path component
M_PACKAGE_INITIALS = 3; // Replace the package name by the initials
}
enum DescriptorSize {
DS_AUTO = 0; // Select minimal size based on field type
DS_1 = 1; // 1 word; up to 15 byte fields, no arrays
DS_2 = 2; // 2 words; up to 4095 byte fields, 4095 entry arrays
DS_4 = 4; // 4 words; up to 2^32-1 byte fields, 2^16-1 entry arrays
DS_8 = 8; // 8 words; up to 2^32-1 entry arrays
}
// This is the inner options message, which basically defines options for
// a field. When it is used in message or file scope, it applies to all
// fields.
message NanoPBOptions {
// Allocated size for 'bytes' and 'string' fields.
// For string fields, this should include the space for null terminator.
optional int32 max_size = 1;
// Maximum length for 'string' fields. Setting this is equivalent
// to setting max_size to a value of length+1.
optional int32 max_length = 14;
// Allocated number of entries in arrays ('repeated' fields)
optional int32 max_count = 2;
// Size of integer fields. Can save some memory if you don't need
// full 32 bits for the value.
optional IntSize int_size = 7 [default = IS_DEFAULT];
// Force type of field (callback or static allocation)
optional FieldType type = 3 [default = FT_DEFAULT];
// Use long names for enums, i.e. EnumName_EnumValue.
optional bool long_names = 4 [default = true];
// Add 'packed' attribute to generated structs.
// Note: this cannot be used on CPUs that break on unaligned
// accesses to variables.
optional bool packed_struct = 5 [default = false];
// Add 'packed' attribute to generated enums.
optional bool packed_enum = 10 [default = false];
// Skip this message
optional bool skip_message = 6 [default = false];
// Generate oneof fields as normal optional fields instead of union.
optional bool no_unions = 8 [default = false];
// integer type tag for a message
optional uint32 msgid = 9;
// decode oneof as anonymous union
optional bool anonymous_oneof = 11 [default = false];
// Proto3 singular field does not generate a "has_" flag
optional bool proto3 = 12 [default = false];
// Force proto3 messages to have no "has_" flag.
// This was default behavior until nanopb-0.4.0.
optional bool proto3_singular_msgs = 21 [default = false];
// Generate an enum->string mapping function (can take up lots of space).
optional bool enum_to_string = 13 [default = false];
// Generate bytes arrays with fixed length
optional bool fixed_length = 15 [default = false];
// Generate repeated field with fixed count
optional bool fixed_count = 16 [default = false];
// Generate message-level callback that is called before decoding submessages.
// This can be used to set callback fields for submsgs inside oneofs.
optional bool submsg_callback = 22 [default = false];
// Shorten or remove package names from type names.
// This option applies only on the file level.
optional TypenameMangling mangle_names = 17 [default = M_NONE];
// Data type for storage associated with callback fields.
optional string callback_datatype = 18 [default = "pb_callback_t"];
// Callback function used for encoding and decoding.
// Prior to nanopb-0.4.0, the callback was specified in per-field pb_callback_t
// structure. This is still supported, but does not work inside e.g. oneof or pointer
// fields. Instead, a new method allows specifying a per-message callback that
// will be called for all callback fields in a message type.
optional string callback_function = 19 [default = "pb_default_field_callback"];
// Select the size of field descriptors. This option has to be defined
// for the whole message, not per-field. Usually automatic selection is
// ok, but if it results in compilation errors you can increase the field
// size here.
optional DescriptorSize descriptorsize = 20 [default = DS_AUTO];
// Set default value for has_ fields.
optional bool default_has = 23 [default = false];
// Extra files to include in generated `.pb.h`
repeated string include = 24;
// Automatic includes to exclude from generated `.pb.h`
// Same as nanopb_generator.py command line flag -x.
repeated string exclude = 26;
// Package name that applies only for nanopb.
optional string package = 25;
// Override type of the field in generated C code. Only to be used with related field types
optional google.protobuf.FieldDescriptorProto.Type type_override = 27;
// Due to historical reasons, nanopb orders fields in structs by their tag number
// instead of the order in .proto. Set this to false to keep the .proto order.
// The default value will probably change to false in nanopb-0.5.0.
optional bool sort_by_tag = 28 [default = true];
// Set the FT_DEFAULT field conversion strategy.
// A field that can become a static member of a c struct (e.g. int, bool, etc)
// will be a a static field.
// Fields with dynamic length are converted to either a pointer or a callback.
optional FieldType fallback_type = 29 [default = FT_CALLBACK];
}
// Extensions to protoc 'Descriptor' type in order to define options
// inside a .proto file.
//
// Protocol Buffers extension number registry
// --------------------------------
// Project: Nanopb
// Contact: Petteri Aimonen <jpa@kapsi.fi>
// Web site: http://kapsi.fi/~jpa/nanopb
// Extensions: 1010 (all types)
// --------------------------------
extend google.protobuf.FileOptions {
optional NanoPBOptions nanopb_fileopt = 1010;
}
extend google.protobuf.MessageOptions {
optional NanoPBOptions nanopb_msgopt = 1010;
}
extend google.protobuf.EnumOptions {
optional NanoPBOptions nanopb_enumopt = 1010;
}
extend google.protobuf.FieldOptions {
optional NanoPBOptions nanopb = 1010;
}

39
third_party/nanopb/generator/protoc vendored Executable file
View file

@ -0,0 +1,39 @@
#!/usr/bin/env python3
# This file acts as a drop-in replacement of binary protoc.exe.
# It will use either Python-based protoc from grpcio-tools package,
# or if it is not available, protoc.exe from path if found.
import sys
import os
import os.path
from nanopb_generator import invoke_protoc
if __name__ == '__main__':
# Get path of the directory where this script is stored.
if getattr(sys, 'frozen', False):
mypath = os.path.dirname(sys.executable) # For pyInstaller
else:
mypath = os.path.dirname(__file__)
# Avoid recursive calls to self
env_paths = os.environ["PATH"].split(os.pathsep)
if mypath in env_paths:
env_paths.remove(mypath)
os.environ["PATH"] = os.pathsep.join(env_paths)
# Add argument for finding the nanopb generator when using --nanopb_out=
# argument to protoc.
if os.path.isfile(os.path.join(mypath, "protoc-gen-nanopb.exe")):
protoc_gen_nanopb = os.path.join(mypath, "protoc-gen-nanopb.exe")
elif os.name == 'nt':
protoc_gen_nanopb = os.path.join(mypath, "protoc-gen-nanopb.bat")
else:
protoc_gen_nanopb = os.path.join(mypath, "protoc-gen-nanopb")
args = sys.argv[1:]
if os.path.isfile(protoc_gen_nanopb):
args = ['--plugin=protoc-gen-nanopb=%s' % protoc_gen_nanopb] + args
status = invoke_protoc(['protoc'] + args)
sys.exit(status)

View file

@ -0,0 +1,13 @@
#!/bin/sh
# This file is used to invoke nanopb_generator.py as a plugin
# to protoc on Linux and other *nix-style systems.
# Use it like this:
# protoc --plugin=protoc-gen-nanopb=..../protoc-gen-nanopb --nanopb_out=dir foo.proto
#
# Note that if you use the binary package of nanopb, the protoc
# path is already set up properly and there is no need to give
# --plugin= on the command line.
MYPATH=$(dirname "$0")
exec "$MYPATH/nanopb_generator.py" --protoc-plugin

View file

@ -0,0 +1,16 @@
#!/bin/sh
# This file is used to invoke nanopb_generator.py2 as a plugin
# to protoc on Linux and other *nix-style systems.
#
# The difference from protoc-gen-nanopb is that this executes with Python 2.
#
# Use it like this:
# protoc --plugin=protoc-gen-nanopb=..../protoc-gen-nanopb-py2 --nanopb_out=dir foo.proto
#
# Note that if you use the binary package of nanopb, the protoc
# path is already set up properly and there is no need to give
# --plugin= on the command line.
MYPATH=$(dirname "$0")
exec "$MYPATH/nanopb_generator.py2" --protoc-plugin

View file

@ -0,0 +1,12 @@
@echo off
:: This file is used to invoke nanopb_generator.py as a plugin
:: to protoc on Windows.
:: Use it like this:
:: protoc --plugin=protoc-gen-nanopb=..../protoc-gen-nanopb.bat --nanopb_out=dir foo.proto
::
:: Note that if you use the binary package of nanopb, the protoc
:: path is already set up properly and there is no need to give
:: --plugin= on the command line.
set mydir=%~dp0
python "%mydir%\nanopb_generator.py" --protoc-plugin %*

View file

@ -0,0 +1,9 @@
@echo off
:: This file acts as a drop-in replacement of binary protoc.exe.
:: It will use either Python-based protoc from grpcio-tools package,
:: or if it is not available, protoc.exe from path if found.
setLocal enableDelayedExpansion
set mydir=%~dp0
python "%mydir%\protoc" %*
exit /b %ERRORLEVEL%

42
third_party/nanopb/library.json vendored Normal file
View file

@ -0,0 +1,42 @@
{
"name": "Nanopb",
"version": "0.4.6.4",
"keywords": "protocol buffers, protobuf, google",
"description": "Nanopb is a plain-C implementation of Google's Protocol Buffers data format. It is targeted at 32 bit microcontrollers, but is also fit for other embedded systems with tight (<10 kB ROM, <1 kB RAM) memory constraints.",
"repository": {
"type": "git",
"url": "https://github.com/nanopb/nanopb.git"
},
"authors": [{
"name": "Petteri Aimonen",
"email": "jpa@nanopb.mail.kapsi.fi",
"url": "http://koti.kapsi.fi/jpa/nanopb/"
}],
"export": {
"include": [
"*.c",
"*.cpp",
"*.h",
"examples",
"generator"
],
"exclude": [
"generator/**/__pycache__",
"examples/platformio/.gitignore"
]
},
"build": {
"extraScript": "generator/platformio_generator.py",
"srcDir": "",
"srcFilter": [
"+<*.c>"
]
},
"examples": [
"examples/platformio/platformio.ini",
"examples/platformio/src/*.c",
"examples/*/*.c"
],
"frameworks": "*",
"platforms": "*"
}

911
third_party/nanopb/pb.h vendored Normal file
View file

@ -0,0 +1,911 @@
/* Common parts of the nanopb library. Most of these are quite low-level
* stuff. For the high-level interface, see pb_encode.h and pb_decode.h.
*/
#ifndef PB_H_INCLUDED
#define PB_H_INCLUDED
/*****************************************************************
* Nanopb compilation time options. You can change these here by *
* uncommenting the lines, or on the compiler command line. *
*****************************************************************/
/* Enable support for dynamically allocated fields */
/* #define PB_ENABLE_MALLOC 1 */
/* Define this if your CPU / compiler combination does not support
* unaligned memory access to packed structures. Note that packed
* structures are only used when requested in .proto options. */
/* #define PB_NO_PACKED_STRUCTS 1 */
/* Increase the number of required fields that are tracked.
* A compiler warning will tell if you need this. */
/* #define PB_MAX_REQUIRED_FIELDS 256 */
/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */
/* #define PB_FIELD_32BIT 1 */
/* Disable support for error messages in order to save some code space. */
/* #define PB_NO_ERRMSG 1 */
/* Disable support for custom streams (support only memory buffers). */
/* #define PB_BUFFER_ONLY 1 */
/* Disable support for 64-bit datatypes, for compilers without int64_t
or to save some code space. */
/* #define PB_WITHOUT_64BIT 1 */
/* Don't encode scalar arrays as packed. This is only to be used when
* the decoder on the receiving side cannot process packed scalar arrays.
* Such example is older protobuf.js. */
/* #define PB_ENCODE_ARRAYS_UNPACKED 1 */
/* Enable conversion of doubles to floats for platforms that do not
* support 64-bit doubles. Most commonly AVR. */
/* #define PB_CONVERT_DOUBLE_FLOAT 1 */
/* Check whether incoming strings are valid UTF-8 sequences. Slows down
* the string processing slightly and slightly increases code size. */
/* #define PB_VALIDATE_UTF8 1 */
/* This can be defined if the platform is little-endian and has 8-bit bytes.
* Normally it is automatically detected based on __BYTE_ORDER__ macro. */
/* #define PB_LITTLE_ENDIAN_8BIT 1 */
/* Configure static assert mechanism. Instead of changing these, set your
* compiler to C11 standard mode if possible. */
/* #define PB_C99_STATIC_ASSERT 1 */
/* #define PB_NO_STATIC_ASSERT 1 */
/******************************************************************
* You usually don't need to change anything below this line. *
* Feel free to look around and use the defined macros, though. *
******************************************************************/
/* Version of the nanopb library. Just in case you want to check it in
* your own program. */
#define NANOPB_VERSION "nanopb-0.4.6"
/* Include all the system headers needed by nanopb. You will need the
* definitions of the following:
* - strlen, memcpy, memset functions
* - [u]int_least8_t, uint_fast8_t, [u]int_least16_t, [u]int32_t, [u]int64_t
* - size_t
* - bool
*
* If you don't have the standard header files, you can instead provide
* a custom header that defines or includes all this. In that case,
* define PB_SYSTEM_HEADER to the path of this file.
*/
#ifdef PB_SYSTEM_HEADER
#include PB_SYSTEM_HEADER
#else
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>
#ifdef PB_ENABLE_MALLOC
#include <stdlib.h>
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Macro for defining packed structures (compiler dependent).
* This just reduces memory requirements, but is not required.
*/
#if defined(PB_NO_PACKED_STRUCTS)
/* Disable struct packing */
# define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END
# define pb_packed
#elif defined(__GNUC__) || defined(__clang__)
/* For GCC and clang */
# define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END
# define pb_packed __attribute__((packed))
#elif defined(__ICCARM__) || defined(__CC_ARM)
/* For IAR ARM and Keil MDK-ARM compilers */
# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)")
# define PB_PACKED_STRUCT_END _Pragma("pack(pop)")
# define pb_packed
#elif defined(_MSC_VER) && (_MSC_VER >= 1500)
/* For Microsoft Visual C++ */
# define PB_PACKED_STRUCT_START __pragma(pack(push, 1))
# define PB_PACKED_STRUCT_END __pragma(pack(pop))
# define pb_packed
#else
/* Unknown compiler */
# define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END
# define pb_packed
#endif
/* Detect endianness */
#ifndef PB_LITTLE_ENDIAN_8BIT
#if ((defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \
defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \
defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM)) \
&& CHAR_BIT == 8
#define PB_LITTLE_ENDIAN_8BIT 1
#endif
#endif
/* Handly macro for suppressing unreferenced-parameter compiler warnings. */
#ifndef PB_UNUSED
#define PB_UNUSED(x) (void)(x)
#endif
/* Harvard-architecture processors may need special attributes for storing
* field information in program memory. */
#ifndef PB_PROGMEM
#ifdef __AVR__
#include <avr/pgmspace.h>
#define PB_PROGMEM PROGMEM
#define PB_PROGMEM_READU32(x) pgm_read_dword(&x)
#else
#define PB_PROGMEM
#define PB_PROGMEM_READU32(x) (x)
#endif
#endif
/* Compile-time assertion, used for checking compatible compilation options.
* If this does not work properly on your compiler, use
* #define PB_NO_STATIC_ASSERT to disable it.
*
* But before doing that, check carefully the error message / place where it
* comes from to see if the error has a real cause. Unfortunately the error
* message is not always very clear to read, but you can see the reason better
* in the place where the PB_STATIC_ASSERT macro was called.
*/
#ifndef PB_NO_STATIC_ASSERT
# ifndef PB_STATIC_ASSERT
# if defined(__ICCARM__)
/* IAR has static_assert keyword but no _Static_assert */
# define PB_STATIC_ASSERT(COND,MSG) static_assert(COND,#MSG);
# elif defined(PB_C99_STATIC_ASSERT)
/* Classic negative-size-array static assert mechanism */
# define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1];
# define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER)
# define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##_##LINE##_##COUNTER
# elif defined(__cplusplus)
/* C++11 standard static_assert mechanism */
# define PB_STATIC_ASSERT(COND,MSG) static_assert(COND,#MSG);
# else
/* C11 standard _Static_assert mechanism */
# define PB_STATIC_ASSERT(COND,MSG) _Static_assert(COND,#MSG);
# endif
# endif
#else
/* Static asserts disabled by PB_NO_STATIC_ASSERT */
# define PB_STATIC_ASSERT(COND,MSG)
#endif
/* Test that PB_STATIC_ASSERT works
* If you get errors here, you may need to do one of these:
* - Enable C11 standard support in your compiler
* - Define PB_C99_STATIC_ASSERT to enable C99 standard support
* - Define PB_NO_STATIC_ASSERT to disable static asserts altogether
*/
PB_STATIC_ASSERT(1, STATIC_ASSERT_IS_NOT_WORKING)
/* Number of required fields to keep track of. */
#ifndef PB_MAX_REQUIRED_FIELDS
#define PB_MAX_REQUIRED_FIELDS 64
#endif
#if PB_MAX_REQUIRED_FIELDS < 64
#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64).
#endif
#ifdef PB_WITHOUT_64BIT
#ifdef PB_CONVERT_DOUBLE_FLOAT
/* Cannot use doubles without 64-bit types */
#undef PB_CONVERT_DOUBLE_FLOAT
#endif
#endif
/* List of possible field types. These are used in the autogenerated code.
* Least-significant 4 bits tell the scalar type
* Most-significant 4 bits specify repeated/required/packed etc.
*/
typedef uint_least8_t pb_type_t;
/**** Field data types ****/
/* Numeric types */
#define PB_LTYPE_BOOL 0x00U /* bool */
#define PB_LTYPE_VARINT 0x01U /* int32, int64, enum, bool */
#define PB_LTYPE_UVARINT 0x02U /* uint32, uint64 */
#define PB_LTYPE_SVARINT 0x03U /* sint32, sint64 */
#define PB_LTYPE_FIXED32 0x04U /* fixed32, sfixed32, float */
#define PB_LTYPE_FIXED64 0x05U /* fixed64, sfixed64, double */
/* Marker for last packable field type. */
#define PB_LTYPE_LAST_PACKABLE 0x05U
/* Byte array with pre-allocated buffer.
* data_size is the length of the allocated PB_BYTES_ARRAY structure. */
#define PB_LTYPE_BYTES 0x06U
/* String with pre-allocated buffer.
* data_size is the maximum length. */
#define PB_LTYPE_STRING 0x07U
/* Submessage
* submsg_fields is pointer to field descriptions */
#define PB_LTYPE_SUBMESSAGE 0x08U
/* Submessage with pre-decoding callback
* The pre-decoding callback is stored as pb_callback_t right before pSize.
* submsg_fields is pointer to field descriptions */
#define PB_LTYPE_SUBMSG_W_CB 0x09U
/* Extension pseudo-field
* The field contains a pointer to pb_extension_t */
#define PB_LTYPE_EXTENSION 0x0AU
/* Byte array with inline, pre-allocated byffer.
* data_size is the length of the inline, allocated buffer.
* This differs from PB_LTYPE_BYTES by defining the element as
* pb_byte_t[data_size] rather than pb_bytes_array_t. */
#define PB_LTYPE_FIXED_LENGTH_BYTES 0x0BU
/* Number of declared LTYPES */
#define PB_LTYPES_COUNT 0x0CU
#define PB_LTYPE_MASK 0x0FU
/**** Field repetition rules ****/
#define PB_HTYPE_REQUIRED 0x00U
#define PB_HTYPE_OPTIONAL 0x10U
#define PB_HTYPE_SINGULAR 0x10U
#define PB_HTYPE_REPEATED 0x20U
#define PB_HTYPE_FIXARRAY 0x20U
#define PB_HTYPE_ONEOF 0x30U
#define PB_HTYPE_MASK 0x30U
/**** Field allocation types ****/
#define PB_ATYPE_STATIC 0x00U
#define PB_ATYPE_POINTER 0x80U
#define PB_ATYPE_CALLBACK 0x40U
#define PB_ATYPE_MASK 0xC0U
#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK)
#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK)
#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK)
#define PB_LTYPE_IS_SUBMSG(x) (PB_LTYPE(x) == PB_LTYPE_SUBMESSAGE || \
PB_LTYPE(x) == PB_LTYPE_SUBMSG_W_CB)
/* Data type used for storing sizes of struct fields
* and array counts.
*/
#if defined(PB_FIELD_32BIT)
typedef uint32_t pb_size_t;
typedef int32_t pb_ssize_t;
#else
typedef uint_least16_t pb_size_t;
typedef int_least16_t pb_ssize_t;
#endif
#define PB_SIZE_MAX ((pb_size_t)-1)
/* Data type for storing encoded data and other byte streams.
* This typedef exists to support platforms where uint8_t does not exist.
* You can regard it as equivalent on uint8_t on other platforms.
*/
typedef uint_least8_t pb_byte_t;
/* Forward declaration of struct types */
typedef struct pb_istream_s pb_istream_t;
typedef struct pb_ostream_s pb_ostream_t;
typedef struct pb_field_iter_s pb_field_iter_t;
/* This structure is used in auto-generated constants
* to specify struct fields.
*/
typedef struct pb_msgdesc_s pb_msgdesc_t;
struct pb_msgdesc_s {
const uint32_t *field_info;
const pb_msgdesc_t * const * submsg_info;
const pb_byte_t *default_value;
bool (*field_callback)(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field);
pb_size_t field_count;
pb_size_t required_field_count;
pb_size_t largest_tag;
};
/* Iterator for message descriptor */
struct pb_field_iter_s {
const pb_msgdesc_t *descriptor; /* Pointer to message descriptor constant */
void *message; /* Pointer to start of the structure */
pb_size_t index; /* Index of the field */
pb_size_t field_info_index; /* Index to descriptor->field_info array */
pb_size_t required_field_index; /* Index that counts only the required fields */
pb_size_t submessage_index; /* Index that counts only submessages */
pb_size_t tag; /* Tag of current field */
pb_size_t data_size; /* sizeof() of a single item */
pb_size_t array_size; /* Number of array entries */
pb_type_t type; /* Type of current field */
void *pField; /* Pointer to current field in struct */
void *pData; /* Pointer to current data contents. Different than pField for arrays and pointers. */
void *pSize; /* Pointer to count/has field */
const pb_msgdesc_t *submsg_desc; /* For submessage fields, pointer to field descriptor for the submessage. */
};
/* For compatibility with legacy code */
typedef pb_field_iter_t pb_field_t;
/* Make sure that the standard integer types are of the expected sizes.
* Otherwise fixed32/fixed64 fields can break.
*
* If you get errors here, it probably means that your stdint.h is not
* correct for your platform.
*/
#ifndef PB_WITHOUT_64BIT
PB_STATIC_ASSERT(sizeof(int64_t) == 2 * sizeof(int32_t), INT64_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(uint64_t) == 2 * sizeof(uint32_t), UINT64_T_WRONG_SIZE)
#endif
/* This structure is used for 'bytes' arrays.
* It has the number of bytes in the beginning, and after that an array.
* Note that actual structs used will have a different length of bytes array.
*/
#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; pb_byte_t bytes[n]; }
#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes))
struct pb_bytes_array_s {
pb_size_t size;
pb_byte_t bytes[1];
};
typedef struct pb_bytes_array_s pb_bytes_array_t;
/* This structure is used for giving the callback function.
* It is stored in the message structure and filled in by the method that
* calls pb_decode.
*
* The decoding callback will be given a limited-length stream
* If the wire type was string, the length is the length of the string.
* If the wire type was a varint/fixed32/fixed64, the length is the length
* of the actual value.
* The function may be called multiple times (especially for repeated types,
* but also otherwise if the message happens to contain the field multiple
* times.)
*
* The encoding callback will receive the actual output stream.
* It should write all the data in one call, including the field tag and
* wire type. It can write multiple fields.
*
* The callback can be null if you want to skip a field.
*/
typedef struct pb_callback_s pb_callback_t;
struct pb_callback_s {
/* Callback functions receive a pointer to the arg field.
* You can access the value of the field as *arg, and modify it if needed.
*/
union {
bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg);
bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg);
} funcs;
/* Free arg for use by callback */
void *arg;
};
extern bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field);
/* Wire types. Library user needs these only in encoder callbacks. */
typedef enum {
PB_WT_VARINT = 0,
PB_WT_64BIT = 1,
PB_WT_STRING = 2,
PB_WT_32BIT = 5,
PB_WT_PACKED = 255 /* PB_WT_PACKED is internal marker for packed arrays. */
} pb_wire_type_t;
/* Structure for defining the handling of unknown/extension fields.
* Usually the pb_extension_type_t structure is automatically generated,
* while the pb_extension_t structure is created by the user. However,
* if you want to catch all unknown fields, you can also create a custom
* pb_extension_type_t with your own callback.
*/
typedef struct pb_extension_type_s pb_extension_type_t;
typedef struct pb_extension_s pb_extension_t;
struct pb_extension_type_s {
/* Called for each unknown field in the message.
* If you handle the field, read off all of its data and return true.
* If you do not handle the field, do not read anything and return true.
* If you run into an error, return false.
* Set to NULL for default handler.
*/
bool (*decode)(pb_istream_t *stream, pb_extension_t *extension,
uint32_t tag, pb_wire_type_t wire_type);
/* Called once after all regular fields have been encoded.
* If you have something to write, do so and return true.
* If you do not have anything to write, just return true.
* If you run into an error, return false.
* Set to NULL for default handler.
*/
bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension);
/* Free field for use by the callback. */
const void *arg;
};
struct pb_extension_s {
/* Type describing the extension field. Usually you'll initialize
* this to a pointer to the automatically generated structure. */
const pb_extension_type_t *type;
/* Destination for the decoded data. This must match the datatype
* of the extension field. */
void *dest;
/* Pointer to the next extension handler, or NULL.
* If this extension does not match a field, the next handler is
* automatically called. */
pb_extension_t *next;
/* The decoder sets this to true if the extension was found.
* Ignored for encoding. */
bool found;
};
#define pb_extension_init_zero {NULL,NULL,NULL,false}
/* Memory allocation functions to use. You can define pb_realloc and
* pb_free to custom functions if you want. */
#ifdef PB_ENABLE_MALLOC
# ifndef pb_realloc
# define pb_realloc(ptr, size) realloc(ptr, size)
# endif
# ifndef pb_free
# define pb_free(ptr) free(ptr)
# endif
#endif
/* This is used to inform about need to regenerate .pb.h/.pb.c files. */
#define PB_PROTO_HEADER_VERSION 40
/* These macros are used to declare pb_field_t's in the constant array. */
/* Size of a structure member, in bytes. */
#define pb_membersize(st, m) (sizeof ((st*)0)->m)
/* Number of entries in an array. */
#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0]))
/* Delta from start of one member to the start of another member. */
#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2))
/* Force expansion of macro value */
#define PB_EXPAND(x) x
/* Binding of a message field set into a specific structure */
#define PB_BIND(msgname, structname, width) \
const uint32_t structname ## _field_info[] PB_PROGMEM = \
{ \
msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ ## width, structname) \
0 \
}; \
const pb_msgdesc_t* const structname ## _submsg_info[] = \
{ \
msgname ## _FIELDLIST(PB_GEN_SUBMSG_INFO, structname) \
NULL \
}; \
const pb_msgdesc_t structname ## _msg = \
{ \
structname ## _field_info, \
structname ## _submsg_info, \
msgname ## _DEFAULT, \
msgname ## _CALLBACK, \
0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \
0 msgname ## _FIELDLIST(PB_GEN_REQ_FIELD_COUNT, structname), \
0 msgname ## _FIELDLIST(PB_GEN_LARGEST_TAG, structname), \
}; \
msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ASSERT_ ## width, structname)
#define PB_GEN_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) +1
#define PB_GEN_REQ_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) \
+ (PB_HTYPE_ ## htype == PB_HTYPE_REQUIRED)
#define PB_GEN_LARGEST_TAG(structname, atype, htype, ltype, fieldname, tag) \
* 0 + tag
/* X-macro for generating the entries in struct_field_info[] array. */
#define PB_GEN_FIELD_INFO_1(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_2(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_4(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_8(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_AUTO(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \
tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_FIELDINFO_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size)
#define PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_ ## width(tag, type, data_offset, data_size, size_offset, array_size)
/* X-macro for generating asserts that entries fit in struct_field_info[] array.
* The structure of macros here must match the structure above in PB_GEN_FIELD_INFO_x(),
* but it is not easily reused because of how macro substitutions work. */
#define PB_GEN_FIELD_INFO_ASSERT_1(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_2(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_4(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_8(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_GEN_FIELD_INFO_ASSERT_AUTO(structname, atype, htype, ltype, fieldname, tag) \
PB_FIELDINFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \
tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
#define PB_FIELDINFO_ASSERT_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size)
#define PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \
PB_FIELDINFO_ASSERT_ ## width(tag, type, data_offset, data_size, size_offset, array_size)
#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
#define PB_DO_PB_HTYPE_REQUIRED(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_SINGULAR(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DO_PB_HTYPE_OPTIONAL(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_REPEATED(structname, fieldname) offsetof(structname, fieldname)
#define PB_DO_PB_HTYPE_FIXARRAY(structname, fieldname) offsetof(structname, fieldname)
#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SO ## htype(structname, fieldname)
#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SO_PTR ## htype(structname, fieldname)
#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) PB_SO_CB ## htype(structname, fieldname)
#define PB_SO_PB_HTYPE_REQUIRED(structname, fieldname) 0
#define PB_SO_PB_HTYPE_SINGULAR(structname, fieldname) 0
#define PB_SO_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname))
#define PB_SO_PB_HTYPE_ONEOF2(structname, fullname, unionname) PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname)
#define PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname)
#define PB_SO_PB_HTYPE_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname)
#define PB_SO_PB_HTYPE_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count)
#define PB_SO_PB_HTYPE_FIXARRAY(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname)
#define PB_SO_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 0
#define PB_SO_PTR_PB_HTYPE_REPEATED(structname, fieldname) PB_SO_PB_HTYPE_REPEATED(structname, fieldname)
#define PB_SO_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_REQUIRED(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_SINGULAR(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname)
#define PB_SO_CB_PB_HTYPE_OPTIONAL(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_REPEATED(structname, fieldname) 0
#define PB_SO_CB_PB_HTYPE_FIXARRAY(structname, fieldname) 0
#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_AS ## htype(structname, fieldname)
#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) PB_AS_PTR ## htype(structname, fieldname)
#define PB_ARRAY_SIZE_CALLBACK(htype, structname, fieldname) 1
#define PB_AS_PB_HTYPE_REQUIRED(structname, fieldname) 1
#define PB_AS_PB_HTYPE_SINGULAR(structname, fieldname) 1
#define PB_AS_PB_HTYPE_OPTIONAL(structname, fieldname) 1
#define PB_AS_PB_HTYPE_ONEOF(structname, fieldname) 1
#define PB_AS_PB_HTYPE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname)
#define PB_AS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname)
#define PB_AS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_ONEOF(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_REPEATED(structname, fieldname) 1
#define PB_AS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname[0])
#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DS ## htype(structname, fieldname)
#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DS_PTR ## htype(structname, fieldname)
#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) PB_DS_CB ## htype(structname, fieldname)
#define PB_DS_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DS_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0])
#define PB_DS_PTR_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
#define PB_DS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0][0])
#define PB_DS_CB_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
#define PB_DS_CB_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_DS_CB_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname)
#define PB_ONEOF_NAME(type, tuple) PB_EXPAND(PB_ONEOF_NAME_ ## type tuple)
#define PB_ONEOF_NAME_UNION(unionname,membername,fullname) unionname
#define PB_ONEOF_NAME_MEMBER(unionname,membername,fullname) membername
#define PB_ONEOF_NAME_FULL(unionname,membername,fullname) fullname
#define PB_GEN_SUBMSG_INFO(structname, atype, htype, ltype, fieldname, tag) \
PB_SUBMSG_INFO_ ## htype(_PB_LTYPE_ ## ltype, structname, fieldname)
#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_ONEOF(ltype, structname, fieldname) PB_SUBMSG_INFO_ONEOF2(ltype, structname, PB_ONEOF_NAME(UNION, fieldname), PB_ONEOF_NAME(MEMBER, fieldname))
#define PB_SUBMSG_INFO_ONEOF2(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername)
#define PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) PB_SI ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE)
#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
#define PB_SI_PB_LTYPE_BOOL(t)
#define PB_SI_PB_LTYPE_BYTES(t)
#define PB_SI_PB_LTYPE_DOUBLE(t)
#define PB_SI_PB_LTYPE_ENUM(t)
#define PB_SI_PB_LTYPE_UENUM(t)
#define PB_SI_PB_LTYPE_FIXED32(t)
#define PB_SI_PB_LTYPE_FIXED64(t)
#define PB_SI_PB_LTYPE_FLOAT(t)
#define PB_SI_PB_LTYPE_INT32(t)
#define PB_SI_PB_LTYPE_INT64(t)
#define PB_SI_PB_LTYPE_MESSAGE(t) PB_SUBMSG_DESCRIPTOR(t)
#define PB_SI_PB_LTYPE_MSG_W_CB(t) PB_SUBMSG_DESCRIPTOR(t)
#define PB_SI_PB_LTYPE_SFIXED32(t)
#define PB_SI_PB_LTYPE_SFIXED64(t)
#define PB_SI_PB_LTYPE_SINT32(t)
#define PB_SI_PB_LTYPE_SINT64(t)
#define PB_SI_PB_LTYPE_STRING(t)
#define PB_SI_PB_LTYPE_UINT32(t)
#define PB_SI_PB_LTYPE_UINT64(t)
#define PB_SI_PB_LTYPE_EXTENSION(t)
#define PB_SI_PB_LTYPE_FIXED_LENGTH_BYTES(t)
#define PB_SUBMSG_DESCRIPTOR(t) &(t ## _msg),
/* The field descriptors use a variable width format, with width of either
* 1, 2, 4 or 8 of 32-bit words. The two lowest bytes of the first byte always
* encode the descriptor size, 6 lowest bits of field tag number, and 8 bits
* of the field type.
*
* Descriptor size is encoded as 0 = 1 word, 1 = 2 words, 2 = 4 words, 3 = 8 words.
*
* Formats, listed starting with the least significant bit of the first word.
* 1 word: [2-bit len] [6-bit tag] [8-bit type] [8-bit data_offset] [4-bit size_offset] [4-bit data_size]
*
* 2 words: [2-bit len] [6-bit tag] [8-bit type] [12-bit array_size] [4-bit size_offset]
* [16-bit data_offset] [12-bit data_size] [4-bit tag>>6]
*
* 4 words: [2-bit len] [6-bit tag] [8-bit type] [16-bit array_size]
* [8-bit size_offset] [24-bit tag>>6]
* [32-bit data_offset]
* [32-bit data_size]
*
* 8 words: [2-bit len] [6-bit tag] [8-bit type] [16-bit reserved]
* [8-bit size_offset] [24-bit tag>>6]
* [32-bit data_offset]
* [32-bit data_size]
* [32-bit array_size]
* [32-bit reserved]
* [32-bit reserved]
* [32-bit reserved]
*/
#define PB_FIELDINFO_1(tag, type, data_offset, data_size, size_offset, array_size) \
(0 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(data_offset) & 0xFF) << 16) | \
(((uint32_t)(size_offset) & 0x0F) << 24) | (((uint32_t)(data_size) & 0x0F) << 28)),
#define PB_FIELDINFO_2(tag, type, data_offset, data_size, size_offset, array_size) \
(1 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(array_size) & 0xFFF) << 16) | (((uint32_t)(size_offset) & 0x0F) << 28)), \
(((uint32_t)(data_offset) & 0xFFFF) | (((uint32_t)(data_size) & 0xFFF) << 16) | (((uint32_t)(tag) & 0x3c0) << 22)),
#define PB_FIELDINFO_4(tag, type, data_offset, data_size, size_offset, array_size) \
(2 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(array_size) & 0xFFFF) << 16)), \
((uint32_t)(int_least8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \
(data_offset), (data_size),
#define PB_FIELDINFO_8(tag, type, data_offset, data_size, size_offset, array_size) \
(3 | (((tag) << 2) & 0xFF) | ((type) << 8)), \
((uint32_t)(int_least8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \
(data_offset), (data_size), (array_size), 0, 0, 0,
/* These assertions verify that the field information fits in the allocated space.
* The generator tries to automatically determine the correct width that can fit all
* data associated with a message. These asserts will fail only if there has been a
* problem in the automatic logic - this may be worth reporting as a bug. As a workaround,
* you can increase the descriptor width by defining PB_FIELDINFO_WIDTH or by setting
* descriptorsize option in .options file.
*/
#define PB_FITS(value,bits) ((uint32_t)(value) < ((uint32_t)1<<bits))
#define PB_FIELDINFO_ASSERT_1(tag, type, data_offset, data_size, size_offset, array_size) \
PB_STATIC_ASSERT(PB_FITS(tag,6) && PB_FITS(data_offset,8) && PB_FITS(size_offset,4) && PB_FITS(data_size,4) && PB_FITS(array_size,1), FIELDINFO_DOES_NOT_FIT_width1_field ## tag)
#define PB_FIELDINFO_ASSERT_2(tag, type, data_offset, data_size, size_offset, array_size) \
PB_STATIC_ASSERT(PB_FITS(tag,10) && PB_FITS(data_offset,16) && PB_FITS(size_offset,4) && PB_FITS(data_size,12) && PB_FITS(array_size,12), FIELDINFO_DOES_NOT_FIT_width2_field ## tag)
#ifndef PB_FIELD_32BIT
/* Maximum field sizes are still 16-bit if pb_size_t is 16-bit */
#define PB_FIELDINFO_ASSERT_4(tag, type, data_offset, data_size, size_offset, array_size) \
PB_STATIC_ASSERT(PB_FITS(tag,16) && PB_FITS(data_offset,16) && PB_FITS((int_least8_t)size_offset,8) && PB_FITS(data_size,16) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width4_field ## tag)
#define PB_FIELDINFO_ASSERT_8(tag, type, data_offset, data_size, size_offset, array_size) \
PB_STATIC_ASSERT(PB_FITS(tag,16) && PB_FITS(data_offset,16) && PB_FITS((int_least8_t)size_offset,8) && PB_FITS(data_size,16) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width8_field ## tag)
#else
/* Up to 32-bit fields supported.
* Note that the checks are against 31 bits to avoid compiler warnings about shift wider than type in the test.
* I expect that there is no reasonable use for >2GB messages with nanopb anyway.
*/
#define PB_FIELDINFO_ASSERT_4(tag, type, data_offset, data_size, size_offset, array_size) \
PB_STATIC_ASSERT(PB_FITS(tag,30) && PB_FITS(data_offset,31) && PB_FITS(size_offset,8) && PB_FITS(data_size,31) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width4_field ## tag)
#define PB_FIELDINFO_ASSERT_8(tag, type, data_offset, data_size, size_offset, array_size) \
PB_STATIC_ASSERT(PB_FITS(tag,30) && PB_FITS(data_offset,31) && PB_FITS(size_offset,8) && PB_FITS(data_size,31) && PB_FITS(array_size,31), FIELDINFO_DOES_NOT_FIT_width8_field ## tag)
#endif
/* Automatic picking of FIELDINFO width:
* Uses width 1 when possible, otherwise resorts to width 2.
* This is used when PB_BIND() is called with "AUTO" as the argument.
* The generator will give explicit size argument when it knows that a message
* structure grows beyond 1-word format limits.
*/
#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FI_WIDTH ## atype(htype, ltype)
#define PB_FI_WIDTH_PB_ATYPE_STATIC(htype, ltype) PB_FI_WIDTH ## htype(ltype)
#define PB_FI_WIDTH_PB_ATYPE_POINTER(htype, ltype) PB_FI_WIDTH ## htype(ltype)
#define PB_FI_WIDTH_PB_ATYPE_CALLBACK(htype, ltype) 2
#define PB_FI_WIDTH_PB_HTYPE_REQUIRED(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_SINGULAR(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_OPTIONAL(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_ONEOF(ltype) PB_FI_WIDTH ## ltype
#define PB_FI_WIDTH_PB_HTYPE_REPEATED(ltype) 2
#define PB_FI_WIDTH_PB_HTYPE_FIXARRAY(ltype) 2
#define PB_FI_WIDTH_PB_LTYPE_BOOL 1
#define PB_FI_WIDTH_PB_LTYPE_BYTES 2
#define PB_FI_WIDTH_PB_LTYPE_DOUBLE 1
#define PB_FI_WIDTH_PB_LTYPE_ENUM 1
#define PB_FI_WIDTH_PB_LTYPE_UENUM 1
#define PB_FI_WIDTH_PB_LTYPE_FIXED32 1
#define PB_FI_WIDTH_PB_LTYPE_FIXED64 1
#define PB_FI_WIDTH_PB_LTYPE_FLOAT 1
#define PB_FI_WIDTH_PB_LTYPE_INT32 1
#define PB_FI_WIDTH_PB_LTYPE_INT64 1
#define PB_FI_WIDTH_PB_LTYPE_MESSAGE 2
#define PB_FI_WIDTH_PB_LTYPE_MSG_W_CB 2
#define PB_FI_WIDTH_PB_LTYPE_SFIXED32 1
#define PB_FI_WIDTH_PB_LTYPE_SFIXED64 1
#define PB_FI_WIDTH_PB_LTYPE_SINT32 1
#define PB_FI_WIDTH_PB_LTYPE_SINT64 1
#define PB_FI_WIDTH_PB_LTYPE_STRING 2
#define PB_FI_WIDTH_PB_LTYPE_UINT32 1
#define PB_FI_WIDTH_PB_LTYPE_UINT64 1
#define PB_FI_WIDTH_PB_LTYPE_EXTENSION 1
#define PB_FI_WIDTH_PB_LTYPE_FIXED_LENGTH_BYTES 2
/* The mapping from protobuf types to LTYPEs is done using these macros. */
#define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL
#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES
#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64
#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT
#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT
#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32
#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64
#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32
#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT
#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT
#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE
#define PB_LTYPE_MAP_MSG_W_CB PB_LTYPE_SUBMSG_W_CB
#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32
#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64
#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT
#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT
#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING
#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT
#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT
#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION
#define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES
/* These macros are used for giving out error messages.
* They are mostly a debugging aid; the main error information
* is the true/false return value from functions.
* Some code space can be saved by disabling the error
* messages if not used.
*
* PB_SET_ERROR() sets the error message if none has been set yet.
* msg must be a constant string literal.
* PB_GET_ERROR() always returns a pointer to a string.
* PB_RETURN_ERROR() sets the error and returns false from current
* function.
*/
#ifdef PB_NO_ERRMSG
#define PB_SET_ERROR(stream, msg) PB_UNUSED(stream)
#define PB_GET_ERROR(stream) "(errmsg disabled)"
#else
#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg))
#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)")
#endif
#define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false
#ifdef __cplusplus
} /* extern "C" */
#endif
#ifdef __cplusplus
#if __cplusplus >= 201103L
#define PB_CONSTEXPR constexpr
#else // __cplusplus >= 201103L
#define PB_CONSTEXPR
#endif // __cplusplus >= 201103L
#if __cplusplus >= 201703L
#define PB_INLINE_CONSTEXPR inline constexpr
#else // __cplusplus >= 201703L
#define PB_INLINE_CONSTEXPR PB_CONSTEXPR
#endif // __cplusplus >= 201703L
namespace nanopb {
// Each type will be partially specialized by the generator.
template <typename GenMessageT> struct MessageDescriptor;
} // namespace nanopb
#endif /* __cplusplus */
#endif

388
third_party/nanopb/pb_common.c vendored Normal file
View file

@ -0,0 +1,388 @@
/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c.
*
* 2014 Petteri Aimonen <jpa@kapsi.fi>
*/
#include "pb_common.h"
static bool load_descriptor_values(pb_field_iter_t *iter)
{
uint32_t word0;
uint32_t data_offset;
int_least8_t size_offset;
if (iter->index >= iter->descriptor->field_count)
return false;
word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
switch(word0 & 3)
{
case 0: {
/* 1-word format */
iter->array_size = 1;
iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
size_offset = (int_least8_t)((word0 >> 24) & 0x0F);
data_offset = (word0 >> 16) & 0xFF;
iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
break;
}
case 1: {
/* 2-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6));
size_offset = (int_least8_t)((word0 >> 28) & 0x0F);
data_offset = word1 & 0xFFFF;
iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
break;
}
case 2: {
/* 4-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
iter->array_size = (pb_size_t)(word0 >> 16);
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
size_offset = (int_least8_t)(word1 & 0xFF);
data_offset = word2;
iter->data_size = (pb_size_t)word3;
break;
}
default: {
/* 8-word format */
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
iter->array_size = (pb_size_t)word4;
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
size_offset = (int_least8_t)(word1 & 0xFF);
data_offset = word2;
iter->data_size = (pb_size_t)word3;
break;
}
}
if (!iter->message)
{
/* Avoid doing arithmetic on null pointers, it is undefined */
iter->pField = NULL;
iter->pSize = NULL;
}
else
{
iter->pField = (char*)iter->message + data_offset;
if (size_offset)
{
iter->pSize = (char*)iter->pField - size_offset;
}
else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED &&
(PB_ATYPE(iter->type) == PB_ATYPE_STATIC ||
PB_ATYPE(iter->type) == PB_ATYPE_POINTER))
{
/* Fixed count array */
iter->pSize = &iter->array_size;
}
else
{
iter->pSize = NULL;
}
if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL)
{
iter->pData = *(void**)iter->pField;
}
else
{
iter->pData = iter->pField;
}
}
if (PB_LTYPE_IS_SUBMSG(iter->type))
{
iter->submsg_desc = iter->descriptor->submsg_info[iter->submessage_index];
}
else
{
iter->submsg_desc = NULL;
}
return true;
}
static void advance_iterator(pb_field_iter_t *iter)
{
iter->index++;
if (iter->index >= iter->descriptor->field_count)
{
/* Restart */
iter->index = 0;
iter->field_info_index = 0;
iter->submessage_index = 0;
iter->required_field_index = 0;
}
else
{
/* Increment indexes based on previous field type.
* All field info formats have the following fields:
* - lowest 2 bits tell the amount of words in the descriptor (2^n words)
* - bits 2..7 give the lowest bits of tag number.
* - bits 8..15 give the field type.
*/
uint32_t prev_descriptor = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3));
/* Add to fields.
* The cast to pb_size_t is needed to avoid -Wconversion warning.
* Because the data is is constants from generator, there is no danger of overflow.
*/
iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len);
iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED));
iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type));
}
}
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message)
{
memset(iter, 0, sizeof(*iter));
iter->descriptor = desc;
iter->message = message;
return load_descriptor_values(iter);
}
bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension)
{
const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg;
bool status;
uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]);
if (PB_ATYPE(word0 >> 8) == PB_ATYPE_POINTER)
{
/* For pointer extensions, the pointer is stored directly
* in the extension structure. This avoids having an extra
* indirection. */
status = pb_field_iter_begin(iter, msg, &extension->dest);
}
else
{
status = pb_field_iter_begin(iter, msg, extension->dest);
}
iter->pSize = &extension->found;
return status;
}
bool pb_field_iter_next(pb_field_iter_t *iter)
{
advance_iterator(iter);
(void)load_descriptor_values(iter);
return iter->index != 0;
}
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
{
if (iter->tag == tag)
{
return true; /* Nothing to do, correct field already. */
}
else if (tag > iter->descriptor->largest_tag)
{
return false;
}
else
{
pb_size_t start = iter->index;
uint32_t fieldinfo;
if (tag < iter->tag)
{
/* Fields are in tag number order, so we know that tag is between
* 0 and our start position. Setting index to end forces
* advance_iterator() call below to restart from beginning. */
iter->index = iter->descriptor->field_count;
}
do
{
/* Advance iterator but don't load values yet */
advance_iterator(iter);
/* Do fast check for tag number match */
fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F))
{
/* Good candidate, check further */
(void)load_descriptor_values(iter);
if (iter->tag == tag &&
PB_LTYPE(iter->type) != PB_LTYPE_EXTENSION)
{
/* Found it */
return true;
}
}
} while (iter->index != start);
/* Searched all the way back to start, and found nothing. */
(void)load_descriptor_values(iter);
return false;
}
}
bool pb_field_iter_find_extension(pb_field_iter_t *iter)
{
if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION)
{
return true;
}
else
{
pb_size_t start = iter->index;
uint32_t fieldinfo;
do
{
/* Advance iterator but don't load values yet */
advance_iterator(iter);
/* Do fast check for field type */
fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION)
{
return load_descriptor_values(iter);
}
} while (iter->index != start);
/* Searched all the way back to start, and found nothing. */
(void)load_descriptor_values(iter);
return false;
}
}
static void *pb_const_cast(const void *p)
{
/* Note: this casts away const, in order to use the common field iterator
* logic for both encoding and decoding. The cast is done using union
* to avoid spurious compiler warnings. */
union {
void *p1;
const void *p2;
} t;
t.p2 = p;
return t.p1;
}
bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message)
{
return pb_field_iter_begin(iter, desc, pb_const_cast(message));
}
bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension)
{
return pb_field_iter_begin_extension(iter, (pb_extension_t*)pb_const_cast(extension));
}
bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
{
if (field->data_size == sizeof(pb_callback_t))
{
pb_callback_t *pCallback = (pb_callback_t*)field->pData;
if (pCallback != NULL)
{
if (istream != NULL && pCallback->funcs.decode != NULL)
{
return pCallback->funcs.decode(istream, field, &pCallback->arg);
}
if (ostream != NULL && pCallback->funcs.encode != NULL)
{
return pCallback->funcs.encode(ostream, field, &pCallback->arg);
}
}
}
return true; /* Success, but didn't do anything */
}
#ifdef PB_VALIDATE_UTF8
/* This function checks whether a string is valid UTF-8 text.
*
* Algorithm is adapted from https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
* Original copyright: Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> 2005-03-30
* Licensed under "Short code license", which allows use under MIT license or
* any compatible with it.
*/
bool pb_validate_utf8(const char *str)
{
const pb_byte_t *s = (const pb_byte_t*)str;
while (*s)
{
if (*s < 0x80)
{
/* 0xxxxxxx */
s++;
}
else if ((s[0] & 0xe0) == 0xc0)
{
/* 110XXXXx 10xxxxxx */
if ((s[1] & 0xc0) != 0x80 ||
(s[0] & 0xfe) == 0xc0) /* overlong? */
return false;
else
s += 2;
}
else if ((s[0] & 0xf0) == 0xe0)
{
/* 1110XXXX 10Xxxxxx 10xxxxxx */
if ((s[1] & 0xc0) != 0x80 ||
(s[2] & 0xc0) != 0x80 ||
(s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || /* overlong? */
(s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || /* surrogate? */
(s[0] == 0xef && s[1] == 0xbf &&
(s[2] & 0xfe) == 0xbe)) /* U+FFFE or U+FFFF? */
return false;
else
s += 3;
}
else if ((s[0] & 0xf8) == 0xf0)
{
/* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
if ((s[1] & 0xc0) != 0x80 ||
(s[2] & 0xc0) != 0x80 ||
(s[3] & 0xc0) != 0x80 ||
(s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || /* overlong? */
(s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) /* > U+10FFFF? */
return false;
else
s += 4;
}
else
{
return false;
}
}
return true;
}
#endif

49
third_party/nanopb/pb_common.h vendored Normal file
View file

@ -0,0 +1,49 @@
/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c.
* These functions are rarely needed by applications directly.
*/
#ifndef PB_COMMON_H_INCLUDED
#define PB_COMMON_H_INCLUDED
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Initialize the field iterator structure to beginning.
* Returns false if the message type is empty. */
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message);
/* Get a field iterator for extension field. */
bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension);
/* Same as pb_field_iter_begin(), but for const message pointer.
* Note that the pointers in pb_field_iter_t will be non-const but shouldn't
* be written to when using these functions. */
bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message);
bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension);
/* Advance the iterator to the next field.
* Returns false when the iterator wraps back to the first field. */
bool pb_field_iter_next(pb_field_iter_t *iter);
/* Advance the iterator until it points at a field with the given tag.
* Returns false if no such field exists. */
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag);
/* Find a field with type PB_LTYPE_EXTENSION, or return false if not found.
* There can be only one extension range field per message. */
bool pb_field_iter_find_extension(pb_field_iter_t *iter);
#ifdef PB_VALIDATE_UTF8
/* Validate UTF-8 text string */
bool pb_validate_utf8(const char *s);
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

1716
third_party/nanopb/pb_decode.c vendored Normal file

File diff suppressed because it is too large Load diff

199
third_party/nanopb/pb_decode.h vendored Normal file
View file

@ -0,0 +1,199 @@
/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c.
* The main function is pb_decode. You also need an input stream, and the
* field descriptions created by nanopb_generator.py.
*/
#ifndef PB_DECODE_H_INCLUDED
#define PB_DECODE_H_INCLUDED
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Structure for defining custom input streams. You will need to provide
* a callback function to read the bytes from your storage, which can be
* for example a file or a network socket.
*
* The callback must conform to these rules:
*
* 1) Return false on IO errors. This will cause decoding to abort.
* 2) You can use state to store your own data (e.g. buffer pointer),
* and rely on pb_read to verify that no-body reads past bytes_left.
* 3) Your callback may be used with substreams, in which case bytes_left
* is different than from the main stream. Don't use bytes_left to compute
* any pointers.
*/
struct pb_istream_s
{
#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, pb_byte_t *buf, size_t count);
#endif
void *state; /* Free field for use by callback implementation */
size_t bytes_left;
#ifndef PB_NO_ERRMSG
const char *errmsg;
#endif
};
#ifndef PB_NO_ERRMSG
#define PB_ISTREAM_EMPTY {0,0,0,0}
#else
#define PB_ISTREAM_EMPTY {0,0,0}
#endif
/***************************
* Main decoding functions *
***************************/
/* Decode a single protocol buffers message from input stream into a C structure.
* Returns true on success, false on any failure.
* The actual struct pointed to by dest must match the description in fields.
* Callback fields of the destination structure must be initialized by caller.
* All other fields will be initialized by this function.
*
* Example usage:
* MyMessage msg = {};
* uint8_t buffer[64];
* pb_istream_t stream;
*
* // ... read some data into buffer ...
*
* stream = pb_istream_from_buffer(buffer, count);
* pb_decode(&stream, MyMessage_fields, &msg);
*/
bool pb_decode(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct);
/* Extended version of pb_decode, with several options to control
* the decoding process:
*
* PB_DECODE_NOINIT: Do not initialize the fields to default values.
* This is slightly faster if you do not need the default
* values and instead initialize the structure to 0 using
* e.g. memset(). This can also be used for merging two
* messages, i.e. combine already existing data with new
* values.
*
* PB_DECODE_DELIMITED: Input message starts with the message size as varint.
* Corresponds to parseDelimitedFrom() in Google's
* protobuf API.
*
* PB_DECODE_NULLTERMINATED: Stop reading when field tag is read as 0. This allows
* reading null terminated messages.
* NOTE: Until nanopb-0.4.0, pb_decode() also allows
* null-termination. This behaviour is not supported in
* most other protobuf implementations, so PB_DECODE_DELIMITED
* is a better option for compatibility.
*
* Multiple flags can be combined with bitwise or (| operator)
*/
#define PB_DECODE_NOINIT 0x01U
#define PB_DECODE_DELIMITED 0x02U
#define PB_DECODE_NULLTERMINATED 0x04U
bool pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags);
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define pb_decode_noinit(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_NOINIT)
#define pb_decode_delimited(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_DELIMITED)
#define pb_decode_delimited_noinit(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_DELIMITED | PB_DECODE_NOINIT)
#define pb_decode_nullterminated(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_NULLTERMINATED)
#ifdef PB_ENABLE_MALLOC
/* Release any allocated pointer fields. If you use dynamic allocation, you should
* call this for any successfully decoded message when you are done with it. If
* pb_decode() returns with an error, the message is already released.
*/
void pb_release(const pb_msgdesc_t *fields, void *dest_struct);
#else
/* Allocation is not supported, so release is no-op */
#define pb_release(fields, dest_struct) PB_UNUSED(fields); PB_UNUSED(dest_struct);
#endif
/**************************************
* Functions for manipulating streams *
**************************************/
/* Create an input stream for reading from a memory buffer.
*
* msglen should be the actual length of the message, not the full size of
* allocated buffer.
*
* Alternatively, you can use a custom stream that reads directly from e.g.
* a file or a network socket.
*/
pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen);
/* Function to read from a pb_istream_t. You can use this if you need to
* read some custom header data, or to read data in field callbacks.
*/
bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
/************************************************
* Helper functions for writing field callbacks *
************************************************/
/* Decode the tag for the next field in the stream. Gives the wire type and
* field tag. At end of the message, returns false and sets eof to true. */
bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof);
/* Skip the field payload data, given the wire type. */
bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type);
/* Decode an integer in the varint format. This works for enum, int32,
* int64, uint32 and uint64 field types. */
#ifndef PB_WITHOUT_64BIT
bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest);
#else
#define pb_decode_varint pb_decode_varint32
#endif
/* Decode an integer in the varint format. This works for enum, int32,
* and uint32 field types. */
bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest);
/* Decode a bool value in varint format. */
bool pb_decode_bool(pb_istream_t *stream, bool *dest);
/* Decode an integer in the zig-zagged svarint format. This works for sint32
* and sint64. */
#ifndef PB_WITHOUT_64BIT
bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest);
#else
bool pb_decode_svarint(pb_istream_t *stream, int32_t *dest);
#endif
/* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to
* a 4-byte wide C variable. */
bool pb_decode_fixed32(pb_istream_t *stream, void *dest);
#ifndef PB_WITHOUT_64BIT
/* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to
* a 8-byte wide C variable. */
bool pb_decode_fixed64(pb_istream_t *stream, void *dest);
#endif
#ifdef PB_CONVERT_DOUBLE_FLOAT
/* Decode a double value into float variable. */
bool pb_decode_double_as_float(pb_istream_t *stream, float *dest);
#endif
/* Make a limited-length substream for reading a PB_WT_STRING field. */
bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream);
bool pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

1000
third_party/nanopb/pb_encode.c vendored Normal file

File diff suppressed because it is too large Load diff

185
third_party/nanopb/pb_encode.h vendored Normal file
View file

@ -0,0 +1,185 @@
/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c.
* The main function is pb_encode. You also need an output stream, and the
* field descriptions created by nanopb_generator.py.
*/
#ifndef PB_ENCODE_H_INCLUDED
#define PB_ENCODE_H_INCLUDED
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Structure for defining custom output streams. You will need to provide
* a callback function to write the bytes to your storage, which can be
* for example a file or a network socket.
*
* The callback must conform to these rules:
*
* 1) Return false on IO errors. This will cause encoding to abort.
* 2) You can use state to store your own data (e.g. buffer pointer).
* 3) pb_write will update bytes_written after your callback runs.
* 4) Substreams will modify max_size and bytes_written. Don't use them
* to calculate any pointers.
*/
struct pb_ostream_s
{
#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.
*/
const int *callback;
#else
bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
#endif
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 bytes_written; /* Number of bytes written so far. */
#ifndef PB_NO_ERRMSG
const char *errmsg;
#endif
};
/***************************
* Main encoding functions *
***************************/
/* Encode a single protocol buffers message from C structure into a stream.
* Returns true on success, false on any failure.
* The actual struct pointed to by src_struct must match the description in fields.
* All required fields in the struct are assumed to have been filled in.
*
* Example usage:
* MyMessage msg = {};
* uint8_t buffer[64];
* pb_ostream_t stream;
*
* msg.field1 = 42;
* stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
* pb_encode(&stream, MyMessage_fields, &msg);
*/
bool pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct);
/* Extended version of pb_encode, with several options to control the
* encoding process:
*
* PB_ENCODE_DELIMITED: Prepend the length of message as a varint.
* Corresponds to writeDelimitedTo() in Google's
* protobuf API.
*
* PB_ENCODE_NULLTERMINATED: Append a null byte to the message for termination.
* NOTE: This behaviour is not supported in most other
* protobuf implementations, so PB_ENCODE_DELIMITED
* is a better option for compatibility.
*/
#define PB_ENCODE_DELIMITED 0x02U
#define PB_ENCODE_NULLTERMINATED 0x04U
bool pb_encode_ex(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct, unsigned int flags);
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define pb_encode_delimited(s,f,d) pb_encode_ex(s,f,d, PB_ENCODE_DELIMITED)
#define pb_encode_nullterminated(s,f,d) pb_encode_ex(s,f,d, PB_ENCODE_NULLTERMINATED)
/* Encode the message to get the size of the encoded data, but do not store
* the data. */
bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct);
/**************************************
* Functions for manipulating streams *
**************************************/
/* Create an output stream for writing into a memory buffer.
* The number of bytes written can be found in stream.bytes_written after
* encoding the message.
*
* Alternatively, you can use a custom stream that writes directly to e.g.
* a file or a network socket.
*/
pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize);
/* Pseudo-stream for measuring the size of a message without actually storing
* the encoded data.
*
* Example usage:
* MyMessage msg = {};
* pb_ostream_t stream = PB_OSTREAM_SIZING;
* pb_encode(&stream, MyMessage_fields, &msg);
* printf("Message size is %d\n", stream.bytes_written);
*/
#ifndef PB_NO_ERRMSG
#define PB_OSTREAM_SIZING {0,0,0,0,0}
#else
#define PB_OSTREAM_SIZING {0,0,0,0}
#endif
/* Function to write into a pb_ostream_t stream. You can use this if you need
* to append or prepend some custom headers to the message.
*/
bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
/************************************************
* Helper functions for writing field callbacks *
************************************************/
/* Encode field header based on type and field number defined in the field
* structure. Call this from the callback before writing out field contents. */
bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_iter_t *field);
/* Encode field header by manually specifying wire type. You need to use this
* if you want to write out packed arrays from a callback field. */
bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number);
/* Encode an integer in the varint format.
* This works for bool, enum, int32, int64, uint32 and uint64 field types. */
#ifndef PB_WITHOUT_64BIT
bool pb_encode_varint(pb_ostream_t *stream, uint64_t value);
#else
bool pb_encode_varint(pb_ostream_t *stream, uint32_t value);
#endif
/* Encode an integer in the zig-zagged svarint format.
* This works for sint32 and sint64. */
#ifndef PB_WITHOUT_64BIT
bool pb_encode_svarint(pb_ostream_t *stream, int64_t value);
#else
bool pb_encode_svarint(pb_ostream_t *stream, int32_t value);
#endif
/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */
bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size);
/* Encode a fixed32, sfixed32 or float value.
* You need to pass a pointer to a 4-byte wide C variable. */
bool pb_encode_fixed32(pb_ostream_t *stream, const void *value);
#ifndef PB_WITHOUT_64BIT
/* Encode a fixed64, sfixed64 or double value.
* You need to pass a pointer to a 8-byte wide C variable. */
bool pb_encode_fixed64(pb_ostream_t *stream, const void *value);
#endif
#ifdef PB_CONVERT_DOUBLE_FLOAT
/* Encode a float value so that it appears like a double in the encoded
* message. */
bool pb_encode_float_as_double(pb_ostream_t *stream, float value);
#endif
/* Encode a submessage field.
* You need to pass the pb_field_t array and pointer to struct, just like
* with pb_encode(). This internally encodes the submessage twice, first to
* calculate message size and then to actually write it out.
*/
bool pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View file

@ -0,0 +1,3 @@
#include "pb.h"
#include "pb_common.h"
#include "pb_decode.h"

View file

@ -0,0 +1,3 @@
#import "pb.h"
#import <pb_common.h>
#include "pb_decode.h"

View file

@ -0,0 +1 @@
@import nanopb;

View file

@ -0,0 +1,3 @@
#import "nanopb/pb.h"
#import <nanopb/pb_common.h>
#include "nanopb/pb_decode.h"

View file

@ -0,0 +1 @@
import nanopb

View file

@ -0,0 +1 @@
../../pb.h

View file

@ -0,0 +1 @@
../../pb_common.h

View file

@ -0,0 +1 @@
../../pb_decode.h

View file

@ -0,0 +1 @@
../../pb_encode.h

1
third_party/nanopb/spm_headers/pb.h vendored Normal file
View file

@ -0,0 +1 @@
#include "nanopb/pb.h"

View file

@ -0,0 +1 @@
#include "nanopb/pb_common.h"

View file

@ -0,0 +1 @@
#include "nanopb/pb_decode.h"

View file

@ -0,0 +1 @@
#include "nanopb/pb_encode.h"

21
third_party/nanopb/tests/Makefile vendored Normal file
View file

@ -0,0 +1,21 @@
all:
scons
clean:
scons -c
coverage:
rm -rf build coverage
# LCOV does not like the newer gcov format
scons CC=gcc-4.6 CXX=gcc-4.6
# Collect the data
mkdir build/coverage
lcov --base-directory . --directory build/ --gcov-tool gcov-4.6 -c -o build/coverage/nanopb.info
# Remove the test code from results
lcov -r build/coverage/nanopb.info '*tests*' -o build/coverage/nanopb.info
# Generate HTML
genhtml -o build/coverage build/coverage/nanopb.info

240
third_party/nanopb/tests/SConstruct vendored Normal file
View file

@ -0,0 +1,240 @@
Help('''
Type 'scons' to build and run all the available test cases.
It will automatically detect your platform and C compiler and
build appropriately.
You can modify the behaviour using following options:
BUILDDIR Directory to build into (default "build")
CC Name of C compiler
CXX Name of C++ compiler
CCFLAGS Flags to pass to the C compiler
CXXFLAGS Flags to pass to the C++ compiler
LINK Name of linker (usually same as CC)
LINKFLAGS Flags to pass to linker
LINKLIBS Flags to pass to linker after object files
PROTOC Path to protoc binary
PROTOCFLAGS Arguments to pass protoc
NODEFARGS Do not add the default CCFLAGS
NOVALGRIND Do not use valgrind for memory checks
For example, for a clang build, use:
scons CC=clang CXX=clang++
''')
import os
import platform
env = Environment(ENV = os.environ)
# Allow giving environment flags on command line.
list_vars = ['CCFLAGS', 'CXXFLAGS', 'LINKFLAGS', 'LINKLIBS', 'PROTOCFLAGS']
for var,val in ARGUMENTS.items():
if var in list_vars:
env.Append(**{var: val})
else:
env.Replace(**{var: val})
env.SetDefault(BUILDDIR = "build")
env.SConsignFile(env['BUILDDIR'] + "/sconsign")
env.Replace(CONFIGUREDIR = env['BUILDDIR'] + "/config")
# If a cross compilation platform is given, apply the environment settings
# from site_scons/platforms/X/X.py
if ARGUMENTS.get('PLATFORM'):
platform_func = platforms.get(ARGUMENTS.get('PLATFORM'))
if not platform_func:
print("Supported platforms: " + str(platforms.keys()))
raise Exception("Unsupported platform: " + ARGUMENTS.get('PLATFORM'))
else:
platform_func(env)
# Load nanopb generator build rules from site_scons/site_tools/nanopb.py
env.Tool("nanopb")
# Limit memory usage. This is to catch problems like issue #338
try:
import resource
soft, hard = resource.getrlimit(resourse.RLIMIT_AS)
resource.setrlimit(resource.RLIMIT_AS, (100*1024*1024, hard))
except:
pass
# On Mac OS X, gcc is usually alias for clang.
# To avoid problem with default options, use clang directly.
if platform.system() == "Darwin" and 'CC' not in ARGUMENTS:
env.Replace(CC = "clang", CXX = "clang++")
# Add the builders defined in site_init.py
add_nanopb_builders(env)
# Path to the files shared by tests, and to the nanopb core.
env.Append(CPPPATH = ["#../", "$COMMON"])
# Path for finding nanopb.proto
env.Append(PROTOCPATH = '#../generator')
# Check the compilation environment, unless we are just cleaning up.
if not env.GetOption('clean'):
def check_ccflags(context, flags, linkflags = ''):
'''Check if given CCFLAGS are supported'''
context.Message('Checking support for CCFLAGS="%s"... ' % flags)
oldflags = context.env['CCFLAGS']
oldlinkflags = context.env['LINKFLAGS']
context.env.Append(CCFLAGS = flags)
context.env.Append(LINKFLAGS = linkflags)
result = context.TryCompile("int main() {return 0;}", '.c')
context.env.Replace(CCFLAGS = oldflags)
context.env.Replace(LINKFLAGS = oldlinkflags)
context.Result(result)
return result
def check_protocversion(context):
context.Display("Checking protoc version... ")
status, output = context.TryAction('$PROTOC --version > $TARGET')
if status:
context.Result(str(output.strip()))
return str(output.strip())
else:
context.Display("error: %s\n" % output.strip())
context.did_show_result = 1
context.Result("unknown, assuming 3.6.1")
return "3.6.1"
conf = Configure(env, custom_tests =
{'CheckCCFLAGS': check_ccflags,
'CheckProtocVersion': check_protocversion})
# If the platform doesn't support C99, use our own header file instead.
stdbool = conf.CheckCHeader('stdbool.h')
stdint = conf.CheckCHeader('stdint.h')
stddef = conf.CheckCHeader('stddef.h')
string = conf.CheckCHeader('string.h')
stdlib = conf.CheckCHeader('stdlib.h')
limits = conf.CheckCHeader('limits.h')
if not stdbool or not stdint or not stddef or not string or not limits:
conf.env.Append(CPPDEFINES = {'PB_SYSTEM_HEADER': '\\"pb_syshdr.h\\"'})
conf.env.Append(CPPPATH = "#../extra")
conf.env.Append(SYSHDR = '\\"pb_syshdr.h\\"')
if stdbool: conf.env.Append(CPPDEFINES = {'HAVE_STDBOOL_H': 1})
if stdint: conf.env.Append(CPPDEFINES = {'HAVE_STDINT_H': 1})
if stddef: conf.env.Append(CPPDEFINES = {'HAVE_STDDEF_H': 1})
if string: conf.env.Append(CPPDEFINES = {'HAVE_STRING_H': 1})
if stdlib: conf.env.Append(CPPDEFINES = {'HAVE_STDLIB_H': 1})
if limits: conf.env.Append(CPPDEFINES = {'HAVE_LIMITS_H': 1})
# Check protoc version
conf.env['PROTOC_VERSION'] = conf.CheckProtocVersion()
# Initialize compiler arguments with defaults, unless overridden on
# command line.
if not env.get('NODEFARGS'):
# Check if libmudflap is available (only with GCC)
if 'gcc' in env['CC']:
if conf.CheckLib('mudflap'):
conf.env.Append(CCFLAGS = '-fmudflap')
conf.env.Append(LINKFLAGS = '-fmudflap')
# Check if we can use extra strict warning flags (only with GCC)
extra = '-Wcast-qual -Wlogical-op -Wconversion'
extra += ' -fstrict-aliasing -Wstrict-aliasing=1'
extra += ' -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls'
extra += ' -Wstack-protector '
if 'gcc' in env['CC']:
if conf.CheckCCFLAGS(extra):
conf.env.Append(CORECFLAGS = extra)
# Check if we can use undefined behaviour sanitizer (only with clang)
# TODO: Fuzz test triggers the bool sanitizer, figure out whether to
# modify the fuzz test or to keep ignoring the check.
extra = '-fsanitize=undefined,integer -fno-sanitize-recover=undefined,integer '
if 'clang' in env['CC']:
if conf.CheckCCFLAGS(extra, linkflags = extra):
conf.env.Append(CORECFLAGS = extra)
conf.env.Append(LINKFLAGS = extra)
# End the config stuff
env = conf.Finish()
if not env.get('NODEFARGS'):
# Initialize the CCFLAGS according to the compiler
if 'gcc' in env['CC']:
# GNU Compiler Collection
# Debug info, warnings as errors
env.Append(CFLAGS = '-g -Wall -Werror ')
env.Append(CORECFLAGS = '-Wextra ')
# Pedantic ANSI C. On AVR this doesn't work because we use large
# enums in some of the tests.
if env.get("EMBEDDED") != "AVR":
env.Append(CFLAGS = '-ansi ')
env.Append(CORECFLAGS = '-pedantic ')
# Profiling and coverage
if not env.get("EMBEDDED"):
env.Append(CFLAGS = '-fprofile-arcs -ftest-coverage ')
env.Append(LINKFLAGS = '-g --coverage')
# We currently need uint64_t anyway, even though ANSI C90 otherwise..
env.Append(CFLAGS = '-Wno-long-long')
elif 'clang' in env['CC']:
# CLang
env.Append(CFLAGS = '-ansi -g -Wall -Werror')
env.Append(CORECFLAGS = ' -Wextra -Wcast-qual -Wconversion')
elif 'cl' in env['CC']:
# Microsoft Visual C++
# Debug info on, warning level 2 for tests, warnings as errors
env.Append(CFLAGS = '/Zi /W2 /WX')
env.Append(LINKFLAGS = '/DEBUG')
# More strict checks on the nanopb core
env.Append(CORECFLAGS = '/W4')
# Enable C11 standard
env.Append(CFLAGS = ' /std:c11 ')
# Disable warning about sizeof(union{}) construct that is used in
# message size macros, in e.g. multiple_files testcase. The C construct
# itself is valid, but quite rare, which causes Visual C++ to give a warning
# about it.
env.Append(CFLAGS = '/wd4116')
elif 'tcc' in env['CC']:
# Tiny C Compiler
env.Append(CFLAGS = '-Wall -Werror -g')
if 'clang' in env['CXX']:
env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers')
elif 'g++' in env['CXX'] or 'gcc' in env['CXX']:
env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers -std=gnu++11')
elif 'cl' in env['CXX']:
env.Append(CXXFLAGS = '/Zi /W2 /WX /wd4116 /wd4127')
env.SetDefault(CORECFLAGS = '')
if not env.get("EMBEDDED") and not env.get("NOVALGRIND"):
valgrind = env.WhereIs('valgrind')
if valgrind:
env.SetDefault(VALGRIND = valgrind)
# Make it possible to add commands to the end of linker line
env.SetDefault(LINKLIBS = '')
env.Replace(LINKCOM = env['LINKCOM'] + " $LINKLIBS")
# Place build files under separate folder
import os.path
env['VARIANT_DIR'] = env['BUILDDIR']
env['BUILD'] = '#' + env['VARIANT_DIR']
env['COMMON'] = '#' + env['VARIANT_DIR'] + '/common'
# Include common/SConscript first to make sure its exports are available
# to other SConscripts.
SConscript("common/SConscript", exports = 'env', variant_dir = env['VARIANT_DIR'] + '/common')
# Now include the SConscript files from all subdirectories
for subdir in Glob('*/SConscript') + Glob('regression/*/SConscript'):
if str(subdir).startswith("common/"): continue
if str(subdir).startswith("common\\"): continue
SConscript(subdir, exports = 'env', variant_dir = env['VARIANT_DIR'] + '/' + os.path.dirname(str(subdir)))

View file

@ -0,0 +1,45 @@
# Build and run a test that encodes and decodes a message that contains
# all of the Protocol Buffers data types.
Import("env")
env.NanopbProto(["alltypes", "alltypes.options"])
enc = env.Program(["encode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_common.o"])
dec = env.Program(["decode_alltypes.c", "alltypes.pb.c", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
# Test the round-trip from nanopb encoder to nanopb decoder
env.RunTest(enc)
env.RunTest([dec, "encode_alltypes.output"])
# Re-encode the data using protoc, and check that the results from nanopb
# match byte-per-byte to the protoc output.
env.Decode("encode_alltypes.output.decoded",
["encode_alltypes.output", "alltypes.proto"],
MESSAGE='AllTypes')
env.Encode("encode_alltypes.output.recoded",
["encode_alltypes.output.decoded", "alltypes.proto"],
MESSAGE='AllTypes')
env.Compare(["encode_alltypes.output", "encode_alltypes.output.recoded"])
# Do the same checks with the optional fields present.
env.RunTest("optionals.output", enc, ARGS = ['1'])
env.RunTest("optionals.decout", [dec, "optionals.output"], ARGS = ['1'])
env.Decode("optionals.output.decoded",
["optionals.output", "alltypes.proto"],
MESSAGE='AllTypes')
env.Encode("optionals.output.recoded",
["optionals.output.decoded", "alltypes.proto"],
MESSAGE='AllTypes')
env.Compare(["optionals.output", "optionals.output.recoded"])
# And for the _zero initializer
env.RunTest("zeroinit.output", enc, ARGS = ['2'])
env.RunTest("zeroinit.decout", [dec, "zeroinit.output"], ARGS = ['2'])
env.Decode("zeroinit.output.decoded",
["zeroinit.output", "alltypes.proto"],
MESSAGE='AllTypes')
env.Encode("zeroinit.output.recoded",
["zeroinit.output.decoded", "alltypes.proto"],
MESSAGE='AllTypes')
env.Compare(["zeroinit.output", "zeroinit.output.recoded"])

View file

@ -0,0 +1,8 @@
* max_size:16
* max_count:5
*.*fbytes fixed_length:true max_size:4
*.*farray fixed_count:true max_count:5
*.*farray2 fixed_count:true max_count:3
IntSizes.*int8 int_size:IS_8
IntSizes.*int16 int_size:IS_16
DescriptorSize8 descriptorsize:DS_8

View file

@ -0,0 +1,166 @@
syntax = "proto2";
// package name placeholder
enum NonZeroBasedEnum {
Two = 2;
Three = 3;
Four = 4;
}
message SubMessage {
required string substuff1 = 1 [default = "1"];
required int32 substuff2 = 2 [default = 2];
optional fixed32 substuff3 = 3 [default = 3];
}
message EmptyMessage {
}
enum HugeEnum {
Negative = -2147483647; /* protoc doesn't accept -2147483648 here */
Positive = 2147483647;
}
message Limits {
required int32 int32_min = 1 [default = 2147483647];
required int32 int32_max = 2 [default = -2147483647];
required uint32 uint32_min = 3 [default = 4294967295];
required uint32 uint32_max = 4 [default = 0];
required int64 int64_min = 5 [default = 9223372036854775807];
required int64 int64_max = 6 [default = -9223372036854775807];
required uint64 uint64_min = 7 [default = 18446744073709551615];
required uint64 uint64_max = 8 [default = 0];
required HugeEnum enum_min = 9 [default = Positive];
required HugeEnum enum_max = 10 [default = Negative];
required int32 largetag = 65535 [default = 0];
}
message IntSizes {
required int32 req_int8 = 1 ;
required uint32 req_uint8 = 2 ;
required sint32 req_sint8 = 3 ;
required int32 req_int16 = 4 ;
required uint32 req_uint16 = 5 ;
required sint32 req_sint16 = 6 ;
}
message DescriptorSize8 {
required int32 first = 1;
required int32 second = 22222;
}
enum MyEnum {
Zero = 0;
First = 1;
Second = 2;
Truth = 42;
}
message AllTypes {
required int32 req_int32 = 1;
required int64 req_int64 = 2;
required uint32 req_uint32 = 3;
required uint64 req_uint64 = 4;
required sint32 req_sint32 = 5;
required sint64 req_sint64 = 6;
required bool req_bool = 7;
required fixed32 req_fixed32 = 8;
required sfixed32 req_sfixed32= 9;
required float req_float = 10;
required fixed64 req_fixed64 = 11;
required sfixed64 req_sfixed64= 12;
required double req_double = 13;
required string req_string = 14;
required bytes req_bytes = 15;
required SubMessage req_submsg = 16;
required MyEnum req_enum = 17;
required EmptyMessage req_emptymsg = 18;
required bytes req_fbytes = 19;
repeated int32 rep_int32 = 21 [packed = true];
repeated int64 rep_int64 = 22 [packed = true];
repeated uint32 rep_uint32 = 23 [packed = true];
repeated uint64 rep_uint64 = 24 [packed = true];
repeated sint32 rep_sint32 = 25 [packed = true];
repeated sint64 rep_sint64 = 26 [packed = true];
repeated bool rep_bool = 27 [packed = true];
repeated fixed32 rep_fixed32 = 28 [packed = true];
repeated sfixed32 rep_sfixed32= 29 [packed = true];
repeated float rep_float = 30 [packed = true];
repeated fixed64 rep_fixed64 = 31 [packed = true];
repeated sfixed64 rep_sfixed64= 32 [packed = true];
repeated double rep_double = 33 [packed = true];
repeated string rep_string = 34;
repeated bytes rep_bytes = 35;
repeated SubMessage rep_submsg = 36;
repeated MyEnum rep_enum = 37 [packed = true];
repeated EmptyMessage rep_emptymsg = 38;
repeated bytes rep_fbytes = 39;
repeated int32 rep_farray = 40 [packed = true];
optional int32 opt_int32 = 41 [default = 4041];
optional int64 opt_int64 = 42 [default = 4042];
optional uint32 opt_uint32 = 43 [default = 4043];
optional uint64 opt_uint64 = 44 [default = 4044];
optional sint32 opt_sint32 = 45 [default = 4045];
optional sint64 opt_sint64 = 46 [default = 4046];
optional bool opt_bool = 47 [default = false];
optional fixed32 opt_fixed32 = 48 [default = 4048];
optional sfixed32 opt_sfixed32= 49 [default = 4049];
optional float opt_float = 50 [default = 4050];
optional fixed64 opt_fixed64 = 51 [default = 4051];
optional sfixed64 opt_sfixed64= 52 [default = 4052];
optional double opt_double = 53 [default = 4053];
optional string opt_string = 54 [default = "4054"];
optional bytes opt_bytes = 55 [default = "\x34\x5C\x00\xff"];
optional SubMessage opt_submsg = 56;
optional MyEnum opt_enum = 57 [default = Second];
optional EmptyMessage opt_emptymsg = 58;
optional bytes opt_fbytes = 59 [default = "4059"];
oneof oneof
{
SubMessage oneof_msg1 = 60;
EmptyMessage oneof_msg2 = 61;
SubMessage static_msg = 63;
}
optional NonZeroBasedEnum opt_non_zero_based_enum = 62;
// Second fixed length array field to test the length check logic.
repeated fixed32 rep_farray2 = 95 [packed = true];
// Check support for custom integer sizes
required IntSizes req_intsizes = 96;
// Check support for 8-word descriptors
required DescriptorSize8 req_ds8 = 97;
// Check that extreme integer values are handled correctly
// Also checks support for 4-word descriptors
required Limits req_limits = 98;
// Just to make sure that the size of the fields has been calculated
// properly, i.e. otherwise a bug in last field might not be detected.
required int32 end = 999;
extensions 200 to 255;
}
message TestExtension {
extend AllTypes {
optional TestExtension testextension = 250;
}
optional string strval = 1;
}

Some files were not shown because too many files have changed in this diff Show more